first commit

This commit is contained in:
魏天炜
2026-11-12 15:29:12 +08:00
commit 5dabea54ab
93 changed files with 12170 additions and 0 deletions

View File

@@ -0,0 +1,39 @@
# 异步 Agent Loop 的产品时间线
异步提问让 Agent 发出 `question` 后继续做不依赖答案的工作。Agent 走到需要答案的步骤时可以等待,收到答案再推进。**2026 年 9 月已有明确的 API 和 Codex CLI 发布记录。** 两者的回传协议不同,Responses API 的原生异步函数通过原 `call_id` 回传工具结果,Codex CLI 的提问工具先返回 `accepted`,实际答复随后作为带问题 ID 的用户输入进入会话。表内 PR 合并时间以北京时间计,厂商发布日志保留页面日期。 [Responses API 回传示例](https://developers.openai.com/api/docs/guides/async-tool-calling#return-the-users-answer)、[Codex CLI 请求快照](https://github.com/openai/codex/blob/rust-v0.167.1/codex-rs/core/tests/suite/snapshots/all__suite__scenarios__astra_async_question_and_answer.snap#L38-L50)
## 异步提问
- **2026-09-03**,OpenAI Responses API 为 GPT-6 Astra 发布异步工具调用。开发者可把自己的提问工具声明为 `async: true`,由应用显示问题、保存待回答状态并送回结果。 [API 发布记录](https://developers.openai.com/api/docs/changelog?mw_entry=2026-09-03-3f56515da8b13ccc)、[异步提问示例](https://developers.openai.com/api/docs/guides/async-tool-calling#add-a-tool-to-ask-the-user-for-input)
- **2026-09-03**,Codex CLI 0.153.0 的发布记录列出 `request_user_input_async`,由模型目录启用。**2026-09-09**,CLI 0.154.0 的终端界面支持边工作边收取选项或自由文本回答。 [Codex CLI 0.153.0](https://learn.chatgpt.com/docs/changelog?date=2026-09-03#:~:text=Structured%20asynchronous%20questions)、[Codex CLI 0.154.0](https://learn.chatgpt.com/docs/changelog?date=2026-09-09#:~:text=Answer%20questions%20inline)
- **OpenCode** 的内置 `question` 依照当前文档会暂停执行,等用户填写表单后返回答案。11 月的两条 PR 分别涉及后台 Shell 和 ACP 客户端发送新指令。 [OpenCode `question` 文档](https://opencode.ai/docs/tools/#question)、[OpenCode `question` 实现](https://github.com/anomalyco/opencode/blob/b451fe3952b649881d13e9c3534edb61c2767b8e/packages/core/src/tool/plugin/question.ts#L62-L108)
## Steer、Queue 和后台执行
Steer 把新的用户输入送给当前运行,Queue 把新输入留给下一轮。2025 年夏秋的发布记录已经能看到这些交互和后台命令。Codex CLI 的异步答复也可走 Steer,答复内的问题 ID 保留了和原问题的关联。上游场景测试覆盖了在当前轮处理这类答复。 [Codex Steer 和 Queue](https://learn.chatgpt.com/docs/prompting#steering-and-queuing)、[Codex CLI 场景测试](https://github.com/openai/codex/blob/rust-v0.167.1/codex-rs/core/tests/suite/scenarios.rs#L893-L910)
## Cursor 和 Claude Code
| 时间 | 产品 | 已公开的能力 |
| --- | --- | --- |
| 2025 年 5 月至 6 月 | Cursor 0.50、1.0 | Background Agent 从预览到 GA。整只 Agent 在独立远端环境执行,可并行派活、查看和跟进。 [0.50](https://cursor.com/changelog/0-50)、[1.0](https://cursor.com/changelog/1-0) |
| 2025-07-03 | Cursor 1.2 | 可在 Agent 工作期间提交追问,当前任务结束后按队列执行。 [Queued messages](https://cursor.com/changelog/1-2#queued-messages) |
| 2025-08-06 | Cursor 1.4 | 区分 Queue、Steer、Interrupt。Steer 通常在一次工具调用之后生效。 [More Agent steerability](https://cursor.com/changelog/1-4#more-agent-steerability) |
| 2025 年 8 月 | Claude Code 1.0.71 | `Ctrl+B` 把 Bash 命令移到后台,Claude 可以继续工作。 [Claude Code 1.0.71](https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md#1071) |
| 2025-10-15 | Claude Code 2.0.19 | 长时间运行的 Bash 命令在达到前台超时后自动转后台,保留原进程。 [Claude Code 2.0.19](https://code.claude.com/docs/en/changelog#:~:text=Auto-background%20long-running%20bash%20commands) |
| 2026-08-19 | Cursor | 发布说明强调运行中的追问在工具边界进入,避免切断当时的动作。 [Steering improvements](https://cursor.com/changelog/08-19-26#steering-improvements) |
| 2026-09-23 | Claude Code 2.1.281 | Send now 改为先把运行中的工具移到后台,再处理新输入。 [Claude Code 2.1.281](https://code.claude.com/docs/en/changelog#:~:text=Changed%20send%20now) |
## OpenCode
- **2026-05-15**,PR #27084 合入实验性后台子 Agent。父会话可拿到后台子 Agent 的结果。 [OpenCode #27084](https://github.com/anomalyco/opencode/pull/27084)
- **2026-06-30 至 07-13**,V2 的通用 Job 服务将结果通知交给各工具。7 月初的 PR 已验证用 `Ctrl+B` 将运行中的 shell 放到后台。7 月 13 日的 TUI 修复描述了已有完成通知经持久化 inbox 唤醒原会话的路径。10 月公开的 OpenCode 2.0 介绍也展示了后台 shell、继续发消息和结果回报。 [OpenCode #34559](https://github.com/anomalyco/opencode/pull/34559)、[OpenCode #35320](https://github.com/anomalyco/opencode/pull/35320)、[OpenCode #36534](https://github.com/anomalyco/opencode/pull/36534)、[OpenCode 2.0 Background Tasks](https://anoma.ly/notes/opencode-2-0/#background-tasks)
- **2026-11-09 13:32**,PR #54394 把已有的同会话 steering 接到 ACP 临时扩展 `_session/steering`。运行中的 Loop 在下一步读取消息。空闲时接口提示客户端发普通 prompt。 [OpenCode #54394](https://github.com/anomalyco/opencode/pull/54394)
- **2026-11-11 00:31**,PR #63024 合入 `dev`。开启 `shell_timeout_background` 时,shell 超过默认 120 秒前台等待预算后自动把同一进程转到后台,完成后复用已有通知路径。合并时本地和开发构建默认开启,发行构建默认关闭。 [OpenCode #63024](https://github.com/anomalyco/opencode/pull/63024)
## Codex
- **2025-09-11**,Codex CLI #3288 合入实验性的 PTY 执行工具。会话 ID 可供后续读取或交互,建立了长命令可跨工具调用存活的基础。 [Codex #3288](https://github.com/openai/codex/pull/3288)
- **2026-01-13**,Codex CLI #9077 合入运行中默认发送消息,Tab 用于排队。**2026-02-05**,Codex 桌面版 26.205 发布记录明确列出 mid-turn steering。 [Codex #9077](https://github.com/openai/codex/pull/9077)、[Codex app 26.205](https://learn.chatgpt.com/docs/changelog?date=2026-02-05&index=0)
- **2026-09-29**,CLI 0.159.0 增加可选的 `instant_interrupt`,让新输入可以在模型响应或长时间 Code Mode 调用期间导入。**2026-10-15**,CLI 0.163.0 的发布记录列出响应期间的即时 steering。 [Codex CLI 0.159.0](https://learn.chatgpt.com/docs/changelog?date=2026-09-29)、[Codex CLI 0.163.0](https://learn.chatgpt.com/docs/changelog?date=2026-10-15)
- App Server 文档列有 `turn/steer` 和后台终端相关接口。CLI 0.167.1 的 `exec_command` 在等待预算耗尽时可返回 process ID,退出监听器把完成事件发回原 turn。桌面版是否在普通命令结束后自动开启一次模型续跑仍待实测。T3 Code 的适配器会对符合条件的后台命令另行提交续跑通知。 [Codex App Server](https://learn.chatgpt.com/docs/app-server#api-overview)、[返回 process ID](https://github.com/openai/codex/blob/rust-v0.167.1/codex-rs/core/src/unified_exec/process_manager.rs#L651-L667)、[退出事件](https://github.com/openai/codex/blob/rust-v0.167.1/codex-rs/core/src/unified_exec/async_watcher.rs#L327-L379)、[T3 Code 的完成处理](https://github.com/pingdotgg/t3code/blob/a536ff7ac0c080190f098965d0a0d244caf5b211/apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.ts#L5179-L5238)

View File

@@ -0,0 +1,35 @@
# 异步 Agent Loop 是怎么调度的
DeepSeek 的设计文章在第 4.1 节把长工具调用拆成启动和完成两次交互。启动先返回「已启动」通知,工具继续运行。Agent Loop 可以在当前推理步结束后处理新输入,执行器在工具结束后把结果送回原会话。本文核对了文章中文镜像、DeepSeek Harness `fcc0ad4` 和公开原型 `6337fc8` 的源码、文档与上游测试,时序数字为假设值。 [设计文章 §4.1](https://telegra.ph/Super-agent-%E8%AE%BE%E8%AE%A1%E6%8E%A2%E7%B4%A2%E8%BF%88%E5%90%91%E6%9B%B4%E8%87%AA%E4%B8%BB%E7%9A%84-Agent-%E7%B3%BB%E7%BB%9F-10-31-2#:~:text=4.1%20%E5%85%A8%E5%8F%8C%E5%B7%A5%E4%BA%A4%E4%BA%92)
## 一个会话里发生了什么
在 DeepSeek Harness 的术语里,一次模型请求和它调用的工具组成一个 step,一个 turn 可以包含多个 step。Loop 在 step 边界取出可处理的输入,组装下一次模型请求。同步执行长命令时,当前 step 要等命令的最终结果。命令实现即使用了 JavaScript 的 `async/await`,同一会话仍在等这个 step 结束。异步工具则把工作交给后台执行器,返回 `job_id`,让当前 step 可以结束。此后用户消息和后台完成通知都可以成为模型的输入,后台任务的进度独立推进。 [Turn 与 Step](https://github.com/deepseek-ai/deepseek-harness/blob/fcc0ad462172522aaf5c93a7b2e01f6b9f0b0159/docs/architecture.md#L81-L112)、[Bash 工具的两个分支](https://github.com/deepseek-ai/deepseek-harness/blob/fcc0ad462172522aaf5c93a7b2e01f6b9f0b0159/packages/shell/tool-bash/src/index.ts#L498-L530)
公开原型的 Worker 会在前台 shell 命令等待超过 5 秒时把命令交给后台。Harness 也支持直接使用 `run_in_background`,任务获准后先返回 ID,启动失败可以随后以失败结果结算。完成通知会进入正在运行的 Agent 的下一步,或者在开启唤醒投递时让空闲 Agent 发起后续一轮。短输出可以随通知一起返回,长输出留给 `job_output` 读取。 [原型的 Worker 调度](https://github.com/deepseek-ai/dsh-superagent-prototype/blob/6337fc823ce20251c8de8085948165c81aaa701e/docs/003-execution.md#L23-L45)、[Bash 工具文档](https://github.com/deepseek-ai/deepseek-harness/blob/fcc0ad462172522aaf5c93a7b2e01f6b9f0b0159/packages/shell/tool-bash/README.md#L60-L62)、[完成通知的投递](https://github.com/deepseek-ai/deepseek-harness/blob/fcc0ad462172522aaf5c93a7b2e01f6b9f0b0159/packages/jobs/tool-jobs/src/index.ts#L355-L410)
如果后续工作确实依赖结果,Agent 可以调用 `job_output(wait: true)`。Harness 的这个等待可以被当前 step 的用户 steer 提前结束,返回仍在运行的状态,让新消息进入下一步,原命令继续运行。排给后续 turn 的消息会继续等待。上游测试分别覆盖这两条路径,此处核对了测试代码。 [等待与 steer 的实现](https://github.com/deepseek-ai/deepseek-harness/blob/fcc0ad462172522aaf5c93a7b2e01f6b9f0b0159/packages/jobs/tool-jobs/src/index.ts#L461-L515)、[上游测试](https://github.com/deepseek-ai/deepseek-harness/blob/fcc0ad462172522aaf5c93a7b2e01f6b9f0b0159/packages/jobs/tool-jobs/tests/steer-wait.spec.ts#L88-L150)
## 等一分钟的测试,谁省下了时间
假设修完过期判断后启动一组本地回归,耗时 60 秒。第 10 秒你问「把刚才的 diff 给我看一下」,这一步只读现有改动,假设模型处理和回答用 3 秒,异步版此时可以开始下一步。
| 从测试启动计时 | 同步调用 | 异步调度 |
| --- | --- | --- |
| 第 0 秒 | 当前 step 开始等待测试结果 | 后台任务开始,工具先返回 `job_id` |
| 第 10 秒 | 追问已发送,当前 step 仍在等测试 | Loop 开始处理追问 |
| 第 13 秒 | 测试仍在跑 | Agent 已回 diff,测试继续跑 |
| 第 60 秒 | 测试结束,Loop 可以处理追问 | 测试结束,完成通知交回原会话 |
| 第 63 秒 | Agent 回 diff | Agent 可以已经在汇报回归结果 |
在这个示意里,追问到回答从 53 秒变成 3 秒,测试本身两边都是 60 秒。若追问换成「测试通过了吗」,第 60 秒才有最终结果,前面只能回答当前状态。若等待期间还有独立工作,例如只读检查同一改动的边界条件,就可能把这段工作和回归重叠起来。若每一步都依赖前一步结果,或者工具本身很快,重叠空间就很小。结果自动投回会话还能让 Agent 在命令完成后自行继续,用户可以等汇报再回来。
并发带来的成本落在执行器和会话管理上。任务要有明确的归属、状态和取消方式,完成结果要对应启动它的任务。如果测试途中改了代码,已有结果应标明对应的版本,必要时重新验证。后台进程也会占用资源。Harness 的本地 job 服务提供并发限制,任务在所属 Agent 被释放或 Harness 关闭时结束。持久化与重启恢复需要额外机制。 [本地 Job 服务与生命周期](https://github.com/deepseek-ai/deepseek-harness/blob/fcc0ad462172522aaf5c93a7b2e01f6b9f0b0159/packages/jobs/jobs-local/README.md#L10-L23)
## 和 T3 Code 的关系
T3 的 Queue 表达「等后续一轮」,Steer 表达「交给当前一轮」。输入框接受了消息、Provider 收到了消息、模型把它纳入下一次请求,是三个不同时间点。Provider 决定当前工具会继续、等待还是被中断。T3 与文章直接对应的机制是后台完成事件,例如 Codex 适配器在符合条件的命令结束后提交通知,T3 服务把它送回原线程,当前轮忙时排在后面。开另一个会话可以并行做另一件事,而这个例子关注同一会话如何继续处理输入并接回测试结果。 [T3 的 Queue 与 Steer](https://github.com/pingdotgg/t3code/blob/a536ff7ac0c080190f098965d0a0d244caf5b211/docs/user/composer.md#L63-L80)、[Codex 后台结果](https://github.com/pingdotgg/t3code/blob/a536ff7ac0c080190f098965d0a0d244caf5b211/apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.ts#L5179-L5238)、[T3 同线程续跑](https://github.com/pingdotgg/t3code/blob/a536ff7ac0c080190f098965d0a0d244caf5b211/apps/server/src/orchestration-v2/ProviderContinuationService.ts#L182-L205)
## 周五的演示边界
两遍都跑同一个本地测试,输入同一个只读追问,分别展示同步等待与后台执行。模型用固定桩,测试命令真实运行。记录测试启动、追问到达、Loop 将追问交给模型桩、测试退出、结果进入会话的时间。让观众看见异步版在测试还运行时已经回答,以及结束后会话确实收到退出码。Demo 验证交互顺序,现场时长用于说明等待发生在哪里。

View File

@@ -0,0 +1,44 @@
# 异步工具调用的场景与运行机制
截至 2026-11-12,编码 Agent 里可核验的场景包括等人回答、跑长命令、派子 Agent、监听持续事件、等待远端工具和生成图片。常见收益是把等待和独立工作重叠、让用户继续交互,或让会话空闲到结果到达,减少模型主动查询进度。结果可以稍后交回同一会话,并在推进到依赖它的步骤时汇合。本文依据官方文档、源码和上游测试快照,未现场运行各产品。 [OpenAI 异步工具指南](https://developers.openai.com/api/docs/guides/async-tool-calling)、[OpenCode 工具文档](https://opencode.ai/docs/tools/)、[Claude Code Monitor](https://code.claude.com/docs/en/tools-reference#monitor-tool)
## 一个调用的生命周期
1. **发起。** 模型发出工具调用,运行时将它绑定到会话、调用 ID 和实际任务。有的工具调用保持待完成,有的工具先返回任务 ID 或收件回执,之后用独立的会话事件报告结果。 [OpenAI 异步工具指南](https://developers.openai.com/api/docs/guides/async-tool-calling)、[DeepSeek Bash 后台分支](https://github.com/deepseek-ai/deepseek-harness/blob/fcc0ad462172522aaf5c93a7b2e01f6b9f0b0159/packages/shell/tool-bash/src/index.ts#L498-L530)
2. **继续。** 执行器等待命令退出、远端结果或人回复。Agent 可以处理新的输入,或做当前目标下的独立工作。走到依赖该结果的步骤才等。OpenAI 指南示范用 `wait_for_tasks` 等一组所选任务,应用先按原调用 ID 交付各项结果,再返回等待工具的状态。DeepSeek Harness 的 `job_output(wait: true)` 可以被当前轮的 steer 提前结束,任务继续运行。 [OpenAI Wait Tool](https://developers.openai.com/api/docs/guides/async-tool-calling#add-a-wait-tool)、[DeepSeek 等待与 steer](https://github.com/deepseek-ai/deepseek-harness/blob/fcc0ad462172522aaf5c93a7b2e01f6b9f0b0159/packages/jobs/tool-jobs/src/index.ts#L461-L515)
3. **交付。** 执行器取得完成、失败或取消状态。结果可以来自进程退出、应用回调、轮询、订阅或用户回复。调用 ID 或任务 ID 负责归属,运行时决定何时让模型看到事件。DeepSeek Harness 可以在安全边界投递,也可按配置唤醒空闲 Agent。Codex 的后台 Hook 在活跃轮次将输出送入下一次模型请求,空闲时等用户的下一轮。 [DeepSeek 完成投递](https://github.com/deepseek-ai/deepseek-harness/blob/fcc0ad462172522aaf5c93a7b2e01f6b9f0b0159/packages/jobs/tool-jobs/src/index.ts#L355-L410)、[Codex 后台 Hook](https://learn.chatgpt.com/docs/hooks#run-hooks-in-the-background)
## 工具场景
| 场景 | 等待期间可以做什么 | 结果与产品证据 |
| --- | --- | --- |
| **向用户提问** | 问兼容范围时先读现有调用方、整理改动影响。得到回答后才选方案。 | Codex CLI 有异步提问能力。Responses API 指南示范先问报告受众,等待期间查资料。OpenCode 内置 `question` 会暂停执行,Claude Agent SDK 的 `AskUserQuestion` 由阻塞的 `canUseTool` 回调收集答案。 [Codex CLI 0.153.0](https://learn.chatgpt.com/docs/changelog?date=2026-09-03#:~:text=Structured%20asynchronous%20questions)、[OpenAI 异步提问示例](https://developers.openai.com/api/docs/guides/async-tool-calling#add-a-tool-to-ask-the-user-for-input)、[OpenCode Question](https://opencode.ai/docs/tools/#question)、[Claude SDK 用户输入](https://code.claude.com/docs/en/agent-sdk/user-input) |
| **Shell、构建、回归测试** | 测试运行时查看 diff、解释改动或阅读与构建独立的代码。等退出码和日志回来后判断是否通过。 | OpenCode 和 Claude Code 支持后台 shell。DeepSeek Harness 的 Bash 返回 `job_id`,完成通知可附短输出,长输出通过 `job_output` 取回。 [OpenCode Shell](https://opencode.ai/docs/tools/#shell)、[Claude Code 后台 Bash](https://code.claude.com/docs/en/interactive-mode#background-bash-commands)、[DeepSeek Bash 文档](https://github.com/deepseek-ai/deepseek-harness/blob/fcc0ad462172522aaf5c93a7b2e01f6b9f0b0159/packages/shell/tool-bash/README.md#L60-L62) |
| **子 Agent** | 主 Agent 实现改动,子 Agent 在独立上下文里只读审查测试边界。主 Agent 在汇总时再用结论。 | OpenCode `subagent` 的 `background: true` 立即返回,结束时通知父会话。Claude Code 支持后台子 Agent,需要权限时可把请求送到主会话。 [OpenCode Subagent](https://opencode.ai/docs/tools/#subagent)、[Claude Code 子 Agent](https://code.claude.com/docs/en/sub-agents#run-subagents-in-foreground-or-background) |
| **持续监听** | 持续看测试日志、开发服务或 WebSocket 上的新事件,Agent 平时可继续交互,只在相关事件到达时处理。 | Claude Code Monitor 在后台监听命令输出或 WebSocket,运行过程中可产生多次事件,有超时和取消。流式展示普通前台命令的日志也会看到新行,是否放行 Agent 的下一步取决于工具是否让出执行。 [Claude Code Monitor](https://code.claude.com/docs/en/tools-reference#monitor-tool) |
| **远端工具、回调** | 启动一个慢查询、远端校验或 CI,先整理本地证据。完成事件回来后汇合结论。 | MCP Tasks 扩展规定任务 ID、轮询或订阅、输入请求和终态结果。Claude Code 2.1.319 明确支持把 MCP 服务返回的 Task 放到后台,完成后告知 Claude。GitHub 提供 `workflow_run.completed` 事件,产品可据 run ID 关联原会话,关联与唤醒由应用实现。 [MCP Tasks 扩展](https://modelcontextprotocol.io/extensions/tasks/overview)、[Claude Code 2.1.319](https://code.claude.com/docs/en/changelog#:~:text=Added%20support%20for%20MCP%20tasks%20in%20the%20terminal)、[GitHub workflow_run](https://docs.github.com/en/webhooks/webhook-events-and-payloads#workflow_run) |
| **长耗时产物** | 图片生成或远端报表导出时先写文案、核对数据或解释内容。等产物 ID、路径或链接后再预览并交付。 | OpenCode 的实验性图片工具在后台运行,完成后回传保存路径。导出报表和转码属于同一调度模式的示例,具体工具需要自行提供启动、完成和失败语义。 [OpenCode Image Generate](https://opencode.ai/docs/tools/#image-generate) |
| **后台 Hook** | 一次会话事件触发额外的背景资料采集或检查,主操作先继续。 | Codex 支持在后台执行命令 Hook,并在下一次可用模型请求中交付信息。Hook 由生命周期事件触发。需要约束触发操作的审批、拒绝或重写仍走同步 Hook。 [Codex 后台 Hook](https://learn.chatgpt.com/docs/hooks#run-hooks-in-the-background) |
OpenCode 2.2.6 的无交互 `opencode run` 会等自己发起的后台 shell、子 Agent 和图片任务结算,允许模型处理结果后再退出。持续运行的开发服务或 watcher 因此可能一直占住这次 CLI run。后台执行解决的是会话里的等待方式,进程什么时候退出由 CLI 生命周期决定。 [OpenCode 2.2.6](https://opencode.ai/changelog/v2.2.6)
## 结果如何回到 Agent
**Codex CLI 0.167.1。** `request_user_input_async` 发出一个包含问题、与调用 ID 关联的 agent message,然后立即结算工具调用,返回 `{"accepted":true}`。这个回执表示已提交问题。TUI 把用户回答编码成带 `questionItemId` 的 `<send_user_message_question_reply>` 消息。会话仍在运行时,提交走 `turn/steer`。上游场景测试覆盖了这一路径,下一次模型请求的快照里,实际回答是一条 role 为 `user` 的消息,此时原工具调用已经结束。 [Codex 提问工具](https://github.com/openai/codex/blob/rust-v0.167.1/codex-rs/core/src/tools/handlers/request_user_input_async.rs#L131-L147)、[TUI 回答编码](https://github.com/openai/codex/blob/rust-v0.167.1/codex-rs/tui/src/bottom_pane/async_questions/state.rs#L126-L170)、[TUI 提交路径](https://github.com/openai/codex/blob/rust-v0.167.1/codex-rs/tui/src/app/user_turn_submission.rs#L27-L54)、[场景测试](https://github.com/openai/codex/blob/rust-v0.167.1/codex-rs/core/tests/suite/scenarios.rs#L893-L910)、[请求快照](https://github.com/openai/codex/blob/rust-v0.167.1/codex-rs/core/tests/suite/snapshots/all__suite__scenarios__astra_async_question_and_answer.snap#L38-L50)
**Responses API 原生异步工具。** 应用把自定义提问函数声明为 `async: true`。模型可以发出待完成的调用并继续,应用负责展示问题、收答和绑定原 `call_id`。答案作为稍后的 `function_call_output` 发回,续接最新的 `previous_response_id`。如已经发起显式等待,先回传原工具结果,再回传 wait 状态。这是一种可用的 API 协议,Codex CLI 采用上段所述的回执和用户消息。 [OpenAI 异步提问与结果回传](https://developers.openai.com/api/docs/guides/async-tool-calling#return-the-users-answer)
**DeepSeek Harness 的后台任务。** 它也用会话消息承载稍后才到的结果。完成通知由 `createUserMessage` 构造,来源标为 `tool-jobs`。Agent 忙时通过 `inject` 在下一步处理。启用了唤醒投递且预算允许时,空闲 Agent 通过 `followup` 继续。长输出可留在任务服务,模型收到通知后按任务 ID 读取。 [DeepSeek 结果投递](https://github.com/deepseek-ai/deepseek-harness/blob/fcc0ad462172522aaf5c93a7b2e01f6b9f0b0159/packages/jobs/tool-jobs/src/index.ts#L377-L410)
## 容易混用的交互
| 机制 | 等待或交付发生在哪里 |
| --- | --- |
| **同步工具** | 当前模型步骤等待结果。宿主可用 `await` 或异步 I/O 实现底层执行,会话仍受工具结果约束。 |
| **并行工具调用** | 同一步发出多项调用,例如并行读三个文件。应用可以并发执行并等待这一批,再发起下次模型推理。多项异步任务也可重叠执行,并让后续推理先做其他工作。具体组合受协议约束,例如 Responses API 的 Multi-agent 模式要求避免把异步工具和 parallel tool calls 混用。 [OpenAI 异步工具限制](https://developers.openai.com/api/docs/guides/async-tool-calling#compatibility) |
| **显式等待** | 模型在依赖处等待选定任务,其他后台任务仍可推进。Responses API 示例是应用定义的 `wait_for_tasks`,其他运行时可以提供阻塞等待、只读状态或完成通知。 |
| **Steer 与 Queue** | Steer 把新的用户输入送入当前轮。Queue 让新输入在后续轮次执行。问题答案有自己的关联 ID,即使实现上复用了用户消息通道。 |
| **确认和授权** | 例如用户确认发布前,草拟说明和核对差异可以继续,发布动作等明确结果。权限决策属于受控操作的前置条件,异步展示批准 UI 也要保留这条依赖。 |
| **后台运行整轮** | Responses API `background: true` 把整个 response 放到后台并给调用方状态查询,作用范围是 response。独立云 Agent、另开会话和后台子 Agent 各有自己的运行状态。子 Agent 如果通过工具调用启动并把结果交回父会话,也可以构成父会话的一次异步工具调用。 |
这些区别可用三个观察点核对。工具启动后模型能否推进,结果以什么 ID 和形态回到模型,空闲时是否自动恢复。协议可以支持其中一部分。例如 Claude Managed Agents 的自定义工具通过事件交回结果,普通单线程调用可以停在 `requires_action`,有其他工作流线程运行时会话整体可以仍是 `running`。单凭 HTTP 请求先返回或结果通过 webhook 送达,无法判断模型在等待期间的进度。 [Claude Managed Agents 会话事件](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#return-a-custom-tool-result)、[OpenAI Background Mode](https://developers.openai.com/api/docs/guides/background)、[Codex Steer 与 Queue](https://learn.chatgpt.com/docs/prompting#steering-and-queuing)、[Claude SDK 审批与输入](https://code.claude.com/docs/en/agent-sdk/user-input)

View File

@@ -0,0 +1,13 @@
# T3 Code 与异步 Agent Loop
T3 Code 的源码核对固定在 2026 年 11 月 11 日查询到的 `main` 提交 `a536ff7`。下面描述的是代码和文档中的行为,现场交互时序待实测。 [T3 Code 提交](https://github.com/pingdotgg/t3code/commit/a536ff7ac0c080190f098965d0a0d244caf5b211)
DeepSeek 设计文章第 4.1 节把耗时工具拆成启动和完成两次交互。启动先返回,Agent Loop 在当前推理步结束后可以处理新消息,后台任务结束时再把结果交回原会话。公开原型的 Worker 会把超过 5 秒的 shell 命令转到后台,并用完成结果唤醒 Worker。 [文章第 4.1 节](https://xitter.cf/DeepSeekHarness/article/2116857257245987236#:~:text=4.1%20Full%2DDuplex)、[原型执行文档](https://github.com/deepseek-ai/dsh-superagent-prototype/blob/6337fc823ce20251c8de8085948165c81aaa701e/docs/003-execution.md#the-executor)
T3 Code 把客户端线程接到 Codex、Claude Code 等现成运行时,由 T3 服务端管理消息与运行状态。忙时发送有两个选项。**Queue** 把消息保存在服务端,等后续 turn。**Steer** 把新消息送给当前 turn,对 Codex 会发 `turn/steer`,并带上目标 turn 的 ID。发送成功和模型何时处理属于两个时间点。 [项目定位](https://github.com/pingdotgg/t3code/blob/a536ff7ac0c080190f098965d0a0d244caf5b211/README.md#L1-L9)、[Queue 与 Steer](https://github.com/pingdotgg/t3code/blob/a536ff7ac0c080190f098965d0a0d244caf5b211/docs/user/composer.md#L63-L80)、[消息分发](https://github.com/pingdotgg/t3code/blob/a536ff7ac0c080190f098965d0a0d244caf5b211/apps/server/src/orchestration-v2/ThreadManagementService.ts#L844-L853)、[Codex 原生 steering](https://github.com/pingdotgg/t3code/blob/a536ff7ac0c080190f098965d0a0d244caf5b211/apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.ts#L7474-L7504)
**Claude 的实现说明了为什么同一个 Steer 按钮会有不同语义。** 适配器声明主动 steering 可能中断前台工具。在发送 `priority: "now"` 之前,它先尝试通过 SDK 把符合条件的前台子 Agent 移到后台,这一步有 5 秒预算。能否保留在途工作取决于 provider、工作类型和转入后台的结果。 [Claude 能力声明](https://github.com/pingdotgg/t3code/blob/a536ff7ac0c080190f098965d0a0d244caf5b211/apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts#L420-L429)、[后台迁移及消息投递](https://github.com/pingdotgg/t3code/blob/a536ff7ac0c080190f098965d0a0d244caf5b211/apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts#L11664-L11803)
**后台结果唤醒才是和原文最接近的一段。** 比如 Codex 某些后台命令在根 turn 已结束后完成,适配器会在满足状态和去重检查时,将退出状态和输出摘要作为 continuation 提交。T3 的服务把它变成同一线程的内部消息,走 `queue_after_active`。适配器也报告待完成的后台工作,让服务端延后回收看似空闲的 provider 会话。 [Codex 命令摘要](https://github.com/pingdotgg/t3code/blob/a536ff7ac0c080190f098965d0a0d244caf5b211/apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.ts#L446-L470)、[完成后请求 continuation](https://github.com/pingdotgg/t3code/blob/a536ff7ac0c080190f098965d0a0d244caf5b211/apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.ts#L5179-L5238)、[同线程投递](https://github.com/pingdotgg/t3code/blob/a536ff7ac0c080190f098965d0a0d244caf5b211/apps/server/src/orchestration-v2/ProviderContinuationService.ts#L182-L205)、[空闲回收](https://github.com/pingdotgg/t3code/blob/a536ff7ac0c080190f098965d0a0d244caf5b211/apps/server/src/orchestration-v2/ProviderSessionManager.ts#L1182-L1238)
周五可以用 T3 Code 的 Queue 和 Steer 开场,再用既定的本地测试演示把三件事落在时间线上。消息何时被接收、何时被模型处理、后台命令何时结束并交回结果。DeepSeek 讲的是 Loop 怎样让长工具让出执行机会,T3 Code 的代码展示了上层产品怎样接住不同 provider 提供的能力。