02.1 Query Loop
关注源码
src/query.tssrc/query/config.tssrc/query/tokenBudget.tssrc/query/stopHooks.ts
核心心智模型
query.ts 不是“问一次模型拿一个字符串”,而是一台消息状态机。它把下面这些对象放进同一条事件流:
- request start
- assistant streaming 片段
- tool use / tool result
- compact boundary
- tombstone / 恢复消息
- tool use summary
因此它天然可以被:
- TUI 消费
- SDK/structured I/O 消费
- 远端会话消费
循环里的稳定输入
进入 query() 时,会先冻结一批本轮稳定数据:
systemPromptuserContextsystemContextcanUseToolfallbackModelquerySourceQueryConfig
query/config.ts 还会把部分 runtime gate 快照化,例如:
- streaming tool execution 是否开启
- 是否发 tool use summary
- 当前是否 ant 构建
- fast mode 是否开启
这一步的意义是让一次 query 内部行为稳定,不被中途的 settings/gate 变化扰动。
循环里的可变状态
query.ts 维护的 State 主要包含:
messagestoolUseContextautoCompactTrackingmaxOutputTokensRecoveryCountpendingToolUseSummarystopHookActiveturnCounttransition
也就是说,query loop 的推进不是靠隐式全局变量,而是靠显式状态迁移。
主回合里真正发生什么
1. 组装模型输入
每一轮会把:
- 历史消息
- user/system context
- 附件
- tool schema
整理成发给模型的请求体。
2. 消费流式模型输出
模型输出可能产生:
- 普通 assistant 内容
- thinking / redacted thinking
- tool use blocks
- API error message
query loop 会边消费边构造新的 transcript message。
3. 进入工具阶段
如果 assistant 输出中带了 tool use,query.ts 会把这一轮转给 services/tools/* 执行,再把 tool result 重新写回 messages。
4. 决定是否继续
继续的原因可能包括:
- 模型刚刚拿到 tool result,需要下一轮继续思考
- 达到 token budget continuation 条件
- 发生了 max_output_tokens 恢复
- 发生了 compact,需要基于摘要继续
关键恢复路径
max_output_tokens 恢复
query.ts 对 max_output_tokens 有专门恢复逻辑,并且会刻意“暂不向 SDK 暴露中间错误”,避免上层误判整个会话已经终止。
自动压缩 / reactive compact
当 token 紧张或 API 返回 prompt too long 时,query loop 会进入 compact 路径,把消息摘要化后再继续。
stop hooks
回合完成后,stop hooks 可能触发:
- session memory
- extract memories
- prompt suggestion
- 其他 post-turn side effects
因此“一轮 query 完成”不只是生成最后一条 assistant message。
设计上值得注意的点
1. 消息是第一公民
系统几乎所有重要事件都被表示为消息或消息边界,而不是只存在于内部回调里。这样可以:
- 统一 transcript
- 统一 UI
- 统一远端同步
2. 恢复路径是主路径的一部分
压缩、fallback、恢复并不是异常分支,而是核心运行时内建能力。
3. query loop 尽量保持“稳定输入 + 显式状态”
这为后续抽出纯 reducer、做 SDK 复用或写测试提供了结构基础。