ducklm/CURRENT_STATE.md

253 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# DuckLM — Текущее состояние проекта
## 1. Что это
DuckLM — локальный event-driven multi-model AI agent runtime. Система принимает пользовательскую задачу, извлекает релевантную память, собирает контекст, принимает orchestration-решение, при необходимости строит план, исполняет шаги через tools и coder, оценивает результаты через critic, сохраняет полезное в долговременную память, публикует события и поддерживает streaming клиенту.
**Ключевой принцип:** центр системы — `RuntimeLoop`. Все execution transitions проходят через него. Router, Orchestrator, ExecutionEngine — decision-producing компоненты, которые только возвращают структурированные объекты (ExecutionDirective), но не исполняют действия напрямую.
## 2. Архитектура
```
Client / CLI / API
RuntimeLoop (runtime_loop.py)
├── State Store / Checkpoints (SQLite)
├── ContextBuilder
├── AsyncRouter (Thinker → JSON Compiler)
├── ExecutionEngine / ExecutionScheduler
│ ├── ToolRegistry / ToolSandbox
│ ├── CoderAdapter
│ └── CriticAdapter
├── PermissionService
├── MemoryRecallService
├── MemoryWritePolicy
├── MemoryInterface (SQLite + hnswlib)
└── EventBus → SQLiteEventStore
StreamingManager → WebSocket
```
## 3. Структура проекта
```
ducklm/
main.py # Точка входа (импорт app.api.server.app)
app/
api/
server.py # FastAPI: POST /chat, WS /stream, GET /health, etc.
static/index.html # Веб-чат (dark theme, Enter=отправить, Shift+Enter=новая строка)
cli/__init__.py # Пока пустой
core/
contracts.py # Pydantic модели: UserTask, PlanStep, ToolResult, CriticScore, ...
config.py # AppConfig, load_app_config()
async_router.py # AsyncRouter: Thinker + JSON Compiler pipeline
context_builder.py # ContextBuilder: сборка контекста с бюджетами
execution_engine.py # ExecutionEngine: исполнение plan/tool/respond/coder
execution_scheduler.py # ExecutionScheduler: парсинг плана, граф задач, цикл выполнения
intent_parser.py # IntentParser: извлечение tool intents из текста
permission_service.py # PermissionService: проверка и разрешений команд
permission_resolution.py # Pydantic модели для API разрешений
events/
event_bus.py # EventBus: per-task ordered publishing
event_store.py # SQLiteEventStore: append-only log
event_types.py # Константы типов событий
memory/
interface.py # MemoryInterface: insert/search/get/delete/reindex/cleanup
store.py # MemoryStore: SQLite хранение MemoryEntry + embeddings
vector_index.py # VectorIndex: hnswlib L2 index
recall.py # MemoryRecallService: LLM-based решение о необходимости recall
write_policy.py # MemoryWritePolicy: детерминированное решение о записи
models/
adapters.py # create_adapter/create_llama_adapter (llama-cpp-python)
async_adapters.py # AsyncOrchestratorAdapter, AsyncCoderAdapter, AsyncCriticAdapter
orchestrator.py # OrchestratorAdapter: обёртка над Llama
coder.py # CoderAdapter
critic.py # CriticAdapter
embeddings.py # EmbeddingsAdapter (sentence-transformers)
permissions/
approval_store.py # SQLiteApprovalStore
runtime/
runtime_loop.py # RuntimeLoop: центральный цикл (sync)
async_runtime_loop.py # AsyncRuntimeLoop: альтернативная async версия
runtime_controller.py # RuntimeController: composition root, инициализация всего
services/__init__.py # Пустой
state/
task_state_store.py # SQLiteTaskStateStore
checkpoint_store.py # SQLiteCheckpointStore
streaming/
manager.py # StreamingManager: подписка на события → WebSocket
tools/
base.py, registry.py, sandbox.py, discover.py
shell_exec.py, file_read.py, file_write.py, memory_tools.py
plugins/ # Plugin discovery: shell_exec, file_read, file_write, memory_tools
config/
models.json # Конфигурация моделей
runtime.json # Таймауты, retry limits, context budgets
permissions.json # Категории команд, пути
prompts/ # Markdown промпты для каждой роли
thinker.md, json_compiler.md, coder.md, critic.md, sys_util.md, orchestrator.md, planning.md, system.md
data/
events/events.sqlite3 # Event store
state/task_state.sqlite3 # Task state
state/checkpoints.sqlite3 # Checkpoints
permissions/approvals.sqlite3 # Permission cache
memory/memory.sqlite3 # Memory store
memory/index.bin # Vector index
models/ # GGUF модели и sentence-transformers
tests/
test_contracts.py # 6 тестов: контракты, router
test_runtime_loop.py # 2 теста: runtime loop events, permission flow
test_tools_flow.py # 7 тестов: file read/write, shell, recovery, permissions
test_api_handlers.py # 6 тестов: health, events, chat, permissions, feedback
```
## 4. Модели и их роли
| Роль | Модель | Backend | Конфиг |
|------|--------|---------|--------|
| Thinker (orchestrator) | Qwen3.5-9B-GLM5.1-Distill-v1-Q4_K_M.gguf | vulkan (GPU) | max_tokens=2048, temp=0.3 |
| JSON Compiler | gemma-4-E4B-it-Q4_K_M.gguf | cpu | max_tokens=1024, temp=0.1 |
| Critic | gemma-4-E4B-it-Q4_K_M.gguf (shared с compiler) | cpu | max_tokens=1024, temp=0.1 |
| Coder | X-Coder-SFT-Qwen3-8B.Q6_K.gguf | cpu | max_tokens=2048, temp=0.2 |
| Sys Utility | Menlo_Lucy-Q4_K_M.gguf | cpu | max_tokens=1024, temp=0.1 |
| Embeddings | all-MiniLM-L6-v2 (sentence-transformers) | — | dim=384 |
**Важно:** Critic и JSON Compiler используют одну и ту же модель (gemma-4B), но разные экземпляры адаптеров. Модели не дублируются в памяти — используется кэширование через `_get_or_create_llm()` с ключом (path, backend, n_gpu_layers, n_ctx).
## 5. Конфигурация
Все настройки в `config/`:
- **models.json** — пути к GGUF файлам, backend, GPU layers, max_tokens, temperature
- **runtime.json** — таймауты (step=30s, task=5min), retry limits, context budgets, retrieval_top_k
- **permissions.json** — hard_stop команды (rm -rf /, dd, mkfs), no_always команды (shutdown, killall), normal команды
- **prompts/*.md** — системные промпты для каждой роли модели
## 6. API
FastAPI сервер на порту 8000 (`scripts/server.sh`):
| Метод | Путь | Описание |
|-------|------|----------|
| GET | `/` | Веб-чат (index.html) |
| GET | `/health` | Health check |
| GET | `/events` | Список последних событий |
| POST | `/chat` | Отправить задачу (UserTask) → получить результат |
| POST | `/permissions/resolve` | Разрешить/запретить команду |
| POST | `/secrets/resolve` | Передать sudo-пароль |
| POST | `/password/resolve` | Передать пароль (альтернативный путь) |
| POST | `/critic/feedback` | Обратная связь от пользователя |
| WS | `/stream/{task_id}` | Streaming событий по задаче |
## 7. Поток выполнения задачи
1. Клиент → POST /chat → `RuntimeController.handle_task()`
2. `RuntimeLoop.run_task()`:
- Проверка hard-stop команд через PermissionService
- Создание task state в SQLiteTaskStateStore
- Публикация TASK_RECEIVED
- Checkpoint: received
- ContextBuilder.build() — сборка контекста (memory, tools, budgets)
- MemoryRecallService.recall() — LLM решает, нужно ли искать в памяти
- AsyncRouter.decide() — Thinker → JSON Compiler → ExecutionDirective
- ExecutionEngine.execute() — исполнение directive:
- plan → парсинг шагов → граф → последовательное выполнение
- tool → проверка разрешений → ToolSandbox → ToolResult
- respond → прямой ответ
- coder → CoderAdapter
- Critic оценка каждого шага (correctness, usefulness, safety)
- Recovery при неудачных шагах (retry/continue/respond/fail)
- MemoryWritePolicy — решение о записи в долговременную память
- Checkpoint: final state
- Публикация TASK_COMPLETED / TASK_FAILED / TASK_AWAITING_PERMISSION
3. Результат возвращается клиенту + события доступны через WebSocket
## 8. Что реализовано и работает
### Core (полностью)
- [x] Модульная структура проекта (app/, config/, data/, tests/)
- [x] Typed contracts (Pydantic модели для всех сущностей)
- [x] RuntimeLoop — центральный цикл
- [x] RuntimeController — composition root
- [x] EventBus + SQLiteEventStore (append-only, per-task ordering)
- [x] TaskStateStore + CheckpointStore (SQLite)
- [x] ContextBuilder с token budgets
- [x] AsyncRouter: Thinker → JSON Compiler pipeline с retry и JSON fix
- [x] IntentParser: извлечение tool intents из естественного языка
- [x] ExecutionEngine: plan/tool/respond/coder/fail
- [x] ExecutionScheduler: парсинг плана, DAG граф, cycle detection
- [x] PermissionService: hard_stop/no_always/normal категории, кэш разрешений
- [x] ToolSandbox: timeout, cwd restrictions
- [x] ToolRegistry + Plugin Discovery
- [x] Tools: shell_exec, file_read, file_write, memory_insert/search/list
- [x] CriticAdapter с retry и recovery (continue/retry/respond/fail)
- [x] MemoryInterface: SQLite + hnswlib vector index
- [x] MemoryRecallService: LLM-based решение о необходимости recall
- [x] MemoryWritePolicy: детерминированное решение о записи
- [x] EmbeddingsAdapter (sentence-transformers)
- [x] FastAPI API: /chat, /health, /events, /permissions/resolve, /secrets/resolve, /critic/feedback
- [x] WebSocket streaming (/stream/{task_id})
- [x] Веб-чат (dark theme, Enter=отправить, Shift+Enter=новая строка, панель событий, permission controls, feedback dialog)
- [x] 21 тест (все проходят)
### Известные баги (исправлены)
- RECALL_PROMPT_TEMPLATE format string escaping — фигурные скобки в JSON примерах нужно двоить
- VectorIndex._get_memory_id возвращал неправильный ID (hash вместо хранения mapping)
- recall_model по умолчанию был sys_util, изменён на json_compiler
## 9. Что ещё нужно сделать
### Приоритет 1 — Доработка до полного MVP
- [ ] **Resume из checkpoint** — после падения/перезапуска восстанавливать задачу из последнего checkpoint
- [ ] **CLI интерфейс** — отправка задач, просмотр событий, поиск в памяти из терминала (app/cli/ пока пустой)
- [ ] **Structured logging** — вместо print() использовать logging с форматированием
- [ ] **WS /stream** — доработать (сейчас базово работает, но нет подписки на новые события в реальном времени при длительных задачах)
### Приоритет 2 — Улучшения
- [ ] **Retry/recovery policy** — более надёжная обработка ошибок tool execution
- [ ] **Replay из event store** — воспроизведение истории задачи для отладки
- [ ] **Параллельное выполнение шагов** — сейчас только sequential DAG, можно добавить parallel для независимых шагов
- [ ] **Веб-чат: отображение streaming ответа** — сейчас ответ приходит целиком, можно добавить потоковую передачу
- [ ] **Веб-чат: отображение tool output** — более красивый рендер результатов shell/file операций
- [ ] **Memory cleanup** — автоматическая очистка старых/низко-весовых записей (базовая логика есть в MemoryInterface.cleanup, но не вызывается автоматически)
### Приоритет 3 — Расширения
- [ ] **web_search / web_fetch tools** — второй приоритет по TASK_3.md
- [ ] **Telegram bot stub** — thin клиент для удалённого управления
- [ ] **Coder integration в план** — пока coder adapter есть, но не интегрирован в планирование как отдельный step kind
- [ ] **Модели: загрузка при старте** — load_models_at_startup() вызывается из lifespan, но если модели не загружены, runtime работает в fallback mode (respond only)
- [ ] **Документация API** — OpenAPI схема генерируется FastAPI, но можно добавить примеры
## 10. Запуск
```bash
cd ~/git/ducklm
./scripts/server.sh
# или
uvicorn main:app --host 0.0.0.0 --port 8000
```
Веб-чат: http://localhost:8000/
## 11. Тестирование
```bash
cd ~/git/ducklm
python -m pytest tests/ -v
```
21 тест, все проходят. Покрытие: контракты, runtime loop, tool flow, API handlers.
## 12. Технологии
- **Python 3.13**, FastAPI, uvicorn, websockets
- **llama-cpp-python** — локальный инференс GGUF моделей (Vulkan/CPU)
- **sentence-transformers** — эмбеддинги (all-MiniLM-L6-v2)
- **hnswlib** — векторный поиск (L2 метрика)
- **SQLite** — event store, task state, checkpoints, memory, permissions
- **Pydantic** — все контракты
- **pytest** — тестирование