Commit Graph
21 Commits
Author SHA1 Message Date
snowspeeder 2be5725fbd feat: integrate real administration retry and approved feature destinations 2026-10-03 13:19:04 -04:00
snowspeeder 523f6cbbf9 feat: integrate durable chat voice transport and deployment assets 2026-10-03 09:02:47 -04:00
snowspeeder 6b8d55fc92 feat: add Hermes WebUI provisioning and English Dragon HD Omni voices
Rebuild & Deploy / rebuild (push) Successful in 2m17s
2026-10-02 16:07:24 -04:00
snowspeeder 129159ffd1 fix: support legacy Docker builder in deployment
Rebuild & Deploy / rebuild (push) Failing after 1m12s
2026-10-01 16:16:47 -04:00
snowspeeder 2aedea84b5 feat: provision private Hermes assistants for authenticated Hope accounts 2026-10-01 13:30:18 -04:00
snowspeeder 436b3fc8b1 refactor: split music streaming into Hope Music
Rebuild & Deploy / rebuild (push) Successful in 2m7s
Move the media server, downloader, library volume, and browser player to the
standalone hope-media-music product. Keep Hope's music tools as a thin HTTP
client of the LAN service on port 8094.

Use a stable voice-room player scope instead of ephemeral LiveKit room names.
The agent now owns the conversation handshake: fresh reported playback mutes
its input, joining pauses music, and the last participant leaving resumes only
music it paused. Peer failures remain non-fatal.

Also move the voice deploy workflow onto the active Unraid Gitea runner and
remove yt-dlp/ffmpeg/media health and volume dependencies from the image.
2026-09-12 06:35:15 -04:00
snowspeeder 8a7cca456f fix: force tool calls for drifted intents and harden tool-use prompt
Small local models (qwen2.5-vl-3b, gemma-4-e4b) narrate actions ('Sure,
I'll pause the music') without emitting the tool call once the full
system prompt and 26-tool set are in context. Measured: qwen emitted
tools in 2/8 realistic intents, gemma 5/8; single-tool tests pass 100%,
so this is context-induced drift, not plumbing.

- agent/intent_router.py: deterministic forced-call router for
  high-frequency intents — media controls, now_playing/list_library,
  'remember that ...' memory saves, explicit YouTube Music searches,
  and personal-fact recall (memory_recall/search_notes/skill_recall,
  excluded for weather/time questions). Fires only when the tool is
  available; guards against how-do-I questions.
- agent.py: generalize _ForcedToolCallStream to any tool; route through
  intent_router after the dispatch check. System prompt adds a hard
  'call, don't narrate' rule and reconditions 'answer directly'.
- tests/test_intent_router.py: 30 unit tests pinning router behavior.

Verified against the live LLM with the full fidelity harness: combined
forced-or-emitted coverage 8/8 on qwen2.5-vl-3b (was 2/8) and 8/8 on
gemma-4-e4b (was 5/8). Full suite: 79 passed.
2026-08-29 15:38:35 -04:00
snowspeeder 04c4a53594 feat: media player API, web player panel, and Hope music MCP
- web/media_server.py: FastAPI service owning the permanent library
  (library.json + ./media volume), yt-dlp YouTube Music search, queued
  download jobs with mp3 transcode (ffmpeg), per-room player desired
  state, and an HTTPS proxy for external live-stream URLs.
- agent/media_mcp.py: Hope tools — search_music, play_song,
  offer_song_choices, pause/resume/stop/skip/seek, now_playing,
  list_library, add_stream.
- agent/agent.py: media toolset wiring + conversation rule (music
  playing disables the agent mic; re-engaging pauses music).
- web UI: slide-out Music panel (search, suggestions, library, live
  stream add, play/pause, ±10s, seek, volume) with a reconciling poller
  and media_state data-channel reports.
- token server returns the minted room name; nginx serves /media/files
  as static (native Range) and proxies /media/api to the media server.
- supervisord runs media-server; compose mounts ./media and adds
  ffmpeg to the image.
2026-08-29 13:03:12 -04:00
snowspeeder 321421e37f fix: reliably dispatch and return background tasks
Rebuild & Deploy / rebuild (push) Successful in 47s
2026-08-29 07:29:38 -04:00
snowspeeder c940923539 feat: connect Shane voice sessions to memory 2026-08-28 16:22:18 -04:00
Shane c815bcb485 feat: replace custom memory MCP with Cognee remote server
- Remove memory_mcp.py (stdio markdown-file memory)
- Add Cognee MCP as remote Streamable HTTP toolset at 192.168.86.2:8003/mcp
- Filter to only remember/recall/forget tools via allowed_tools
- Update system prompt: Memory section moved to top priority with
  explicit 'call recall FIRST' instructions and examples
- Add COGNEE_MCP_URL env var to docker-compose
- Remove /memory volume mount (no longer needed)
- Rewrite memory tests to use Cognee HTTP client fixture
- 28/28 tests passing
2026-08-23 08:10:42 -04:00
Shane 44e8d05e2c feat: background task dispatch system with live UI panel
- agent/task_registry.py: file-based JSONL event registry (cross-process)
- agent/task_worker.py: autonomous LLM loop with weather/time/memory/web tools
- agent/dispatch_mcp.py: MCP tool exposing dispatch_task to the main agent
- agent/agent.py: registers dispatch toolset, polls task events → room data
- web: slide-out task panel (FAB button + badge), live step streaming via
  data channel topic 'tasks', status dots (running/completed/failed)
- Dockerfile: copies new task_*.py and dispatch_mcp.py files

The dispatch MCP runs in its own process; events flow through
/tmp/tasks/events.jsonl which the main agent tails every second and
forwards to the browser. Tasks run up to 10 LLM iterations with tool calls.
2026-08-22 18:06:23 -04:00
Shane ab6b5254ef feat: context compaction + skills system
Compaction:
- GemmaLLM.chat() truncates ChatContext to last 30 items (~15 turns)
  before sending to LLM, preventing context window overflow on long
  conversations. Preserves system prompt and removes orphaned tool calls.

Skills:
- agent/skills_mcp.py: MCP server with skill_save, skill_recall,
  skill_list, skill_update tools backed by .md files in /skills
- skills/ dir bind-mounted into container, git-trackable
- System prompt instructs Hope to save repeatable procedures as skills
  and recall them before performing tasks she's done before
- Distinct from memory (facts) — skills are learned *procedures*
2026-08-22 16:42:16 -04:00
Shane de1a5d8400 feat: markdown memory system — Hope learns from conversations
- agent/memory_mcp.py: MCP server with memory_recall, memory_save, memory_list
  tools backed by .md files in /memory (simple keyword matching for v1)
- memory/ dir bind-mounted into container, persists across rebuilds,
  easily backed up via git
- System prompt instructs Hope to recall on past references and save
  personal info/preferences naturally without announcing it
- Dockerfile: copy memory_mcp.py; compose: ./memory:/memory volume
2026-08-22 16:33:00 -04:00
Shane c620867854 fix: disable preemptive_generation for tool call compatibility; add get_time tool
- preemptive_generation was incompatible with MCP tool calls: it starts
  generating before the turn finalizes, breaking the tool execution loop
  (agent said 'let me check' then hung forever)
- Add get_time(location?) to weather_mcp.py for date/time queries
- Update system prompt with Weather & Time section
2026-08-22 16:13:06 -04:00
Shane d3f9f2c4ed feat: implement full UPDATE.md review — critical fixes, UI upgrade, infra hardening
Critical frontend bugs:
- Add TrackSubscribed/attach() for agent audio playback
- Fix decodeToString TypeError with TextDecoder
- XSS fix: innerHTML -> textContent in addMessage
- Fresh token on reconnect retry

Agent fixes:
- GemmaLLM subclass with reasoning_content fallback wrapper
- Disable Gemma 4 thinking mode via chat_template_kwargs (6.8s -> 0.5s)
- Remove duplicate session-level LLM
- Replace global _active_session with closure-based handler
- asyncio.create_task instead of deprecated get_event_loop
- Explicit silero VAD, topic filter on voice-control

Infra:
- supervisord: all programs log to /dev/stdout
- Dockerfile: uv sync --frozen with committed uv.lock
- nginx config moved to real file, token_server.py no longer served
- entrypoint.sh: cert persisted, only regenerated on IP change
- compose: healthcheck + cert volume
- token_server: CORS removed, room pinned to voice-room

UI upgrade:
- Orb UI with state machine (idle/connecting/listening/thinking/speaking)
- Streaming transcripts via lk.transcription text streams
- Barge-in hint, thinking chip, audio visualizer
- Glassmorphism, chat bubbles, settings sheet, light mode
- PWA manifest, favicon, wake-lock, safe-area insets
- localStorage conversation history

Docs: AGENTS.md drift fixed
2026-08-22 15:21:59 -04:00
Shane d1eeb01f3d fix: set SSL_CERT_FILE to correct path for slim base image 2026-08-22 12:51:01 -04:00
Shane 045ddabac7 feat: web access via MCP (Firecrawl search/scrape) + mcp server attach support
- agent/web_mcp.py: stdio MCP server exposing web_search and web_scrape,
  backed by the self-hosted Firecrawl stack on xNAS (no API key needed)
- agent.py: Agent now attaches mcp_servers built from config; EXTRA_MCP_SERVERS
  env var allows adding arbitrary HTTP/SSE MCP servers as JSON
- Dockerfile: installs livekit-agents[mcp], copies web_mcp.py
- .env.example: WEB_MCP_ENABLED, FIRECRAWL_BASE, EXTRA_MCP_SERVERS documented
2026-08-22 12:29:04 -04:00
Shane 6f2b231938 feat: HTTPS web frontend (self-signed) + server-side token endpoint
- nginx serves the UI over HTTPS on 8090 with a self-signed cert
  (browsers require a secure context for microphone access)
- added /token endpoint (tiny Python HTTP server) that signs LiveKit
  JWTs server-side, keeping the API secret out of the browser
- app.js now fetches a signed token from /token and uses wss:// when
  the page is served over HTTPS
- supervisord runs the token-server as a fourth process
2026-08-22 08:31:19 -04:00
Shane 18bbc75216 fix: livekit.yaml config (remove invalid bind_addr field) 2026-08-22 08:15:57 -04:00
Shane 97633cc585 feat: Dockerfile, docker-compose, livekit.yaml, supervisord.conf 2026-08-22 07:41:58 -04:00