- client.go: эндпоинты /api/* (create+model, prompt-admit, message, active, interrupt) - runner.go: неблокирующий prompt + поллинг новых assistant-сообщений; завершение = сессия ушла из активных дренажей + стабильное финальное сообщение - config.go: чтение top-level model из opencode.jsonc (JSONC-стрип) + хардпин в сессию - server.go: healthcheck /api/health, MinVersion=1.18.18, понятная ошибка для старого бинаря - класс O5 WARN: устойчивость к v1-конфигу провайдера (npm/options игнорируются v2) - README: раздел интеграции, минимальная версия opencode, предупреждения - .serena: актуализация памяти (core, tech_stack)
5.9 KiB
5.9 KiB
core
Ratatoskr-go — оркестратор конвейера Ratatoskr (порт с Python на Go) в единый статический бинарь (CGO_ENABLED=0). Субагенты запускаются через внешний процесс opencode. Взаимодействие — Telegram-бот.
Структура (модули internal/)
cmd/ratatoskr/ точка входа, сборка бинаря; main.version и main.updateToken вшиваются ldflag'ом
internal/
app/ composition root/DI: App.New -> config.Load+Validate, ResolveExePaths, storage, Runner, Analyst, Core, Worker, Updater. packageOwner="kamelion", Version="0.1.0"
config/ YAML+env загрузка (${VAR:-default}), defaults, validate C1-C4
chat/ мультиканальный Router; telegram — long-poll канал. Коды M1-M5
core/ state-machine задач + Decider/analyst интерфейс. Коды D3/D4
analyst/ аналитик: промпт + разбор JSON-вердикта (opencode agent). Коды A1-A4
worker/ polling-планировщик + dev/reviewer-конвейер + gitops. Коды W*, E*, R*
agents/ встроенные opencode-агенты (analyst.md, dev.md, reviewer.md) через go:embed
opencode/ HTTP-клиент v2 API opencode serve, поллинг вердикта, LiveRegistry. Коды O1-O5
storage/ SQLite (modernc.org/sqlite, без CGO): tasks, traces, task_history. Коды S1-S5
update/ автообновление из Gitea Packages. Коды U1-U6
Ключевые инварианты
- Команды/ядро: Core.ProcessTurn — state-machine поверх storage. Команды: /start /cancel /skip /retry N /status N /continue N. Активная задача — одна на чат.
- Фазы аналитика (Decision.Phase):
ask(уточняющие вопросы),propose(правки черновика),ready(черновик полон как есть),abort(тема вне проекта). propose и ready в core обрабатываются одинаково. - Статусы задач: draft→collecting→ready→approved→running→success/failed/timeout, плюс cancelled/aborted/closed. approved — финальное одобрение («создавай»), после чего воркер берёт задачу. IsValidTransition/IsTerminal в storage/models.go.
- Decider/Worker/Analyst/Reviewer: Decider=analyst интерфейс (analyst пакет реализует); Worker — polling-планировщик dev-агента; Reviewer проверяет diff dev-ветки (R1-R6), вердикт JSON {passed, critical_issues, solid_violations, comments}.
- gitops (worker): worker работает с worktrees; feature-ветка =
feat/<taskTag>от origin/main; ensureBranch (reset --hard + clean -fd + checkout -B), branchDiff (origin/main...<branch>), push через http.extraHeader, токен как Bearer. - Пути «всё рядом с .exe»: относительные db/worktree резолвятся от каталога бинаря (ExeDir), не от cwd. config.yaml ищутся рядом с бинарём, фоллбэк cwd.
- Автообновление: авто = только Check+уведомление; замена — по /update. Версии в
Gitea Packages
commit-<sha7>/(неlatest/). Вердикты агентов — строгий JSON.
opencode (v2 HTTP API, >= 1.18.18)
- Интеграция с субагентами — через headless
opencode serve, v2 API (префикс/api/*). Минимальная версия opencode >= 1.18.18 (старый бинарь — только/global/health, не годится; healthcheck падает с понятной ошибкой, класс O1). - Хардпин модели: при создании сессии читается top-level
"model"из конфига opencode (internal/opencode/config.go, JSONC-стрип////* *//trailing-запятых) и передаётся вPOST /api/sessionкак{"model":{providerID,id}}(разборprovider/idпо первому/). - Класс O5 WARN (устойчивость к v1-конфигу): конфиг по старой v1-схеме
(
provider.X.npm/options) молча игнорируется v2 → провайдер без api → модель unsupported → fallback. Раtatoskr не чинит это сам, но логирует warning: конфиг не читается/нетmodel, и/или фактическая модель ответа (из assistant-сообщения) ≠ ожидаемой. Правильный v2-вид:api:{type:"aisdk",package,url}иrequest.headersвместоoptions.headers. - Поллинг вердикта:
POST /api/session/:id/prompt(durable admit, неблокирующий) →GET /api/session/:id/message?order=desc&limit=200(новые assistant-сообщения, текст вcontent[].type=="text") → завершение =GET /api/session/activeбез сессии + финальное assistant-сообщение, стабильноеsettlePolls=2опроса.POST .../interruptвместо abort. ModelRef{ProviderID,ID,Variant}— аналог v2 Model.Ref;MinVersion="1.18.18"в server.go.
Контракты (не ломать)
App.New(configPath, version, updateToken string)— сигнатура.packageOwner— константа "kamelion" (не плодить vars/ldflag/конфиг).update.Updater— создаётся структурой&update.Updater{...}, конструктора нет.
См. также mem:tech_stack, mem:conventions, mem:task_completion, mem:suggested_commands.