From 5497f258844882508002acf60fc47277b88bf0f1 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 20 May 2026 15:45:58 +0000 Subject: [PATCH] feat(codex): default task query to review summary --- AGENTS.md | 2 +- docs/reference/cli.md | 4 +- docs/reference/code-queue-supervision.md | 6 +- scripts/src/code-queue.ts | 74 ++++++++++++++++++++++-- scripts/src/help.ts | 4 +- 5 files changed, 78 insertions(+), 12 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 32a0f2b3..756d9cff 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -47,7 +47,7 @@ UniDesk 是一个以主 server 为统一入口的分布式工作平台;本文 - `bun scripts/cli.ts ci install/status/run/publish-backend-core/publish-user-service/run-dev-e2e/logs`:在 D601 原生 k3s 上安装和运行 Tekton CI,支持每 commit 检查、Code Queue 只读性能门禁、`CI.json` catalog 驱动的 backend-core 与 user-service commit-pinned 镜像发布和手动触发的 `origin/master:deploy.json#environments.dev` 临时 namespace e2e;catalog/producer/consumer 分工见 `docs/reference/cicd-standardization.md`,`run-dev-e2e` 的 Git 控制 runner、短 launcher 和 no-CD 边界见 `docs/reference/dev-ci-runner.md`,Tekton 规则见 `docs/reference/ci.md`。 - `bun scripts/cli.ts codex deploy `:旧 Code Queue 兼容部署入口已禁用,原因是它会绕过受控部署边界直连 D601 部署 Code Queue;规则见 `docs/reference/codex-deploy.md`。 - `bun scripts/cli.ts codex submit [prompt] [--prompt-file path|--prompt-stdin] [--queue ]`:通过 backend-core 私有代理提交 Code Queue 任务;控制面默认走主 server `code-queue-mgr` 写入 PostgreSQL,`--dry-run` 可只检查请求体不入队,规则见 `docs/reference/cli.md`。 -- `bun scripts/cli.ts codex task `:按 Code Queue 任务 ID 查询初始 prompt、最后 assistant message、工具调用摘要、attempt/judge/error 和耗时,便于新任务引用历史 session。 +- `bun scripts/cli.ts codex task `:按 Code Queue 任务 ID 查询默认审阅摘要,只返回原始 prompt、最终 response、最后错误和渐进披露命令;需要工具调用、attempt/judge 和详细耗时时显式加 `--detail`。 - `bun scripts/cli.ts codex judge --attempt [--dry-run]`:按指定 task/attempt 用与队列 worker 相同的上下文构建和 MiniMax judge 调用路径单步复现完成判定;`--dry-run` 只输出 prompt/payload 诊断。 - `bun scripts/cli.ts codex steer [prompt|--prompt-file path|--prompt-stdin] [--dry-run]`:通过 Code Queue 私有代理向运行中的 active turn 注入纠偏提示,正式替代底层 `microservice proxy ... /steer` 调用。 - `bun scripts/cli.ts codex interrupt|cancel `:通过 Code Queue 私有代理中断运行任务或取消 queued/retry_wait 任务,规则见 `docs/reference/cli.md`。 diff --git a/docs/reference/cli.md b/docs/reference/cli.md index 487f3f28..eddd538f 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -40,9 +40,9 @@ CLI 可以从 `master` 快速演进,但必须兼容 `deploy.json` 固定的 CI - `schedule list|get|runs|run|retry-run|delete|upsert-pgdata-backup` 管理 backend-core 定时任务和运行历史。`schedule runs --limit N` 是全局历史视图,返回 `scope=global` 和 `scheduleId=null`;`schedule runs --limit N` 是指定 schedule 历史视图,返回 `scope=schedule` 和对应 `scheduleId`。CLI 必须拒绝 `schedule runs 50` 这类纯数字位置参数,并提示使用 `schedule runs --limit 50`,避免把空数组误判成“没有历史 run”。`schedule run --wait-ms N` 触发同一 schedule,并且即使 wait 超时也必须返回 `newRunId` 和 `observeCommand`;`schedule retry-run ` 只接受 failed run,从原 run 反查 `scheduleId` 后重触发同一 schedule,并输出 `originalRunId`、`scheduleId`、`newRunId` 和 `observeCommand`。 - `codex deploy ` 是旧 Code Queue 兼容部署入口,已禁用以防止维护通道直连 D601 部署 Code Queue;当前 dev 自动化只做 `ci run-dev-e2e` smoke,不提供 Code Queue CD,详细规则见 `docs/reference/codex-deploy.md`。 - `codex submit [prompt] [--prompt-file path|--prompt-stdin] [--queue queueId] [--provider-id id] [--cwd path] [--model model] [--reasoning-effort effort] [--execution-mode mode] [--max-attempts N] [--reference-task-id id] [--dry-run]` 通过 backend-core 私有代理向稳定 `code-queue` 用户服务路径提交任务;prompt 必须且只能来自位置参数、文件或 stdin 之一,`--dry-run` 只返回结构化请求且不实际入队。提交确认和 dry-run 必须返回完整 prompt、字符数和 `truncated=false`,不能套用任务详情的预览截断策略,否则长任务 prompt 无法被人工验收。真实提交会经过本机本地串行化保护和短节流,避免同一指挥端并发 submit 把低内存主机或 `code-queue-mgr` 控制面打抖;返回值会附带 `submitConcurrencyGuard` 说明本次提交的锁与等待信息。backend-core 默认把提交、队列 CRUD、已读状态、历史摘要和轻量 Trace 读取分流到主 server `code-queue-mgr`,由它写入主 PostgreSQL;D601 scheduler 只轮询并执行已入库任务。 -- `codex task ` 通过 Code Queue 私有代理按任务 ID 查询结构化执行摘要;默认只返回有界 prompt/response 预览、执行 Provider、工作目录、最后 assistant message、最近工具调用摘要、attempt、judge、错误、耗时和 trace 翻页提示,适合在新队列任务中引用历史 session 且避免噪声爆炸。该摘要读取默认由主 server `code-queue-mgr` 从 PostgreSQL 返回,不依赖 D601 `code-queue-read` Service 可用。 +- `codex task ` 通过 Code Queue 私有代理按任务 ID 查询结构化审阅摘要;默认只返回任务身份、执行 Provider、工作目录、attempt 计数、原始 prompt、最终 response、最后错误和渐进披露命令,适合指挥官审阅完成未读任务且避免上下文爆炸。需要旧式详细摘要时显式加 `--detail`;需要完整 prompt/response 文本时加 `--full`;需要工具调用、judge、attempt 全量摘要时使用 `--detail --full --tool-limit N`。该摘要读取默认由主 server `code-queue-mgr` 从 PostgreSQL 返回,不依赖 D601 `code-queue-read` Service 可用。 - `codex tasks [--view supervisor|full] [--queue id] [--status succeeded|running|queued|failed|canceled|judging|retry_wait[,..]] [--unread|--unread-only] [--limit N] [--before-id id]` 通过同一私有代理输出渐进式披露视图。默认 `supervisor` 只返回 `running`、`completedUnread`、`recentCompleted`、`queued` 和 `executionDiagnostics` 摘要,不嵌入完整 Trace、final response 或全量 overview;每个条目都带 `commands.show`、`commands.trace`、`commands.output`、`commands.read` 和 `commands.full`。`--unread` 是 `--unread-only` 的别名,必须只保留未读终态;`--status` 必须真实过滤支持的状态,未知参数或未知状态必须结构化失败,不能静默忽略。需要完整当前页任务简表时显式使用 `--view full` 或 `--full`,仍受 `--limit` 和 `--before-id` 分页约束。 -- `codex task --trace --tail|--from-start|--after-seq N|--before-seq N --limit N` 按页拉取 Code Queue 的逻辑 trace;响应会返回 `nextAfterSeq`、`previousBeforeSeq`、`hasMore`、`hasBefore` 和下一页/上一页命令,默认 `--trace` 取最新一页,需要完整 prompt/最后 response 时加 `--full`。 +- `codex task --trace --tail|--from-start|--after-seq N|--before-seq N --limit N` 按页拉取 Code Queue 的逻辑 trace;响应会返回 `nextAfterSeq`、`previousBeforeSeq`、`hasMore`、`hasBefore` 和下一页/上一页命令,默认 `--trace` 取最新一页,且仍以分页 trace 为主;需要完整 prompt/最终 response 时加 `--full`,需要详细 task 摘要时加 `--detail`。 - `codex output --tail|--from-start|--after-seq N|--before-seq N --limit N [--full-text]` 按原始 output seq 分页读取底层记录;当 trace 行提示 `commandOmittedLines`、`bodyOmittedLines` 或 `rawSeqs` 时,用该命令按 seq 补取完整信息,默认仍有单条文本预览上限,显式 `--full-text` 才返回该页全文。 - `codex read ` 在人工审阅后标记单个终态任务已读;列表、overview 和 supervisor 视图只返回这个命令字段,不得自动执行,也不得批量清空未读状态。 - `codex dev-ready` 查询 Code Queue `/api/dev-ready` 并返回有界 readiness 摘要,包括工具、Docker、Codex config、SSH 和 `devReady.skills`。`devReady.skills` 只暴露 `UNIDESK_SKILLS_PATH`、是否存在、是否只读、skillCount、`cli-spec` 是否可见和修复建议,不输出宿主 auth/token 文件内容。 diff --git a/docs/reference/code-queue-supervision.md b/docs/reference/code-queue-supervision.md index f1c5662c..d24a1f54 100644 --- a/docs/reference/code-queue-supervision.md +++ b/docs/reference/code-queue-supervision.md @@ -132,12 +132,14 @@ bun scripts/code-queue-pr-preflight-example.ts --repo pikasTech/unidesk --base m - `bun scripts/cli.ts codex queues`:查看低噪声队列计数、active task id、完成未读队列、runnable 队列和控制面诊断;只有需要完整队列行时才加 `--full`。 - `bun scripts/cli.ts codex tasks --unread --limit N`:查看完成未读审阅积压;`--unread` 与 `--unread-only` 等价,不能被静默忽略。 - `bun scripts/cli.ts codex tasks --status succeeded --unread --limit N`:按具体终态过滤监督结果;不支持的 status filter 必须显式失败,不能扩大为未过滤结果。 -- `bun scripts/cli.ts codex task `:查看 attempt、最后 assistant message、最后错误、cancel flag 和当前状态。 -- 当摘要不足时,再使用 `bun scripts/cli.ts codex task --trace --limit N` 或 `codex output`。 +- `bun scripts/cli.ts codex task `:默认只查看原始 prompt、最终 response、最后错误和 drill-down 命令,这是完成未读任务审阅的第一步。 +- 当默认审阅摘要不足时,再逐级使用 `bun scripts/cli.ts codex task --detail`、`bun scripts/cli.ts codex task --trace --limit N` 或 `codex output`。 - 当 master 控制面状态和 D601 scheduler 状态看起来分裂时,使用 `docs/reference/observability.md` 中的活性规则判断。 默认 supervisor 视图必须保持低噪声。每个任务应带 `commands.show`、`commands.trace`、`commands.output`、`commands.full` 和 `commands.read`,让下一步渐进披露动作明确;默认不得嵌入完整 queue 列表、完整 final response、raw output 页或完整 trace 行。`commands.read` 只是在人工审阅后的建议命令,listing 命令绝不能自动执行。 +完成未读任务的审阅也必须遵循渐进披露。指挥官默认只拉取原始 prompt 和最终 response,用它判断任务是否声称完成、是否有明显越界、是否缺少验收证据;不要默认拉完整 trace、全量 tool summary 或 raw output。只有当 final response 与目标不一致、证据不足、远端 commit 无法验证、任务疑似造假、或需要追溯失败原因时,才继续展开 `--detail`、分页 `--trace`、或按 seq 读取 `codex output`。这条规则的目标是降低上下文压力,同时保留通过多步查询拿到完整证据的能力。 + 队列诊断中的 `split-brain` 表示控制面/执行面观测分裂,不自动证明任务已经死亡。如果任务 heartbeat 新鲜且 trace 仍在推进,应把任务视为 live,继续监督,而不是 interrupt 或替换。队列摘要应显示 `effectiveLiveness=live`、`splitBrainLive=true` 和 `recommendedAction=continue-supervision`;如果 heartbeat expired/missing 或满足 stale-recovery 条件,应显示 `effectiveLiveness=at-risk`。 单次 `provider is not online`、SSH 超时、proxy 超时或 registry 请求失败只能证明“当前观察路径失败”,不能单独升级为 D601 全局离线、CI/CD 全局阻塞或业务任务不可推进。指挥官和 runner 必须用多信号裁决运行面状态,至少区分以下观察面: diff --git a/scripts/src/code-queue.ts b/scripts/src/code-queue.ts index 6d1b0994..f93fff73 100644 --- a/scripts/src/code-queue.ts +++ b/scripts/src/code-queue.ts @@ -17,6 +17,7 @@ const submitLockStaleMs = 120_000; const submitThrottleMs = nonNegativeIntegerEnv("UNIDESK_CODEX_SUBMIT_THROTTLE_MS", 2000); interface CodexTaskOptions { + detail: boolean; trace: boolean; traceLimit: number; traceMode: "tail" | "after" | "before"; @@ -117,6 +118,7 @@ interface CodexTasksEntry { steer: string; read: string; full: string; + detail: string; }; } @@ -493,6 +495,19 @@ function compactLastAssistant(value: unknown, full: boolean): Record { + const record = compactLastAssistant(value, full); + return { + at: record.at, + seq: record.seq, + source: record.source, + text: record.text, + chars: record.chars, + truncated: record.truncated, + omittedChars: record.omittedChars, + }; +} + function compactQueuedReason(value: unknown): Record | null { const record = asRecord(value); if (record === null) return null; @@ -684,7 +699,53 @@ function compactSummary(summary: unknown, options: CodexTaskOptions, taskId: str nextPageTemplate: `bun scripts/cli.ts codex task ${taskId} --trace --after-seq --limit ${defaultTraceLimit}`, previousPageTemplate: `bun scripts/cli.ts codex task ${taskId} --trace --before-seq --limit ${defaultTraceLimit}`, rawOutputTemplate: `bun scripts/cli.ts codex output ${taskId} --after-seq --limit ${defaultOutputLimit}`, - fullTextSummary: `bun scripts/cli.ts codex task ${taskId} --full --tool-limit ${Math.max(options.toolLimit, defaultToolLimit)}`, + fullTextSummary: `bun scripts/cli.ts codex task ${taskId} --detail --full --tool-limit ${Math.max(options.toolLimit, defaultToolLimit)}`, + }, + }; +} + +function compactReviewSummary(summary: unknown, options: CodexTaskOptions, taskId: string): Record { + const record = asRecord(summary) ?? {}; + const initialPrompt = asString(record.basePrompt || record.initialPrompt || record.prompt); + const transcriptCount = asNumber(record.transcriptCount, 0); + return { + id: record.id ?? taskId, + queueId: record.queueId ?? null, + status: record.status ?? null, + providerId: record.providerId ?? null, + model: record.model ?? null, + agentPort: record.agentPort ?? null, + agentPortInfo: record.agentPortInfo ?? null, + cwd: record.cwd ?? null, + attempts: { + currentAttempt: record.currentAttempt ?? null, + maxAttempts: record.maxAttempts ?? null, + currentMode: record.currentMode ?? null, + }, + timing: record.timing ?? null, + createdAt: record.createdAt ?? null, + startedAt: record.startedAt ?? null, + updatedAt: record.updatedAt ?? null, + finishedAt: record.finishedAt ?? null, + originalPrompt: textView(initialPrompt, options.full, 3000), + finalResponse: compactFinalResponse(record.lastAssistantMessage, options.full), + lastError: record.lastError ?? null, + counts: { + transcript: record.transcriptCount ?? null, + output: record.outputCount ?? null, + events: record.eventCount ?? null, + }, + disclosure: { + mode: "review", + defaultScope: "original prompt and final response only; use detail/trace/output commands for progressive disclosure", + fullPromptAndResponse: `bun scripts/cli.ts codex task ${taskId} --full`, + detail: `bun scripts/cli.ts codex task ${taskId} --detail`, + fullDetail: `bun scripts/cli.ts codex task ${taskId} --detail --full --tool-limit ${Math.max(options.toolLimit, defaultToolLimit)}`, + traceTail: `bun scripts/cli.ts codex task ${taskId} --trace --tail --limit ${defaultTraceLimit}`, + outputTail: `bun scripts/cli.ts codex output ${taskId} --tail --limit ${defaultOutputLimit}`, + rawOutputTemplate: `bun scripts/cli.ts codex output ${taskId} --after-seq --limit ${defaultOutputLimit}`, + transcriptTotal: transcriptCount, + transcriptMaxSeq: transcriptCount > 0 ? record.transcriptMaxSeq ?? null : null, }, }; } @@ -853,7 +914,7 @@ function compactTracePage(body: Record, taskId: string, limit: function parseTaskOptions(args: string[]): CodexTaskOptions { assertKnownOptions(args, { - flags: ["--trace", "--tail", "--from-start", "--first", "--full", "--raw-summary"], + flags: ["--detail", "--trace", "--tail", "--from-start", "--first", "--full", "--raw-summary"], valueOptions: ["--before-seq", "--beforeSeq", "--after-seq", "--afterSeq", "--trace-limit", "--limit", "--tool-limit"], }, "codex task"); const beforeSeq = nullablePositiveNumberOption(args, ["--before-seq", "--beforeSeq"]); @@ -861,7 +922,9 @@ function parseTaskOptions(args: string[]): CodexTaskOptions { const fromStart = hasFlag(args, "--from-start") || hasFlag(args, "--first"); const trace = hasFlag(args, "--trace") || beforeSeq !== null || args.some((arg) => arg === "--after-seq" || arg === "--afterSeq") || fromStart || hasFlag(args, "--tail"); const traceMode = beforeSeq !== null ? "before" : fromStart || args.some((arg) => arg === "--after-seq" || arg === "--afterSeq") ? "after" : "tail"; + const rawSummary = hasFlag(args, "--raw-summary"); return { + detail: hasFlag(args, "--detail") || rawSummary, trace, traceLimit: positiveIntegerOption(args, ["--trace-limit", "--limit"], defaultTraceLimit, maxTraceLimit), traceMode, @@ -869,7 +932,7 @@ function parseTaskOptions(args: string[]): CodexTaskOptions { beforeSeq, toolLimit: positiveIntegerOption(args, ["--tool-limit"], defaultToolLimit, 500), full: hasFlag(args, "--full") || hasFlag(args, "--raw-summary"), - rawSummary: hasFlag(args, "--raw-summary"), + rawSummary, }; } @@ -963,7 +1026,7 @@ function codexTaskSummary(taskId: string, options: CodexTaskOptions, fetcher: Co const summary = summaryResponse.body.summary; const result: Record = { upstream: summaryResponse.upstream, - summary: compactSummary(summary, options, taskId), + summary: options.detail ? compactSummary(summary, options, taskId) : compactReviewSummary(summary, options, taskId), }; if (options.rawSummary) result.rawSummary = summary; if (options.trace) { @@ -1124,6 +1187,7 @@ function taskWatchEntry(task: Record, summary: Record = { upstream: summaryResponse.upstream, - summary: compactSummary(summary, options, taskId), + summary: options.detail ? compactSummary(summary, options, taskId) : compactReviewSummary(summary, options, taskId), }; if (options.rawSummary) result.rawSummary = summary; if (options.trace) { diff --git a/scripts/src/help.ts b/scripts/src/help.ts index 4840a454..76724c31 100644 --- a/scripts/src/help.ts +++ b/scripts/src/help.ts @@ -49,7 +49,7 @@ export function rootHelp(): unknown { { command: "schedule upsert-pgdata-backup [--time HH:MM] [--remote-base /SERVER_DATA/UNIDESK_PG_DATA]", description: "Create or update the daily PGDATA physical backup task that uploads monthly rotated archives to Baidu Netdisk." }, { command: "codex deploy [--provider-id D601] [--timeout-ms N]", description: "Disabled legacy Code Queue deploy path; use the dev-only artifact consumer instead." }, { command: "codex submit [prompt] [--prompt-file path|--prompt-stdin] [--queue queueId] [--provider-id id] [--cwd path] [--model model] [--execution-mode mode] [--max-attempts N] [--reference-task-id id] [--dry-run]", description: "Submit a Code Queue task through backend-core -> code-queue proxy; --dry-run shows the structured request without enqueueing." }, - { command: "codex task [--trace --tail|--from-start|--after-seq N|--before-seq N --limit N] [--full]", description: "Fetch a compact Code Queue task summary; trace rows are opt-in and paged with next/previous commands to avoid output explosion." }, + { command: "codex task [--detail] [--trace --tail|--from-start|--after-seq N|--before-seq N --limit N] [--full]", description: "Fetch the bounded review view by default: original prompt, final response, and drill-down commands; detail and trace are opt-in." }, { command: "codex tasks [--view supervisor|full] [--queue id] [--status status[,status]] [--unread|--unread-only] [--limit N] [--before-id id]", description: "Show the bounded supervisor view by default: running, unread terminal, recent completed, queued, diagnostics, and drill-down commands." }, { command: "codex output [--tail|--from-start|--after-seq N|--before-seq N --limit N] [--full-text]", description: "Fetch paged raw Code Queue output records by seq when a trace row has omitted command/output text." }, { command: "codex read ", description: "Mark one reviewed terminal task read; never run automatically as part of listing." }, @@ -209,7 +209,7 @@ function codexHelp(): unknown { usage: [ "bun scripts/cli.ts codex deploy # disabled legacy deployment entry", "bun scripts/cli.ts codex submit [prompt] [--prompt-file path|--prompt-stdin] [--queue id] [--dry-run]", - "bun scripts/cli.ts codex task [--trace --tail|--from-start|--after-seq N|--before-seq N --limit N] [--full]", + "bun scripts/cli.ts codex task [--detail] [--trace --tail|--from-start|--after-seq N|--before-seq N --limit N] [--full]", "bun scripts/cli.ts codex tasks [--view supervisor|full] [--queue id] [--status succeeded,running] [--unread|--unread-only] [--limit N] [--before-id id]", "bun scripts/cli.ts codex output [--tail|--from-start|--after-seq N|--before-seq N --limit N] [--full-text]", "bun scripts/cli.ts codex read ",