# Sofiia CTO Agent — Intelligence System Trace (C) > Generated: 2026-02-26 | Реконструкція "інтелектуальної системи" Sofiia --- ## Загальна схема мислення ``` User Input (Telegram / Console / Voice) │ ▼ [BFF: sofiia-console] Auth + Rate limit + Session │ ├─── Voice turn? ──► STT (memory-service) → sanitize_for_voice() → voice_fast_uk │ └─── Text turn? ──► [Router /v1/agents/sofiia/infer] │ ┌────────────┴────────────┐ │ │ LLM selection Tool call? (profile-based) (tool_manager) │ │ [LLM response] [Tool execution] │ │ strip RBAC check │ │ Memory save Evidence │ │ └────────┬────────────────┘ │ [Dialog Map update] (SQLite tree / future Postgres graph) │ [Response to User] │ [TTS if voice mode] ``` --- ## 1. Intent → Plan → Execute (Canonical CTO Flow) ### 1.1 Документовано - **Docs:** `AGENTS.md` §Example Commands, `docs/ADR_ARCHITECTURE_VNEXT.md` §3.1 CrewAI Workers - **Concept:** "Chat/Intent → Plan (Artifacts) → Execute as Job → Evidence → Dialog Map" - **vNext Design:** вся концепція описана в цьому сеансі розмови ### 1.2 Реалізовано - **Intent → Plan:** ✅ LLM inference через Router (`/v1/agents/sofiia/infer`) - **Plan → Execute (Ops):** ✅ `/api/ops/run` dispatches pre-defined actions - **Execute → Evidence:** ⚠️ частково — ops повертає result, але не зберігає як artifact - **Evidence → Dialog Map:** ❌ ops artifacts не зшиваються в dialog_nodes ### 1.3 Розриви - Немає загального **Job System** (тільки pre-defined ops actions) - Немає `repo_changesets` / `ops_runs` як артефактів у DB - Dialog Map не оновлюється автоматично від ops actions --- ## 2. Модулі Архітектури ### 2.1 BFF (sofiia-console) **Документовано тут:** - `docs/runbook/sofiia-control-plane.md` - `docs/sofiia_ui_vnext_audit.md` - `docs/fabric_contract.md` **Реалізовано тут:** - `services/sofiia-console/app/main.py` — FastAPI v0.3.0 - `services/sofiia-console/app/config.py` — node registry, ENV loading - `docker-compose.node2-sofiia.yml` — deployment config **Що BFF робить:** ``` 1. API Gateway для UI (chat/voice/projects/ops/nodes) 2. Session management (SQLite sofiia.db) 3. Multi-provider LLM proxy (ollama/router/glm/grok) 4. Voice pipeline (STT→LLM→TTS, Phase 2 streaming) 5. Ops dispatcher (risk/pressure/backlog/notion/release) 6. Multi-node health monitor (polling + WebSocket fan-out) 7. Memory save (SQLite first, then Memory Service best-effort) ``` **Розриви:** - Відсутній єдиний Job tracking (кожен ops action — one-shot, без persist) - Відсутній `repo_changesets` flow - `ops.html`, `chat.html`, `nodes.html` — fallback HTML, не окремі файли --- ### 2.2 LLM Routing **Документовано тут:** - `services/router/router-config.yml` - `docs/architecture_inventory/01_SERVICE_CATALOG.md` - `docs/OPENAPI_CONTRACTS.md` **Реалізовано тут:** - `services/router/main.py` — `/v1/agents/{agent_id}/infer` - `services/router/router-config.yml` — `sofiia:` entry **Конфігурація Sofiia (router-config.yml):** ```yaml sofiia: primary: cloud_grok # Grok API (Telegram mode) fallback: cloud_deepseek # DeepSeek API # Console mode може override через ollama ``` **Voice profiles:** ```yaml voice_fast_uk: prefer_models: [gemma3:latest, qwen3.5:35b-a3b, qwen3:14b] deadline_ms: 9000 max_tokens: 256 voice_quality_uk: prefer_models: [qwen3.5:35b-a3b, qwen3:14b] deadline_ms: 12000 max_tokens: 256 ``` **Розриви:** - Відсутній профіль для `repo_changeset` (long-form, structured output) - Відсутній профіль для `plan_generation` (CTO structured plans) --- ### 2.3 Tool System **Документовано тут:** - `AGENTS.md` §Tool List - `docs/architecture_inventory/02_TOOL_CATALOG.md` - `config/rbac_tools_matrix.yml` **Реалізовано тут:** - `services/router/tool_manager.py` — TOOL_DEFINITIONS + execution - `services/router/agent_tools_config.py` — per-agent allowlists **RBAC роль `agent_cto`** (39 permissions): ``` docs: read ops: read/exec_safe repo: read jobs: smoke/drift/backup/deploy kb: read risk: read/write pr_review: use pressure: read/write contract: use backlog: read/write/admin config_lint: use deps: read/gate threatmodel: use cost: read/gate observability drift: read/gate incidents: write alerts: ingest/read/ack/claim ``` **Sofiia спеціалізовані tools (agent_tools_config.py):** ```python AGENT_SPECIALIZED_TOOLS["sofiia"] = [ "comfy_generate_image", "comfy_generate_video", "risk_engine_tool", "architecture_pressure_tool", "backlog_tool", "job_orchestrator_tool", "dependency_scanner_tool", "incident_intelligence_tool", "cost_analyzer_tool", "pieces_tool", "notion_tool", ] ``` **FULL_STANDARD_STACK** (16 tools available to all agents): ``` memory_search, graph_query, web_search, web_extract, crawl4ai_scrape, remember_fact, image_generate, tts_speak, presentation_create/status/download, file_tool, repo_tool, pr_reviewer_tool, contract_tool, oncall_tool, observability_tool, config_linter_tool, threatmodel_tool, job_orchestrator_tool, kb_tool, drift_analyzer_tool, pieces_tool ``` **Розриви:** - Відсутній `repo_changeset_tool` (create/patch/plan/pr) - Відсутній `ops_job_tool` (start/status/cancel з job tracking) - `job_orchestrator_tool` є, але не пов'язаний з Dialog Map artifact creation --- ### 2.4 Memory System **Документовано тут:** - `docs/ADR_ARCHITECTURE_VNEXT.md` §2.5 Memory Service - `docs/MEMORY_API_POLICY.md` - `docs/AGENT-MEMORY-STANDARD.md` **Реалізовано тут:** - `services/memory-service/app/main.py` — threads/events/memories/facts/agents - `services/memory-service/app/vector_store.py` — Qdrant - `docker-compose.memory-node2.yml` — Postgres + Qdrant + Neo4j **3 рівні пам'яті (згідно ADR):** | Рівень | Qdrant | Neo4j | Postgres | |--------|--------|-------|----------| | Personal | `user_{id}_*` | `:User` nodes | `user_facts`, `user_sessions` | | Team/DAO | `team_{id}_*` | `:Team`, `:Project` | `team_facts`, `team_quotas` | | Public | `public_*` | `:Public` | `indexed_content` | **Реальні колекції (NODA2):** - `sofiia_messages` — 1183+ points - `sofiia_summaries` - Memory Service Postgres (port 5433, db `daarion_memory`) **Console-рівень пам'яті (SQLite `sofiia.db`):** ```sql projects, documents, sessions, messages ``` **Розриви:** - Team/DAO namespace: описаний в ADR, реалізований лише для Personal - E2EE для confidential: тільки в ADR, не реалізовано - BFF і Memory Service "знають" одне про одного, але sync неповний --- ### 2.5 Planning System (Supervisor) **Документовано тут:** - `docs/supervisor/langgraph_supervisor.md` - `docs/supervisor/postmortem_draft_graph.md` **Реалізовано тут:** - `services/sofiia-supervisor/app/main.py` - `services/sofiia-supervisor/app/graphs/` **Доступні LangGraph графи:** ``` alert_triage → класифікація/ескалація алертів incident_triage → тріаж інцидентів (SLO, labels, owners) postmortem_draft → автогенерація postmortem документа release_check → pre-release gate checks ``` **Архітектура (загальна):** ``` Event/Trigger → LangGraph Node → State update → Next Node ↓ ↓ NATS event Tool calls (via gateway_client) Memory writes Structured output (JSON) ``` **Розриви:** - Немає `cto_intent_graph` (intent → plan → execute) - Немає `repo_changeset_graph` (diff → plan → PR) - Немає `dialog_map_builder_graph` (events → nodes/edges) - Supervisor ізольований від BFF (не інтегрований у `/api/ops/run`) --- ## 3. Policies (Безпека, Дозволи, Approval) ### 3.1 Документовано - `docs/PRIVACY_GATE.md` — Privacy Gate middleware - `docs/ADR_ARCHITECTURE_VNEXT.md` §4 Privacy Gate - `docs/AGENT_RUNTIME_POLICY.md` - `config/rbac_tools_matrix.yml` - `config/data_governance_policy.yml` - `config/risk_policy.yml` ### 3.2 Реалізовано - RBAC tool allowlist: ✅ `agent_tools_config.py` - API key auth: ✅ `auth.py` - Rate limiting: ✅ per-endpoint - Upload sanitization: ✅ mime + filename + size - Voice guardrails: ✅ `sanitize_for_voice()` - Config linter (secrets detection): ✅ `tool_manager.py` ### 3.3 Не реалізовано - **Privacy Gate middleware** (перевірка `mode=confidential` в Router): 📄 описаний, не реалізований - **2-step Plan → Apply flow**: 📄 описаний як "dangerous actions", не реалізований - **E2EE client-side encryption**: 📄 тільки ADR, не реалізований - **Confidential doc indexing block**: 📄 тільки ADR, не реалізований --- ## 4. Event Model ### 4.1 Документовано - `docs/ADR_ARCHITECTURE_VNEXT.md` §5 NATS Standards - `docs/NATS_SUBJECTS.md` - `docs/NATS_SUBJECT_MAP.md` ### 4.2 NATS Subjects (ADR canonical) ``` message.created.{channel_id} # chat messages attachment.created.{type} # uploaded files agent.run.requested.{agent_id} # agent activation agent.run.completed.{agent_id} quota.consumed.{user_id} audit.{service}.{action} # append-only audit ops.health.{service} ops.alert.{severity} ``` ### 4.3 Fabric Subjects (реалізовані у node-worker) ``` node.{id}.llm.request # LLM offload node.{id}.tts.request # TTS offload node.{id}.stt.request # STT offload node.{id}.voice.llm.request # Voice LLM (dedicated) node.{id}.voice.tts.request # Voice TTS (dedicated) node.{id}.voice.stt.request # Voice STT (dedicated) node.{id}.ocr.request # OCR offload node.{id}.crawl.request # Crawl offload node.{id}.image.request # Image generation ``` ### 4.4 Розриви - `attachment.created` — реалізований частково (upload зберігає файл, але не публікує у NATS) - `task_create`, `doc_upsert`, `meeting_create` — не реалізовані (потрібні для Dialog Map auto-edge) - `agent.run.requested` → legacy flat subject ще може бути в деяких шляхах (відомий drift) - Dialog Map не підписаний на NATS events --- ## 5. Memory Architecture (деталізована) ``` ┌──────────────────────────────────────────────────────────┐ │ Sofiia Memory Layers │ ├──────────────────────────────────────────────────────────┤ │ Layer 0: Working Context (per-turn) │ │ - history[-12:] in BFF request │ │ - sanitize_for_voice() for voice turns │ ├──────────────────────────────────────────────────────────┤ │ Layer 1: Session Memory (sofiia-console SQLite) │ │ Tables: projects, documents, sessions, messages │ │ TTL: indefinite (volume-backed) │ │ Fork: parent_msg_id для branching │ ├──────────────────────────────────────────────────────────┤ │ Layer 2: Long-term Memory (Memory Service) │ │ Qdrant: sofiia_messages (1183+ vectors) │ │ sofiia_summaries │ │ Postgres: daarion_memory DB (facts, threads, events) │ │ Neo4j: agent memory graph (infrastructure ready) │ ├──────────────────────────────────────────────────────────┤ │ Layer 3: Factual Memory (Key-Value) │ │ /facts/upsert, /facts/{key} │ │ Rolling summaries via /threads/{id}/summarize │ └──────────────────────────────────────────────────────────┘ ``` **Namespaces (implemented):** - `sofiia_messages` — agent-specific collection - Загальний: `{agent_id}_{type}` pattern **Sync між Layer 1 і Layer 2:** - `_do_save_memory()` у `main.py`: спочатку SQLite, потім Memory Service (best-effort) - Немає зворотнього sync (Memory Service → SQLite) - Немає конфліктів (append-only обидва) --- ## 6. Dialog Map Intelligence ### Поточна реалізація (Phase 1) ``` SQLite messages table (parent_msg_id = branching) ↓ GET /api/sessions/{sid}/map ↓ Python: build_tree(messages) → nodes/edges ↓ UI:
tree ``` ### Цільова реалізація (vNext Phase 2) ``` NATS events (task_create, doc_upsert, meeting_create) ↓ Dialog Map Builder (новий сервіс або Supervisor граф) ↓ Postgres: dialog_nodes + dialog_edges ↓ GET /projects/{id}/dialog-map ↓ UI: D3/Cytoscape canvas + live WS updates ``` **Node types (vNext):** - `message` — chat message - `task` — задача - `doc` — документ/wiki - `meeting` — зустріч - `agent_run` — виклик агента - `decision` — ADR/рішення - `goal` — ціль/OKR **Edge types (vNext):** - `references` — A посилається на B - `resolves` — A вирішує B - `derives_task` — повідомлення → задача - `updates_doc` — action → doc version - `schedules` — message → meeting - `summarizes` — rollup вузол --- ## 7. Preflight-First Policy **Документовано тут:** - `ops/fabric_preflight.sh` - `docs/fabric_contract.md` **Принцип:** "Zero assumptions" — перед будь-яким deploy/change: 1. Запустити `ops/fabric_preflight.sh` 2. Перевірити моделі (VOICE_REQUIRED_MODELS fail / VOICE_PREFERRED_MODELS warn) 3. Перевірити `ops/fabric_snapshot.py --save` 4. Тільки потім deploy **Реалізовано:** - `ops/fabric_preflight.sh` — перевірки моделей, voice health, canary - `ops/scripts/voice_canary.py` — runtime canary (кожні 5–10 хв) - `ops/voice_latency_audit.sh` — 10-сценарний latency audit --- ## Next Actions for UI Team (1–2 days) 1. **Ознайомитись із Supervisor API** (`/v1/graphs/{name}/runs`) — це готовий "job runner" для CTO workflows 2. **Розширити Supervisor**: додати `cto_intent_graph` на базі `release_check_graph` (спільна структура) 3. **NATS attachment events**: при upload в `docs_router.py` — публікувати `attachment.created` (1 рядок коду) 4. **Dialog Map NATS listener**: простий consumer що upsert-ить SQLite nodes при events 5. **`docs_versions` table**: ALTER TABLE + endpoint — 1–2 год роботи 6. **Privacy Gate stub**: додати перевірку `mode` поля в BFF, навіть якщо без шифрування 7. **Plan → Apply pattern**: для ops actions — показувати "план" перед запуском 8. **`agent_id` нормалізація**: замінити `"l"` на `"sofiia"` в node2 router-config.yml 9. **Memory sync**: додати endpoint для завантаження Sofiia memory з Memory Service у SQLite 10. **CTO Panel**: mock `/api/repo/changesets` і `/api/ops/runs` endpoints для UI розробки