Skip to content

P-CLAW-AGENT-CORE этап 1: агентный цикл оператора (loop + verification) - #34

Draft
EpicStarAi wants to merge 3 commits into
backup/operator-ui-account-fetchfrom
feat/claw-agent-loop
Draft

P-CLAW-AGENT-CORE этап 1: агентный цикл оператора (loop + verification)#34
EpicStarAi wants to merge 3 commits into
backup/operator-ui-account-fetchfrom
feat/claw-agent-loop

Conversation

@EpicStarAi

Copy link
Copy Markdown
Owner

P-CLAW-AGENT-CORE — этап 1: оператор из «одного вызова» в агентный цикл

Draft. Базовая ветка PR: backup/operator-ui-account-fetch (7659db4) — это линия прод-релиза, несущая фундамент гейта (getPrincipal, resolveBoundAccount, telegramMutationsEnabled, approval-гейт prepare→confirm→execute, operator-роуты). В main этого фундамента нет. Тега qclaw-release-20260717-1130 в репозитории не существует; ближайшая соответствующая проду ветка — эта.

Первый коммит (fix(guard)) восстанавливает binding-backed resolveBoundAccount из origin/backup/auth-session-bootstrap — база сама по себе не компилировалась (регресс в telegramGuard.ts). Это идентично тому, что использует параллельная auth-guard-сессия → чистый мёрж, без конфликта.

Что построено (§1 + §3 спеки)

Движок цикла (apps/web/lib/agent/, чистый, юнит-тестируемый):

  • types.tsAgentRun / AgentStep / AgentStepResult, порты (ToolRegistry, Planner, RunStore, Clock). maxSteps=12, таймаут рана, REPEAT_LIMIT.
  • runLoop.ts — план → выбрать шаг → (risk=mutation ⇒ пауза на approval-гейт) → вызвать инструмент → верифицировать → записать → переоценить. Жёсткий maxSteps И wall-clock таймаут, детект повторяющегося шага, запись шага ДО и ПОСЛЕ выполнения, ошибка инструмента не убивает run молча, отмена проверяется между шагами и сразу после вызова (уже выполненное внешнее действие фиксируется, не откатывается).
  • verify.tsderiveStepStatus: success только при пройденной верификации; ok без проверки ⇒ unverified; проверка опровергла ⇒ failed; мутация не может быть unverified.
  • planner.ts — детерминированный HeuristicPlanner, который раскладывает цель на этапы и переоценивает по реальным результатам (пустой/упавший read меняет следующий ход). LLM-планировщик встаёт за тот же порт позже.
  • tools.ts — реальный реестр: read/draft через backend /ai/route (никогда не шлёт); publish — mutation-заглушка, которую цикл не исполняет.

Персистентность (по образцу telegramBindings): agentRunsDb.ts (pg, CREATE TABLE IF NOT EXISTS, аддитивно) + agentRunsStore.ts (fs-фолбэк, работает без DATABASE_URL); migrations/003_agent_runs.sql.

Роуты (аутентифицированы, безопасность не ослаблена):

  • POST /api/operator/rungetPrincipal 401; слот резолвится на сервере через resolveBoundAccount; accountId из тела игнорируется; запускает цикл, возвращает id рана.
  • GET /api/operator/run/[id] — auth + owner-scoped; account id маскируется.
  • POST /api/operator/run/[id]/cancel — auth + owner-scoped; ставит флаг отмены.

UI: изолированная панель «Агентный цикл» в Operator Office — цель, план, шаги с intent + risk + бейджем статуса (partial/unverified/awaiting_approval показаны иначе, чем success), кнопка Стоп.

Дисциплина проверки (§3)

Шаг не может быть success только потому, что вызов не бросил исключение. Для каждого шага отдельно хранится verified {method, passed, evidence}. Искусственно сломанный инструмент (ok без эффекта) даёт failed; непроверяемый — unverified; ни то ни другое не зелёная галочка. Мутация никогда не исполняется в цикле — пауза waiting_approval под существующий гейт.

Безопасность (не ослаблена)

  • Все три роута требуют getPrincipal (в обработчике — middleware /api/operator/* тут не покрывает; параллельная сессия закрывает это отдельно, я не конфликтую).
  • Слот — только resolveBoundAccount на сервере; клиентский accountId игнорируется.
  • Мутации — только через prepare→confirm→execute, уважают telegramMutationsEnabled(); никакого обхода, никакого захардкоженного operatorApproved.
  • Read/draft — без approval.

ЗАПРЕЩЁННОЕ — не делалось

Нет mock/demo/fake-success; нет деплоя; нет реальных отправок в Telegram; TELEGRAM_MUTATION не менялся; TDLib-сессии и привязки не тронуты.

Проверки — всё зелёное

  • npm run build ✓ (Compiled successfully; роуты /api/operator/run* зарегистрированы), tsc --noEmit ✓, npm run lint ✓ (только пре-существующий baseline warnings).
  • npm test17/17 (12 новых: полный цикл, отмена между шагами, детект зацикливания, maxSteps, таймаут, честная ошибка инструмента, дисциплина верификации, сломанный инструмент ⇒ не-зелёный, unverified, мутация не исполняется).
  • Живой прогон на кандидате: неаутентифицированные POST/GET/cancel401; cross-user GET чужого рана → 403. Аутентифицированный ран собери→проанализируй→подготовь: шаг Bootstrap Core v1 infrastructure and AI Operator docs #1 get_last_messagessuccess (verified.passed=true); шаг Reconcile production P3.5-P3.8 hotfixes into GitHub #2 summarize_chatfailed (LLM отключён в среде — честная ошибка бэкенда, не фейковый успех); планировщик переоценил, повторил один раз, затем честно остановился (failed: stage_failed:summarize_chat). Зелёный многошаговый финал требует включённого LLM (env), сам цикл детерминированно доказан тестами.

🤖 Generated with Claude Code

EpicStarAi and others added 3 commits July 19, 2026 19:00
Base branch backup/operator-ui-account-fetch (7659db4) regressed the guard to a
null-stub resolveBoundAccountId and dropped resolveBoundAccount, while 7 routes
still import it — the tree does not typecheck. Restore the deny-by-default,
binding-backed guard verbatim from origin/backup/auth-session-bootstrap (the
BoundResolution ok/none/mismatch resolver). Identical to the guard the parallel
auth-guard session uses, so this is a prerequisite, not a competing change.

Prereq for P-CLAW-AGENT-CORE stage 1 (agent loop).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…routes

P-CLAW-AGENT-CORE stage 1 (§1 + §3): turn the operator from one call into an
agentic loop.

Engine (lib/agent, pure + unit-testable via Node type-stripping):
- types.ts: AgentRun / AgentStep / AgentStepResult, ports (ToolRegistry,
  Planner, RunStore, Clock). maxSteps=12, run timeout, REPEAT_LIMIT.
- runLoop.ts: plan -> pick -> (mutation => approval gate, pause) -> call ->
  verify -> record -> re-evaluate. Hard maxSteps AND wall-clock timeout,
  repeated-step detection, per-step persist BEFORE + AFTER, tool errors never
  silently kill the run, cancel checked between steps and mid-call (already-run
  external effects recorded, not rolled back).
- verify.ts: deriveStepStatus — success ONLY with a passing verification; ok
  without a check => unverified; contradicted => failed; mutation may never be
  unverified. Reusable verifiers (message-id, nonempty, count).
- planner.ts: deterministic HeuristicPlanner that decomposes the goal and
  RE-EVALUATES on real results (empty/failed reads change the next move); an
  LLM planner can drop in behind the same port later.
- tools.ts: real registry — read/draft via backend /ai/route (never sends);
  publish maps to a mutation guard the loop never executes.

Persistence (mirrors telegramBindings): agentRunsDb.ts (pg, CREATE TABLE IF NOT
EXISTS, additive) + agentRunsStore.ts (fs fallback, works with no DATABASE_URL);
migrations/003_agent_runs.sql.

Routes (authenticated, security not weakened):
- POST /api/operator/run — getPrincipal 401; slot resolved server-side via
  resolveBoundAccount; body accountId ignored; launches loop, returns run id.
- GET /api/operator/run/[id] — auth + owner-scoped; account id masked.
- POST /api/operator/run/[id]/cancel — auth + owner-scoped; sets cancel flag.

Tests: 12 new (loop completion, cancel-between-steps, loop detection, maxSteps,
timeout, honest tool-error, verification discipline, broken-tool => not-green,
unverified, mutation-never-executed). Full suite 17/17 green; tsc --noEmit clean.

tsconfig: allowImportingTsExtensions (permissive) so the engine's .ts imports
load in both next build and node --test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ncel

Adds an isolated "Агентный цикл" panel to the Operator Office that drives the
authenticated loop routes: POST /api/operator/run, poll GET /run/[id], and a
Stop button -> POST /run/[id]/cancel. Each step shows its plain-language intent,
risk chip and status badge; partial / unverified / awaiting_approval render
DISTINCTLY from a green success (an unverified step is never a check-mark), with
the verification method + evidence shown per step. Self-contained component +
one dashboard zone; no change to the existing chat flow (keeps this isolated
from parallel sessions). .gitignore: local .agent-runs.json fs store.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant