9.7 KiB
9.7 KiB
DivaCode — AI Being Platform Action Plan
Language: Go
Inference: llama.cpp (HTTP server), OpenAI-compatible API planned
Inspiration: OpenHer, Agent Diva, nanobot
Current Status (2026-06-10)
Builds: yes
Runs: yes (requires llama.cpp on :8080)
Known issues:
- Prompt template is raw text — model dumps reasoning/self-correction meta-text instead of just the response
- No chat template configurability (ChatML, Llama 3 instruct, etc.)
- TUI is basic (no streaming, no word-wrap polish)
- Memory store uses keyword
LIKEsearch, not real embeddings - OpenAI-compatible adapter not yet built
- Matrix adapter is a stub
Architecture Overview
User
│
├── TUI (Bubble Tea)
└── Matrix (future)
│
┌─────┴──────────────────────────────┐
│ Core Agent Loop │
│ (internal/agent/) │
└─────┬──────────────────────────────┘
│
┌─────┴──────────────────────────────┐
│ Companion Layer │
│ (internal/companion/) │
│ ├─ Personality (5 bounded traits) │
│ ├─ Relationship (familiarity,trust)│
│ ├─ Reflection (diary,observations)│
│ ├─ Mood (6 states + energy) │
│ └─ Prompt Composer (dynamic ctx) │
└─────┬──────────────────────────────┘
│
┌─────┴──────────────────────────────┐
│ Memory Layer │
│ (internal/memory/) │
│ ├─ RAG store (keywords → vectors) │
│ └─ Self-memory (promises,strats) │
└─────┬──────────────────────────────┘
│
┌─────┴──────────────────────────────┐
│ Inference (internal/llama/) │
│ ├─ llama.cpp HTTP client │
│ └─ OpenAI-compatible (planned) │
└────────────────────────────────────┘
Skills / Tools:
├─ web_fetch
├─ web_search (stub)
└─ MCP protocol (future)
Phase 0 — Foundation & Scaffolding
Status: COMPLETE
- Go module:
git.db123.ir/db123/divacode - Project structure per Holy Code Bible conventions
internal/config/— std libos.Getenvonlyinternal/storage/—modernc.org/sqlite(pure Go, no CGO), auto-createsdata/dirinternal/llama/client.go— HTTP client forPOST /completion,POST /embedding,GET /health.env.example,Makefile,.gitignore,Dockerfile,docker-compose.ymlAGENTS.mdwith architecture, commands, conventions
Phase 1 — Core Agent Loop
Status: COMPLETE (minor issues remain)
internal/agent/agent.go— message → memory search → prompt → llama → save → respondinternal/agent/scheduler.go— tick every 15m, check mood/diary/auto-messagecmd/divad/main.go— wires everything: config, DB, llama, TUI, scheduler, Matrix, API- Conversation persistence to SQLite (
conversations,messagestables) - Bubble Tea TUI with viewport + input bar
- Prompt template is wrong — uses raw headers, no chat format. Model outputs meta-text
- No token tracking — context window grows unbounded
- TUI doesn't stream tokens (waits for full completion)
Phase 2 — Prompt Templating & Format Fix
Goal: Fix the model output. Swap raw prompt text for a configurable chat template so the model only returns the assistant response.
internal/llama/template.go— chat template formatter:- ChatML (
<|im_start|>system...<|im_end|>) - Llama 3 instruct (
<|begin_of_text|><|start_header_id|>system<|end_header_id|>) - Configurable via env
CHAT_TEMPLATE=chatml(default)
- ChatML (
- Refactor
companion/promptbuilder.goto output structured segments, then let template.go wrap them - Strip system prompt of raw formatting — let the template handle structure
- Test: "hi" produces just "Hello!" not paragraphs of self-correction
Phase 3 — Long-Term Memory (RAG)
Goal: Embedding-based retrieval so the agent recalls across sessions.
internal/memory/embed.go— call llama.cppPOST /embeddingto get vectorsinternal/memory/store.go— upgradeSearch()from keywordLIKEto cosine similarity- Store embeddings as BLOB in
memoriestable - Temporal decay — older memories scored lower
- Importance scoring — "remember this" / emotional content boosts score
- Test: Store info, restart, ask about stored info → recall
Phase 4 — OpenAI-Compatible Adapter
Goal: Swap inference to any OpenAI-compatible API (OpenAI, vLLM, Ollama, etc.).
internal/llama/provider.go— interface:type Provider interface { Complete(ctx, *Request) (*Response, error) Embed(ctx, string) ([]float64, error) Health() error }- Rename
internal/llama/→internal/inference/ llama.go— implements Provider (existing code)openai.go— implements Provider via OpenAI-compatible REST API- Config:
INFERENCE_PROVIDER=llama|openai,OPENAI_API_KEY,OPENAI_BASE_URL - Test: Both providers produce same interface, switchable via env
Phase 5 — Episodic Diary & Reflection
Status: CODE DONE — needs integration into the scheduled pipeline.
internal/companion/reflection.go—GenerateDiary,RecentObservations,AddObservationdiary_entriestable with date, summary, mood, topics, observationsobservationstable with confidence, category, applied flag- Connect scheduler's diary trigger to actual LLM-generated summaries (currently writes stub text)
- Reflection → Personality update pipeline:
- Observations accumulate → periodic analysis → bounded trait drift
- Max 0.5% change/day, max 5%/month
Phase 6 — MCP Tools & Integrations
Status: PARTIAL
internal/tools/registry.go— register/list/execute toolsinternal/tools/builtin.go—web_fetch,web_search(stub)- MCP protocol client (
internal/tools/mcp.go) — stdio/TCP, list tools, execute, parse results - Tool call loop in agent: LLM decides → agent executes → result appended → LLM finalizes
- Plugins: Obsidian vault, Gitea, Actual Budget
Phase 7 — Matrix Integration
Status: STUB
internal/channel/matrix.go— config + start stub- Full Matrix bot with
mautrix-go:- Listen for invitations, join rooms
- Handle DMs with typing indicators
- Bot identity:
@diva:homeserver.tld
- Sync TUI and Matrix state
- Test: Send DM, verify response, verify cross-session memory
Phase 8 — Self-Memory & Identity
Status: CODE DONE
internal/memory/self_memory.go— promises, strategiesagent_promisestable (id, promise, context, fulfilled, deadline)agent_strategiestable (id, situation, strategy, outcome)- Wire into Prompt Composer: "You promised to X" context
- Test: "What did you promise me?" → recall
Phase 9 — Safety Guardrails & Identity Stability
Goal: Prevent personality drift, maintain core safety.
internal/companion/safety.go— core identity (stable) vs state (dynamic)- Personality safety: bounded traits, safety overrides personality, no tool access changes
- Prompt injection protection: user input wrapped in delimiters, strict template sections
Phase 10 — Polish: Streaming TUI, Token Tracking, Observability
Goal: Production-quality UX.
- Token streaming in TUI (char-by-char from llama.cpp SSE or chunked response)
- Context window manager — track tokens, sliding window when full, auto-summarize old messages
POST /v1/chatstreaming via SSE in API mode- Prometheus metrics (
GET /metrics) - Graceful shutdown — drain in-flight requests, save state
Phase 11 — Future Enhancements (Optional)
- Voice: whisper.cpp (STT) + piper/XTTS (TTS)
- VRM/Live2D avatar rendering
- Multi-user with per-user relationship tracking
- Multi-room Matrix
- Plugin system
- WebUI dashboard
- Home Assistant integration
Database Schema (15 tables across 2 DBs)
divacode.db:
conversations,messages,context_state,memories
companion.db:
personality_traits,relationship_metrics,shared_topics,inside_jokesdiary_entries,observationsagent_promises,agent_strategies
Key Principles
- Smallest loop first — get message → memory → llm → response working before adding complexity
- Personality is data, not prompt text — traits in SQLite, composed dynamically
- Memory ≠ Personality — factual memory separate from relationship/emotional state
- Slow evolution — max 0.5% trait change/day, 5%/month
- Core Identity stable — never allow personality to override safety rules
- Diary before reflection — nightly diary is the emotional continuity layer
- Autonomous messaging — scheduler makes it feel alive, not the LLM
- No config libs — std lib
os.Getenvonly - No HTTP routers — std lib
net/httponly - Error wrapping —
fmt.Errorf("context: %w", err), never discard