从入口开始——agent-run-dispatch.ts(283 行),消息进来后分发给 Agent 的第一站。

agent-run-dispatch.ts 是个调度包装层,核心是把 Gateway 请求转成 agentCommandFromGatewayIngress,然后处理成功/超时/错误三种结果。真正的执行逻辑在 agent-run-handler.ts

行号

你的记录

准确度

说明

L29-38

读取 agent 运行超时的参数

readAgentRunTimeoutAttribution — 从 meta 中提取 timeoutPhase 和 providerStarted

L40-42

网关中断的显示原因

⚠️

isGatewayAbortSignalReason — 更准确说是判断是否为网关中断信号(undefined / AbortError / TimeoutError),不是"显示"

L44-58

网关中断的拒绝原因

⚠️

isGatewayAgentAbortRejection — 返回 boolean,判断当前 error+signal 组合是否构成网关中断拒绝,不是"原因"是"判断"

L60-65

解析网关中断的原因

resolveGatewayAgentAbortStopReason — 返回 "restart" | "rpc" | "timeout" 三选一

L67-69

解析网关中断的任务状态

resolveAbortedAgentTaskStatus — "timeout" → "timed_out",其他 → "cancelled"

L71-75

解析网关中断的超时阶段

resolveGatewayAgentAbortTimeoutPhase — restart 时返回 "gateway_draining"

L77-79

解析网关中断的原因

⚠️

resolveAbortedAgentStopReason — 从 ChatAbortControllerEntry 解析,和 L60-65 不同(彼从 signal 解析,此从 entry 解析),两者容易混淆

L81-88

删除重复的网关实体

deleteGatewayDedupeEntries — 遍历 keys 删除 dedupe map 中的条目

L90-283

agent 从网关进入后的运行逻辑

dispatchAgentRunFromGateway — 核心函数,入口到出口的完整调度


 两个小纠正 + 补充理解

1. L40-42 vs L44-58:判断链,不是"原因"

这两个函数的关系是层层递进的:

isGatewayAbortSignalReason(reason)      ← "这是个普通的网关中断信号吗?"

    ↓

isGatewayAgentAbortRejection(error, signal)  ← "这是一次 agent 中断拒绝吗?"

    ↓  (更严格:除了检查 signal,还要检查 error)

resolveGatewayAgentAbortStopReason(signal)  ← "具体是什么原因?restart/timeout/rpc"

isGatewayAgentAbortRejection 的判断逻辑:

  1. signal 没 abort → 直接 false
  2. signal.reason 是 restart → true(重启中断必算)
  3. signal.reason 是 TimeoutError → true
  4. signal.reason 不是普通中断信号 → false(比如用户主动取消)
  5. 最后兜底:error 本身是 AbortError/TimeoutError → true

2. L77-79 和 L60-65 不是一回事

L60-65: resolveGatewayAgentAbortStopReason(signal)

         从 AbortSignal 解析 → "restart" | "rpc" | "timeout"

L77-79: resolveAbortedAgentStopReason(entry)

         从 ChatAbortControllerEntry 解析 → string (default "rpc")

前者在 .catch() 分支用(直接从 signal 拿),后者是导出函数,外部拿 entry 就能解析。你笔记里两处都写了"解析网关中断的原因",建议区分一下。


 L90-283 核心函数结构速览

dispatchAgentRunFromGateway 就是整个文件的主菜,193 行的异步调度逻辑:

1. L112-133: Task Tracking 初始化

   ├── shouldTrackTask? → createRunningTaskRun (最佳努力,失败不阻塞)

   

2. L134-144: settle 闭包定义

   └── 调用 onSettled 回调,决定是否持久化

3. L145-235: agentCommandFromGatewayIngress(...).then(...)

   ├── 成功路径:

   │   ├── 检查 aborted 状态

   │   ├── 读取 timeoutAttribution

   │   ├── 终结 tracked task (tryFinalizeTrackedAgentTask)

   │   ├── 构建 payload (status/summary/stopReason/timeoutPhase)

   │   ├── 构建 terminalOutcome (buildAgentRunTerminalOutcome)

   │   ├── settle → 持久化 dedupe → respond

   │   └── send second res frame (for TS clients)

   │

   └── .catch(...): 错误路径

       ├── isGatewayAgentAbortRejection 判断

       ├── 构建 errorShape(UNAVAILABLE, ...)

       ├── 构建 terminalOutcome (timeout/error)

       ├── settle → persist → respond

       

4. L236-239: .finally()

   ├── clearAgentRunContext (清理运行上下文)

   └── cleanupAbortController (清理中断控制器)

关键设计要点

  • Task tracking 是 best-effort:失败了 log warning,不阻塞 agent run
  • settle 闭包控制持久化节奏:先回调再写 dedupe
  • 两次 respond:Swift 客户端用第一次,TS 客户端等第二次 expectFinal
  • .finally() 保证无论如何都会清理 run context 和 abort controller

主要就两处需要微调——L40-42 和 L44-58 是"判断"而非"显示/解析原因",L77-79 和 L60-65 来源不同。

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐