Files
Maven/REARCH.md
T
kami da60c14399 chore: docker, config, delivery sinks, dialogue, and agent docs
- Dockerfile: multi-stage build with CGO_ENABLED=0, embedder model copy,
  non-root user, healthcheck, and /data volume.
- docker-compose.yml: mavend + mavweb services with shared volume, health
  checks, and restart policy.
- .gitignore: ignore models/llm/*.gguf, deploy/telegram.env, tmp artifacts.
- deploy/mavend.json: add LLM, phraser, voice sections (embedder, model
  paths, wake sensitivity). Add telegram token env-var expansion.
- deploy/telegram.env.example: template for telegram bot token.
- internal/config/config.go: add LLM config struct, voice config struct
  (embedder, llama, wake sensitivity), telegram token loading.
- telegramsink: add chat intent delivery support alongside existing types.
- voicesink: skip empty payloads in delivery.
- dialogue/session: add chat intent to anaphora resolution, test coverage.
- AGENTS.md: update with LLM embedder, LFM model download/configure steps,
  new UI conventions.
- REARCH.md: architecture research document.
- cmd/mavend/main.go: wire LLM config, phraser, embedder, telegram config,
  WebAuthn, IPC event/routine handlers, and reactive notes.
2026-07-10 15:49:27 +04:00

4.2 KiB

Maven — Re-architecture (router-centric, 2026-07-10)

Supersedes the classifier-first routing model. Agreed in a design session after diagnosing that homesrv deploys with a stub phraser (no LLM running) and an embedder-classifier that routes by nearest-neighbor between frozen seed phrases — the structural cause of "she messes up queries."

Hardware reality: homesrv = Ryzen 5 5600U laptop, Vega iGPU, 14 GB shared RAM. Workstation (RX 7900 XT) is NOT the deploy target and is often busy. So: small models, on-demand where heavy, always-on where cheap.

Principle

The LLM is not the center of everything. Deterministic tools handle the bulk. The LLM is used for exactly two things: routing/reasoning and talking back. A sub-1B agentic model (LFM 2.5) is enough for both.

If the router is good, Maven feels good. Routing is the linchpin.

The spine

utterance
   → [world-state context]   cheap: time, presence, calendar_busy, weather (no LLM)
   → ROUTER  = LFM (always-on, agentic)
        reads utterance + context + tool schema, emits a STRUCTURED action:
          • call a tool (deterministic)      • answer directly
          • escalate → 4B reasoner (on-demand)
   → tools (deterministic, fast)  /  4B reasoner (on-demand summon)
   → PHRASER = LFM (always-on, same process as router) → TTS / text
  • Router = Phraser = one resident sub-1B LFM llama-server, two call-sites (route-prompt, phrase-prompt). Always warm, no cold start. Cheap on 14 GB.
  • 4B reasoner (Qwen3-4B, already on disk) — summoned on-demand for genuinely complex turns, torn down / idle-unloaded after. Never resident.
  • Embedder demoted from router to tool — it now backs memory.search (RAG) and gives the router a cheap "similar past notes/intents" hint. The router no longer depends on it clearing a threshold. Upgrade MiniLM → bge-m3 for better RU retrieval later (model swap, not architecture).

Router output

  • Constrained structured JSON action {tool, args, escalate} — NOT free-form multi-step function-calling. Sub-1B is far more reliable emitting a fixed schema. Enforce with a GBNF grammar in llama.cpp (near-bulletproof).
  • Keep the existing stage-0 exact-match fast-path for dead-obvious commands (skips the router entirely) — cheap insurance, already built.

The proactive / memory half — one background engine

"Take notes," "remember," "reflect," "suggest do you want to add X?", "remind" are NOT request-path features. They are one digestion worker:

DIGESTION WORKER  (periodic + event-driven, off the request path)
  • reads new facts/notes since last pass
  • RAG-consolidates: dedupe, link, summarize into durable memory
  • reflects: detect patterns ("mentioned X three times")
  • proposes: "want me to add X / remind you about Y?" → nudge dispatcher
  • surfaces due reminders
  runs LFM (cheap) or summons 4B (real synthesis) — never blocks a turn

Notes capture is a deterministic Tier-0 tool; making notes mean something later is the worker + RAG.

Layer table

Layer What Runs
Context world-state (time/presence/calendar/weather) always, no LLM
Router LFM agentic orchestrator — linchpin always-on
Tools note/reminder/memory/calendar/weather/act (deterministic) always
Reasoner Qwen3-4B for complex turns on-demand summon
Phraser LFM — final voice always-on (same proc as router)
Digestion worker reflection → suggestions/nudges/memory background
Reach telegram (+ existing ntfy/voice) quick win
Voice quality custom/better TTS deferred (workstation GPU busy)

Build order

  1. Foundation + router — router-as-LFM, turn the engine ON (resident sub-1B), verify notes+reminders actually round-trip, date/number TTS normalizer, wire telegram reach. After this she's a trustworthy plain assistant.
  2. On-demand 4B reasoner — summon/idle lifecycle + router escalation path.
  3. Digestion worker — reflection, proactive suggestions, memory consolidation, RAG read-back.
  4. Embodiment — voice quality (deferred).

Non-goals (unchanged)

Never phones home. Not a nag. Not autonomous. Feminine-gendered RU self-ref.