# 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** — тестирование