From 0386058f5b50f471e2f9752a774d0f90b6b53cd3 Mon Sep 17 00:00:00 2001 From: root Date: Sun, 12 Jul 2026 02:44:48 +0200 Subject: [PATCH] =?UTF-8?q?docs:=20=E5=9B=BA=E5=8C=96=20Queue=20=E7=BB=88?= =?UTF-8?q?=E6=80=81=E9=87=8D=E8=AF=95=E8=B5=84=E6=BA=90=E5=8E=9F=E8=AF=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/reference/spec-v01-cli.md | 5 +++- docs/reference/spec-v01-postgres.md | 11 +++++-- docs/reference/spec-v01-queue.md | 45 ++++++++++++++++++++++++++--- 3 files changed, 53 insertions(+), 8 deletions(-) diff --git a/docs/reference/spec-v01-cli.md b/docs/reference/spec-v01-cli.md index c874c07..05fcb89 100644 --- a/docs/reference/spec-v01-cli.md +++ b/docs/reference/spec-v01-cli.md @@ -137,9 +137,11 @@ CLI 官方 TypeScript 入口固定为 `scripts/agentrun-cli.ts`。在 G14 非交 - `tool-credentials list|show` 调用 manager REST 读取固定 tool credential 状态,只显示 SecretRef、key presence 和 hash 后缀;不得输出 Secret data。 - `tool-credentials set-github-ssh` 是 GitHub SSH runtime Secret 的受控 bootstrap 入口;输入只能来自本地文件,CLI/manager response 只能显示 bytes、hash suffix、SecretRef 和 `valuesPrinted=false`,不得输出 private key、known_hosts 或 ssh config 内容。 - `backends list` 必须显示 `codex`、`deepseek`、`minimax-m3` 与 `dsflash-go` profile 的 backendKind、protocol、transport、command、requiredSecretKeys 和状态;`dsflash-go` 的 `requiredSecretKeys` 必须包含 `model-catalog.json`;已配置的动态 provider profile(例如 `hy`)必须同样可见,并带动态 discovery 状态;不得因为某个 provider Secret 尚未配置就隐藏 capability。 -- `queue submit/read/cancel/dispatch/refresh --dry-run` 必须只返回 non-mutating plan,固定 `dryRun=true`、`mutation=false`,不得创建 task、mark read、cancel、dispatch、refresh 或启动 runner job。 +- `queue submit/read/cancel/dispatch/refresh/retry --dry-run` 必须只返回 non-mutating plan,固定 `dryRun=true`、`mutation=false`,不得创建 task、mark read、cancel、dispatch、refresh、attempt、run、command 或 runner job。 - `queue dispatch` 是 Q2 的受控手动调度入口,只对单个 task 显式创建 attempt 和 Core run/command/runner job;不得伪装成自动 scheduler;带 `--dry-run` 时只读取 task 并展示将要 POST 的路径和有界 request 摘要。 - `queue refresh` 只根据 Queue task 中保存的 Core run/command 引用回写 Queue attempt 状态,不读取 Core trace 反推 commander 或统计;带 `--dry-run` 时不得写回状态。 +- `queue attempts ` 必须通过 manager REST 分页读取正式 attempt 历史;默认只展示 identity、retry index、状态、Core 资源引用和有界失败可见性,完整记录只能显式 `--full|--raw`。 +- `queue retry --idempotency-key --reason ` 只调用正式 retry 资源原语;不得接受 task/dispatch patch,也不得在 CLI 本地创建 run、command 或 runner Job。相同 key 重放返回同一 attempt;`--dry-run` 做全校验、零写入。 - `queue list/show/commander` 默认返回低噪声 summary,只显示 task/attempt/session ids、state、read cursor、stats 相关字段、compact supervisor 和 drill-down 命令;commander 的 supervisor 只能放 `phase`、last activity source seq/id、timeout budget 和恢复动作摘要,不得展开完整 payload、trace、tool command、stdout/stderr 或 runnerTrace。需要完整 task payload、resource bundle 或 metadata 时显式使用 `--full|--raw`;需要 trace/output 细节时继续按返回的 `sessionId`/`sourceSeq` 走 `sessions trace|output --seq/--event-id/--item-id --full`。 - `queue show` 不得返回或代理完整 output/trace;输出和 trace 只能通过返回的 `sessionPath` 对应 `sessions ...` 命令查询。 - 需要提交较长 Queue task、dispatch body、run base 或 command payload 时,CLI 必须把 `--json-stdin` 作为首选入口,避免为了 heredoc/stdin 内容先写临时 dump 文件再传 `--json-file`;`--json-file` 只用于可复用、已受控的输入文件。`queue submit/dispatch --dry-run` 的 `next.confirm` 不得默认推荐 `--json-file`,有 JSON body 时应提示 `--json-stdin`;只有用户显式维护可复用文件时才使用 file fallback。`sessions send` 的 runner job override 也必须支持 `--runner-json-stdin`。所有 stdin JSON 仍必须解析为 object,并在 dry-run 中只展示有界 body 摘要、bytes 和 keys。 @@ -223,6 +225,7 @@ CLI 官方 TypeScript 入口固定为 `scripts/agentrun-cli.ts`。在 G14 非交 | result/cancel CLI | 已实现 | `runs result`、`commands result`、`runs cancel` 和 `commands cancel` 均调用 manager REST,不维护独立状态。 | | Queue CLI | 已实现/Q1 | 已提供 `queue submit/list/show/stats/commander/read/cancel`,通过 manager REST 访问 Queue task 和 stats,不直连 Postgres。 | | Queue dispatch/refresh CLI | 已实现/Q2 | `queue dispatch` 受控创建 Core run/command/runner job;`queue refresh` 从 Core run/command 终态回写 Queue task/latestAttempt。 | +| Queue retry/attempts CLI | 已实现/Q5 最小切片 | `queue retry` 提供显式幂等终态重试,`queue attempts` 查询正式历史;自动 scheduler、backoff 和 judge 不在该入口内实现。 | | 本地 server 生命周期 CLI | 已实现/Q2 hardening | `server start` 默认后台短返回,`server status/stop` 提供 pid、port、logPath 和 readiness 可见性;`--foreground` 保留给容器/显式调试。 | | stdio 事件部分重建 CLI | 已实现/debug | 按 `sessionId` 从 Kafka 或 JSONL 调用生产 reducer,默认写独立 debug topic/group,永久禁止写产品 topic,并显式披露不可恢复的 durable identity 与 lifecycle。 | | Session CLI | 已实现/Q3 | 已提供 `sessions ps/show/send/cancel/trace/output/read`;默认 ps 只显示 running/unread,terminal 后自动 unread,read cursor 由 CLI 标记。用户级 CLI 只保留 `send`;`turn/steer` 只作为 manager 内部 command type,不再作为 CLI 入口或兼容 alias。 | diff --git a/docs/reference/spec-v01-postgres.md b/docs/reference/spec-v01-postgres.md index 870787c..41ec3fb 100644 --- a/docs/reference/spec-v01-postgres.md +++ b/docs/reference/spec-v01-postgres.md @@ -38,7 +38,7 @@ Secret 名称和 key 可以在实现时按 Kubernetes 命名限制微调,但 - `agentrun_sessions`:SessionRef 到 backend thread/cache identity、execution projection、active run/command、terminal/unread 水位的映射,不保存 credential 文件或 Secret 值。 - `agentrun_session_read_cursors`:按 reader 记录 Session 已读 version,用于 CLI 默认只看 running/unread。 - `agentrun_queue_tasks`:AgentRun Queue task identity、queue/lane、tenant/project、priority、state、backendProfile、workspace/resource 引用、可选 `sessionRef` 和 version;携带 `sessionRef` 的 task dispatch 后必须把 `sessionPath` 写回 Queue 记录。 -- `agentrun_queue_attempts`:task attempt identity、runId、commandId、runnerJobId、sessionId、state、failureKind、retry index 和 timestamps。 +- `agentrun_queue_attempts`:以 `(task_id, attempt_id)` 为主键,保存 retry index/key、previous attempt、runId、commandId、runnerJobId、sessionId、state、failureKind、failureMessage 和 timestamps;`latest_attempt` 只保留 task 最新摘要。 - `agentrun_task_summaries` / `agentrun_attempt_summaries`:Queue 列表、详情和 commander 使用的轻量摘要;不能从 Core trace 反推 overview。 - `agentrun_queue_stats`:按 queue/lane/state/backendProfile 聚合的统计水位。 - `agentrun_queue_read_cursors`:按 user/agent/client 记录 Queue 已读水位。 @@ -63,6 +63,7 @@ Secret 名称和 key 可以在实现时按 Kubernetes 命名限制微调,但 - CI 可以校验 migration 顺序、checksum 和向前兼容,但不得把 live DB dump 写回 source。 - 启动时 `agentrun-mgr` 可以执行幂等 migration 或在 migration 缺失时 fail fast;不得静默以空 schema 继续服务。 - schema migration 记录必须写入 `agentrun_schema_migrations`。 +- `014_v02_queue_attempt_history_retry` 必须从既有 `agentrun_queue_tasks.latest_attempt` 回填首个正式 history row,并建立 `(task_id,idempotency_key)` retry identity、每 task 单一 `reserved/running` attempt 和 `(task_id,retry_index)` 唯一约束。 ## 测试规格 @@ -78,13 +79,17 @@ Secret 名称和 key 可以在实现时按 Kubernetes 命名限制微调,但 阅读本文和 [spec-v01-services.md](spec-v01-services.md),然后创建 run、command、event 和 terminal status,重启 `agentrun-mgr` 后确认 facts 仍可通过 manager API 查询。 +### T4 Queue retry 并发 + +使用隔离的真实 PostgreSQL,通过 `AGENTRUN_SELFTEST_DATABASE_URL= bun run self-test:postgres-queue-retry` 启动两个 store 实例,验证同 retry key 并发只创建一个 reservation 和一组稳定 identity、不同 key 命中 active attempt fence、`dryRun` 不写 attempt 或 task version。该入口禁止回退到 memory store。 + ## 规格的实现情况 | 规格项 | 状态 | 说明 | | --- | --- | --- | | Postgres durable store 规格 | 已定义 | 本文为 v0.1 存储权威。 | | StatefulSet/Service/PVC | 已实现/已通过主闭环 | `agentrun-v01-postgres` StatefulSet、Service 和 PVC 已由 GitOps runtime 提供,作为 `agentrun-v01` durable store。 | -| migration ledger | 已实现/已通过主闭环 | `agentrun-mgr` 启动 Postgres adapter 时幂等创建 `agentrun_schema_migrations` 并记录 migration id/checksum;当前最新 migration 为 `006_v01_session_control`,用于在不改写既有 migration checksum 的前提下新增 session projection/read cursor;readiness 必须显示 migration ready。 | -| manager Postgres adapter | 已实现/已通过主闭环 | `agentrun-mgr` 通过 `DATABASE_URL` 启用 Postgres adapter,持久化 runs、commands、events、runners、runner_jobs、sessions、session read cursors、backends、leases、Queue task 和 read cursor;缺少 `DATABASE_URL` 时 live runtime fail fast,memory 只允许显式 self-test/dev。 | +| migration ledger | 已实现/已通过主闭环 | `agentrun-mgr` 启动 Postgres adapter 时幂等创建 `agentrun_schema_migrations` 并记录 migration id/checksum;当前最新 migration 为 `014_v02_queue_attempt_history_retry`,新增正式 attempt history、回填和终态重试并发约束;readiness 必须显示 migration ready。 | +| manager Postgres adapter | 已实现/已通过主闭环 | `agentrun-mgr` 通过 `DATABASE_URL` 启用 Postgres adapter,持久化 runs、commands、events、runners、runner_jobs、sessions、session read cursors、backends、leases、Queue task、attempt history 和 read cursor;缺少 `DATABASE_URL` 时 live runtime fail fast,memory 只允许显式 self-test/dev。 | | health/readiness store 状态 | 已实现 | health/readiness 返回 adapter、reachable、migrationReady、migrationId、failureKind 和 redacted Secret 状态,不输出 DSN 明文。 | | file/sqlite durable store | 不采用 | 只可用于临时本地测试,不作为 v0.1 runtime truth。 | diff --git a/docs/reference/spec-v01-queue.md b/docs/reference/spec-v01-queue.md index 40e4600..a2287c8 100644 --- a/docs/reference/spec-v01-queue.md +++ b/docs/reference/spec-v01-queue.md @@ -36,6 +36,8 @@ POST /api/v1/queue/tasks/:taskId/cancel POST /api/v1/queue/tasks/:taskId/read POST /api/v1/queue/tasks/:taskId/dispatch POST /api/v1/queue/tasks/:taskId/refresh +GET /api/v1/queue/tasks/:taskId/attempts?cursor=&limit= +POST /api/v1/queue/tasks/:taskId/retry GET /api/v1/queue/stats?queue= GET /api/v1/queue/commander?queue= ``` @@ -86,6 +88,8 @@ AgentRun CLI 必须提供 Queue 和 Session 两组命令。Queue 命令只操作 ./scripts/agentrun queue cancel [--reason ] [--dry-run] [--full|--raw] ./scripts/agentrun queue dispatch [--json-stdin|--json-file ] [--dry-run] [--full|--raw] ./scripts/agentrun queue refresh [--dry-run] [--full|--raw] +./scripts/agentrun queue attempts [--cursor ] [--limit ] [--full|--raw] +./scripts/agentrun queue retry --idempotency-key --reason [--dry-run] [--full|--raw] ``` Session 命令负责输出、trace 和会话控制: @@ -100,7 +104,39 @@ Session 命令负责输出、trace 和会话控制: ./scripts/agentrun sessions read [--reader-id ] ``` -不得新增 `queue output`、`queue trace` 或 `queue session/*` 这类子路径代理。`queue list/show/commander` 默认输出低噪声 summary,最多打印 task/attempt/session ids、状态、统计、`sessionPath`、compact supervisor 和下一步 `sessions ...` 命令;supervisor 只允许披露 phase、last activity source seq/id、timeout budget 和恢复动作摘要,不得展开完整 payload、trace、tool command、stdout/stderr 或 runnerTrace。完整 payload/resource bundle/metadata 只能通过显式 `--full|--raw` 展开;trace/output 细节继续按 `sessionId` + `sourceSeq/eventId/itemId` 走 Session CLI 渐进披露。Queue mutation 命令带 `--dry-run` 时必须只返回 `mutation=false` 的计划,不得写 Queue、Core run/command 或 runner job。一次性 Queue task、dispatch body、run base 或 command payload 必须优先用 `--json-stdin` 接 quoted heredoc;禁止为了把 heredoc/stdin 内容交给 CLI 而先写临时 JSON dump 文件再传 `--json-file`。`--json-file` 只用于可复用、已受控的输入文件。 +不得新增 `queue output`、`queue trace` 或 `queue session/*` 这类子路径代理。 + +- `queue list/show/commander/attempts` 默认输出低噪声 summary,只打印 task/attempt/session ids、状态、失败分类、统计、`sessionPath`、compact supervisor 和下一步 `sessions ...` 命令。 + - supervisor 只允许披露 phase、last activity source seq/id、timeout budget 和恢复动作摘要。 + - 禁止默认展开完整 payload、trace、tool command、stdout/stderr 或 runnerTrace。 +- 完整 payload/resource bundle/metadata 只能通过显式 `--full|--raw` 展开。 + - trace/output 细节继续按 `sessionId` + `sourceSeq/eventId/itemId` 走 Session CLI 渐进披露。 +- Queue mutation 命令带 `--dry-run` 时必须只返回 `mutation=false` 的计划,不得写 Queue、Core run/command 或 runner job。 +- 一次性 Queue task、dispatch body、run base 或 command payload 必须优先用 `--json-stdin` 接 quoted heredoc。 + - 禁止为了把 heredoc/stdin 内容交给 CLI 而先写临时 JSON dump 文件再传 `--json-file`。 + - `--json-file` 只用于可复用、已受控的输入文件。 + +### 终态重试 + +`POST /api/v1/queue/tasks/:taskId/retry` 只接受以下请求体,不接受 task、dispatch 或 runtime patch: + +```json +{ + "idempotencyKey": "retry-20260712-01", + "reason": "依赖已恢复", + "dryRun": false +} +``` + +- 新 key 只允许重试 `failed` 或 `blocked` task;`completed`、`cancelled` 和正在运行的 task 必须拒绝。 +- 同一 task 的相同 key 必须先于当前状态检查返回原 attempt;相同 key 携带不同 reason 必须冲突。 +- `dryRun=true` 必须完成相同的合同、payload hash、状态和依赖校验,但不得创建 attempt、run、command、runner Job 或更新 task version。 +- 重试仍使用同一个 Queue task,创建新的正式 attempt 历史;`latestAttempt` 只保存最新摘要,不能替代 `agentrun_queue_attempts`。 +- attempt reservation 必须预留稳定的 attempt、run 和 runner Job identity;崩溃或并发重放只能续建同一组 Core 资源,不能产生重复 run、command 或 Job。 +- 启用 runner retention 时,Job 创建继续使用 namespace 级 fence 与容量回收 CAS 互斥;未启用 retention 时,必须改用 run 与 idempotency/attempt identity 的细粒度 fence,不得串行整个 namespace。 +- runner Job 物化成功前 task 必须保持原 `failed` 或 `blocked` 状态,reserved attempt 不得伪装为 running。 +- 物化失败必须在 reserved attempt 上持久化有界且脱敏的 `failureKind` 与 `failureMessage`;同 key 成功续建时清空该暂态错误。 +- 旧 terminal attempt、原 task 合同和 `payloadHash` 不可改写;禁止用自动 scheduler、backoff 或 judge 填充本次最小重试原语。 推荐 Queue task 提交形态: @@ -131,7 +167,7 @@ Queue task 的 `resourceBundleRef` 在 dispatch 时原样进入 Core run。若 Queue 首版新增或扩展的稳定表方向: - `agentrun_queue_tasks`:任务 identity、tenant/project、queue/lane、title、priority、state、backendProfile、workspace/resource 引用、可选 `sessionRef`、创建者、version 和 timestamps。 -- `agentrun_queue_attempts`:attempt identity、taskId、runId、commandId、runnerJobId、sessionId、state、failureKind、retry index 和 timestamps。 +- `agentrun_queue_attempts`:以 `(taskId, attemptId)` 为 identity,保存 retry key/index、前序 attempt、runId、commandId、runnerJobId、sessionId、state、failureKind、failureMessage 和 timestamps。 - `agentrun_task_summaries`:task 级摘要、当前状态、最新 attempt、最新 sessionPath、最后用户可见摘要和统计字段。 - `agentrun_attempt_summaries`:attempt 级摘要、terminalStatus、failureKind、runner identity、耗时和有界输出摘要引用。 - `agentrun_queue_stats`:按 queue/lane/state/backendProfile 聚合的轻量统计,可由 Queue 写入或按 Queue 表查询生成。 @@ -171,7 +207,7 @@ Queue 首版新增或扩展的稳定表方向: | Q2 | attempt 到 Core run/command/runner job 的真实闭环 | Queue submit 后通过受控 `queue dispatch` 产生 attempt,并创建真实 Core run/command/runner job;`queue refresh` 从 Core run/command 终态回写 Queue attempt;自动 Scheduler 仍 deferred。 | | Q3 | Session 引用边界 | `queue show` 返回 `sessionPath`,输出和 trace 只能通过 `sessions ...` 查询。 | | Q4 | summary/stats/read/commander | Queue overview、stats、read cursor、commander 全部直接查 Queue 模型。 | -| Q5 | retry/judge/cancel | retry/backoff、judge、cancel 与 attempt/session/core 状态一致。 | +| Q5 | retry/judge/cancel | 先提供终态 task 的显式 retry 与正式 attempt 历史;自动 backoff、scheduler 和 judge 继续 deferred。 | | Q6 | 冻结旧 UniDesk Code Queue 新任务入口 | 新任务只进入 AgentRun Queue;旧系统只归档或只读。 | ## 验收规格 @@ -183,7 +219,7 @@ Queue Q2 的真实手动验收必须覆盖以下稳定边界: - `queue submit` 只创建 Queue task,不触发自动 scheduler。 - `queue dispatch` 是受控手动调度入口,必须创建 Core run、command 和 runner job,并把 attempt 引用写回 Queue task。 - `queue refresh` 只读取 Queue task 保存的 run/command 引用,将 Core 终态回写到 Queue task 和 latestAttempt;不得读取 Core trace、Session trace 或 events 来反推 Queue stats/commander。 -- `queue submit/read/cancel/dispatch/refresh --dry-run` 必须只返回计划,不得改变 task state、read cursor、attempt、run、command 或 runner job。 +- `queue submit/read/cancel/dispatch/refresh/retry --dry-run` 必须只返回计划,不得改变 task state、read cursor、attempt、run、command 或 runner job。 - `queue show/list/stats/commander` 的统计口径必须来自 Queue 模型;默认输出必须有界,输出、trace 和会话控制继续由 Session API/CLI 承接。 - 综合联调里的 `workspaceRef` 必须是 runner 实际可访问且能启动 backend command 的工作区。`opaque` workspace 可用于不依赖 Git checkout 的最小 Queue dispatch 验收;`host-path` 只有在该 path 在 runner 容器/进程内可访问且不破坏 Codex command resolution 时才能作为通过证据。 - 因 workspace 形态导致的 backend command spawn 失败,应归类为 runtime workspace/command 一致性问题,不能误判为 Queue dispatch 或 Queue refresh 失败。 @@ -207,6 +243,7 @@ Queue Q2 的真实手动验收必须覆盖以下稳定边界: | Queue RESTful API | 已实现/Q1 | 已通过 `agentrun-mgr` 暴露 `submit/list/show/stats/read/cancel/commander`,使用短请求和 Queue version/cursor 轻量轮询;Q2 再接入 attempt 与真实执行。 | | Queue CLI | 已实现/Q1 | 已加入 `queue submit/list/show/stats/commander/read/cancel`;Queue 命令只返回 task summary、stats、read cursor 和 `sessionPath`。 | | Queue dispatch/refresh | 已实现/Q2 | `queue dispatch` 受控创建 Core run/command/runner job;`queue refresh` 从 Core run/command 终态回写 Queue task/latestAttempt;自动 Scheduler 仍 deferred。 | +| Queue terminal retry/attempt history | 已实现/Q5 最小切片 | `queue retry/attempts` 在同一 task 下提供幂等终态重试、正式 attempt 历史和失败物化可见性;自动 scheduler、backoff 与 judge 仍 deferred。 | | Session API/CLI | 已实现/Q3 | Queue 只返回 `sessionPath`;Session 层已承接 `ps/show/turn/steer/cancel/output/trace/read`,默认列表只显示 running/unread。 | | Scheduler 接入 | 待实现 | 旧 Code Queue scheduler 不保留;AgentRun Scheduler 是唯一调度方向。 | | OA/Event/integrations | 不采用 | 首版不做,后续如需外部 connector/sink 必须单独立规格。 |