ducklm/CURRENT_STATE.md

16 KiB
Raw Blame History

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 (полностью)

  • Модульная структура проекта (app/, config/, data/, tests/)
  • Typed contracts (Pydantic модели для всех сущностей)
  • RuntimeLoop — центральный цикл
  • RuntimeController — composition root
  • EventBus + SQLiteEventStore (append-only, per-task ordering)
  • TaskStateStore + CheckpointStore (SQLite)
  • ContextBuilder с token budgets
  • AsyncRouter: Thinker → JSON Compiler pipeline с retry и JSON fix
  • IntentParser: извлечение tool intents из естественного языка
  • ExecutionEngine: plan/tool/respond/coder/fail
  • ExecutionScheduler: парсинг плана, DAG граф, cycle detection
  • PermissionService: hard_stop/no_always/normal категории, кэш разрешений
  • ToolSandbox: timeout, cwd restrictions
  • ToolRegistry + Plugin Discovery
  • Tools: shell_exec, file_read, file_write, memory_insert/search/list
  • CriticAdapter с retry и recovery (continue/retry/respond/fail)
  • MemoryInterface: SQLite + hnswlib vector index
  • MemoryRecallService: LLM-based решение о необходимости recall
  • MemoryWritePolicy: детерминированное решение о записи
  • EmbeddingsAdapter (sentence-transformers)
  • FastAPI API: /chat, /health, /events, /permissions/resolve, /secrets/resolve, /critic/feedback
  • WebSocket streaming (/stream/{task_id})
  • Веб-чат (dark theme, Enter=отправить, Shift+Enter=новая строка, панель событий, permission controls, feedback dialog)
  • 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. Запуск

cd ~/git/ducklm
./scripts/server.sh
# или
uvicorn main:app --host 0.0.0.0 --port 8000

Веб-чат: http://localhost:8000/

11. Тестирование

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