Files
ratatoskr-go/.serena/memories/core.md
ki.sagidullin 9f64be4ea5
Some checks failed
CI / test (pull_request) Failing after 32s
CI / build-and-package (amd64, linux) (pull_request) Successful in 42s
CI / build-and-package (amd64, windows) (pull_request) Successful in 42s
feat(opencode): переход на v2 HTTP API opencode (хардпин модели, поллинг вердикта)
- 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)
2026-08-19 08:29:11 +05:00

5.9 KiB
Raw Blame History

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.