Claude Code 源码笔记 -- State状态流转

State 是 queryLoop 唯一的跨轮可变量,所有"记忆"都在这里:

typescript 复制代码
type State = {
  // 完整消息历史
  messages: Message[]
  // 工具上下文,包含 AbortController、工具列表、agentId 等,迭代内可能被更新
  toolUseContext: ToolUseContext
  // 自动压缩跟踪
  autoCompactTracking: AutoCompactTrackingState | undefined
  // max_output_tokens 恢复重试次数(上限3)
  maxOutputTokensRecoveryCount: number
  // 是否已尝试,防止 reactive compact 陷入无限循环的守卫位
  hasAttemptedReactiveCompact: boolean
  // 临时 token 上限覆盖,设置后下一轮将以 64k token 上限重试
  maxOutputTokensOverride: number | undefined
  // 异步预生成的工具摘要,上一轮工具调用摘要的异步 Promise,下一轮 yield 给前端
  pendingToolUseSummary: Promise<ToolUseSummaryMessage | null> | undefined
  // stop hook 是否活跃(防止 hook 错误触发死循环)
  stopHookActive: boolean | undefined
  // 当前轮次,用于 maxTurns 限制检查
  turnCount: number
  // 上一轮 continue 的原因
  transition: Continue | undefined
}

迭代内临时变量

这些变量每轮重新声明,相当于当前轮的"草稿纸":

typescript 复制代码
// 流式收集本轮模型产生的所有 assistant 消息(包括思考、文本、tool_use)
const assistantMessages: AssistantMessage[] = []
// 工具执行完毕后的结果消息,将作为下一轮模型的输入
const toolResults: (UserMessage | AttachmentMessage)[] = []
// 从流中提取的所有 tool_use 块,决定本轮需要调用哪些工具
const toolUseBlocks: ToolUseBlock[] = []
// 只要流中出现了 tool_use 块就置为 true,是"有工具要执行"的信号
let needsFollowUp = false

迭代末尾,这些"草稿"被合并进持久状态:

typescript 复制代码
state.messages = [...messagesForQuery, ...assistantMessages, ...toolResults]

状态枚举:继续循环

以下场景触发state = next; continue,即不退出,开始下一轮:

  1. next_turn ------ 正常推进
    触发条件:模型输出了 tool_use,工具执行完毕,一切正常。 这是最常见的 continue 原因,代表 agent 正在正常工作中。工具结果被追加到 messages 后进入下一轮,让模型基于结果继续推理。
  2. collapse_drain_retry ------ 上下文折叠恢复
    触发条件:收到 HTTP 413(prompt too long),且 context collapse 功能开启,且本轮并非已经从 collapse 中恢复过。 做法是将部分上下文"折叠压缩"释放空间,然后用更短的 messages 重新请求模型,不增加 turnCount。
  3. reactive_compact_retry ------ 响应式压缩恢复
    触发条件:收到 413 或媒体大小错误,尝试对整个对话做一次 compact(生成摘要替换历史)。 hasAttemptedReactiveCompact 被设为 true,确保此路径只走一次,防止无限压缩。
  4. max_output_tokens_escalate ------ 提升 token 上限
    触发条件:模型输出被 max_output_tokens 截断,且本轮还没有尝试过提升上限。 下一轮将以 64k tokens 的上限重试同样的请求。此路径只触发一次(由 maxOutputTokensOverride === undefined 守卫)。
  5. max_output_tokens_recovery ------ 注入恢复提示
    触发条件:max_output_tokens 截断,且 escalate 也没有解决(或不适用)。 向对话注入一条 meta 消息,告知模型"输出被截断,直接继续,不要道歉",最多重试 3 次(由 maxOutputTokensRecoveryCount < 3 守卫)。
  6. stop_hook_blocking ------ Stop Hook 阻塞重试
    触发条件:模型给出了正常响应(非 API 错误),stop hook 执行后发现有阻塞性错误需要反馈给模型。 将 hook 产生的错误消息追加到 messages,让模型看到并修正。stopHookActive 被设为 true 以标记 hook 正在活跃。
  7. token_budget_continuation ------ Token Budget 未耗尽
    触发条件:TOKEN_BUDGET 功能开启,模型给出了响应,但 budget 检查认为还有配额,应该继续。 向对话注入一条"nudge"消息引导模型继续输出,直到 budget 耗尽或任务完成。

状态枚举 退出循环

以下场景触发 return { reason: '...' },循环终止:

  1. blocking_limit
    token 数量已经达到硬性上限,且用户关闭了 autocompact。此时不允许继续,输出错误消息后退出。这是一个"安全阀",为用户保留手动运行 /compact 的空间。
  2. model_error / image_error
    模型调用抛出了无法恢复的异常,或图片大小超限且无法压缩恢复。
  3. aborted_streaming
    用户在模型流式输出过程中按下了中断(Ctrl+C)。
  4. aborted_tools
    用户在工具执行过程中中断。
  5. hook_stopped
    某个工具的 hook 明确返回了"阻止继续"的指令shouldPreventContinuation = true
  6. prompt_too_long
    收到 413,且所有恢复手段(collapse drain + reactive compact)都已用尽,只能放弃。
  7. stop_hook_prevented
    stop hook 明确返回了 preventContinuation: true,通常表示某个外部策略要求停止。
  8. completed
    正常完成。分两种情况:
    • 模型返回了 API 错误(非 tool_use)→ 上报 failure hook 后退出
    • 模型给出正常文本响应,stop hook 无异议,token budget 也耗尽或不需要继续 → 正常完成
  9. max_turns
    turnCount超过了调用方传入的 maxTurns 上限。
latex 复制代码
queryLoop 进入
      │
      ▼
  初始化 state(第268行)
  turnCount=1, transition=undefined
      │
      ╔═════════════════════════════════════════════╗
      ║              while(true) 循环体              ║
      ║                                             ║
      ║  Step 1: 消息预处理                          ║
      ║  snip(截断过长历史)                        ║
      ║  → microcompact(轻量压缩)                  ║
      ║  → contextCollapse(上下文折叠)             ║
      ║  → autoCompact(token超阈值时自动压缩)       ║
      ║         │                                   ║
      ║  Step 2: blocking_limit 检查                ║
      ║  token超限且autocompact关闭?                ║
      ║  是 ──────────────────────────────► return  ║
      ║         │  否                    'blocking_ ║
      ║  Step 3: callModel() 流式调用      limit'   ║
      ║         │                                   ║
      ║   ┌─────▼──────────────────────┐            ║
      ║   │ 内层 while(attemptWithFallback)│         ║
      ║   │  收集 assistantMessages    │            ║
      ║   │  收集 toolUseBlocks        │            ║
      ║   │  设置 needsFollowUp=true   │            ║
      ║   │  FallbackTriggeredError?   │            ║
      ║   │  → 切换模型,continue(内层) │            ║
      ║   └─────────────────────────────┘            ║
      ║         │                                   ║
      ║  其他异常 ──────────────────────► return     ║
      ║         │                   'model_error'   ║
      ║  用户中断 ──────────────────────► return     ║
      ║         │               'aborted_streaming' ║
      ║         │                                   ║
      ║  ┌──────▼──────────────────────────────┐    ║
      ║  │  needsFollowUp == false?             │    ║
      ║  │  (模型没有产生 tool_use)            │    ║
      ║  └──────┬──────────────────────────┬───┘    ║
      ║    true │(无工具)         false  │(有工具)║
      ║         │                          │        ║
      ║ ┌───────▼──────────┐  ┌────────────▼──────┐ ║
      ║ │  停止条件分支     │  │  工具执行分支      │ ║
      ║ │                  │  │                   │ ║
      ║ │ ①413恢复路径:    │  │ runTools()执行    │ ║
      ║ │  collapse_drain  │  │ 所有 toolUseBlocks│ ║
      ║ │  → continue      │  │                   │ ║
      ║ │  reactive_compact│  │ 用户中断?          │ ║
      ║ │  → continue      │  │ → return          │ ║
      ║ │  都失败 → return  │  │  'aborted_tools'  │ ║
      ║ │                  │  │                   │ ║
      ║ │ ②max_output截断: │  │ hook阻止?          │ ║
      ║ │  escalate        │  │ → return          │ ║
      ║ │  → continue      │  │  'hook_stopped'   │ ║
      ║ │  recovery(×3)    │  │                   │ ║
      ║ │  → continue      │  │ maxTurns超限?      │ ║
      ║ │  耗尽 → yield err │  │ → return          │ ║
      ║ │                  │  │  'max_turns'      │ ║
      ║ │ ③API error?      │  │                   │ ║
      ║ │  → return        │  │ 一切正常:          │ ║
      ║ │   'completed'    │  │ messages合并       │ ║
      ║ │                  │  │ turnCount++        │ ║
      ║ │ ④stop hook检查:  │  │ transition=        │ ║
      ║ │  prevented       │  │  'next_turn'       │ ║
      ║ │  → return        │  │ state=next         │ ║
      ║ │  blocking        │  │ → continue ────┐  │ ║
      ║ │  → continue      │  └────────────────│──┘ ║
      ║ │                  │                   │    ║
      ║ │ ⑤token budget:   │                   │    ║
      ║ │  continue budget │                   │    ║
      ║ │  → continue      │                   │    ║
      ║ │  done            │                   │    ║
      ║ │  → return        │                   │    ║
      ║ │   'completed'    │                   │    ║
      ║ └──────────────────┘                   │    ║
      ║         │ return                        │    ║
      ╚═════════╪═══════════════════════════════╪════╝
                │                               │
                ▼                    ┌──────────┘
           循环终止                  │ 回到循环顶部
                                     ▼
                              解构新的 state
                              开始下一轮
函数 触发的状态流转
callModel() 驱动主循环,通过流产生 assistantMessagestoolUseBlocks
runTools() 执行工具,填充toolResults,可触发 aborted_tools/hook_stopped
handleStopHooks() 返回 preventContinuation/blockingErrors,触发 stop_hook_* 系列转换
contextCollapse.recoverFromOverflow() 触发 collapse_drain_retry
reactiveCompact.tryReactiveCompact() 触发 reactive_compact_retry
checkTokenBudget() 触发 token_budget_continuationcompleted
calculateTokenWarningState() 触发 blocking_limit
isMaxOutputTokensTruncated() 触发 max_output_tokens_escalate/recovery
相关推荐
Hammer_Hans2 小时前
DFT笔记38
笔记
CheerWWW2 小时前
C++学习笔记——函数指针、Lambda表达式、谨慎使用using namespace std、命名空间
c++·笔记·学习
独小乐2 小时前
013.定时器之系统Tick实现|千篇笔记实现嵌入式全栈/裸机篇
linux·笔记·单片机·嵌入式硬件·arm
是上好佳佳佳呀2 小时前
【前端(六)】HTML5 新特性笔记总结
前端·笔记·html5
talen_hx2962 小时前
《零基础入门Spark》学习笔记 Day 14
大数据·笔记·学习·spark
Heartache boy2 小时前
DWT基础应用与获取程序运行时间Debug练习(上)
笔记·stm32·单片机
西梅汁3 小时前
C++ 设计模式三大类型理解
笔记
野指针YZZ3 小时前
XV6操作系统:proc机制学习笔记
笔记·学习
Hammer_Hans3 小时前
DFT笔记37
笔记