codev / docs /architecture /agent-loop.md
chenbhao's picture
chore: rename VersperClaw to Codev, update org to chenbhao
96f34e3
|
Raw
History Blame Contribute Delete
27.3 kB

Agent 循环与查询引擎深度分析

本文基于 src/query.tssrc/QueryEngine.tssrc/query/*src/services/tools/* 等核心模块, 详细阐述 Codev (Claude Code) 的 Agent 循环架构、模型调用管道、工具调度机制、恢复策略与继续决策逻辑。 文中列出具体文件路径、函数名称与行号,供开发者快速定位代码。


目录

  1. 主循环架构 (queryLoop)
  2. 模型调用管道
  3. 工具调度与流式执行
  4. Stop Hooks (后处理管道)
  5. 继续决策
  6. 恢复机制
  7. QueryEngine.ts 的角色
  8. 工具执行引擎
  9. 参考文件索引

1. 主循环架构 (queryLoop)

1.1 概述

queryLoop() 是整个 Agent 的核心,它是一个 AsyncGenerator,运行在 query() 函数内部的 while (true) 无限循环中。每次迭代代表一个 turn(回合),包括:输入处理、模型调用、工具执行、后处理钩子、继续决策。

┌─────────────────────────────────────────────────────────────────┐
│                    queryLoop (AsyncGenerator)                     │
│                                                                   │
│  ┌──────────┐   ┌──────────┐   ┌──────────┐   ┌──────────┐      │
│  │ Pre-model │──>│  Model   │──>│  Tool    │──>│  Stop    │──>    │
│  │ Context   │   │Invocation│   │Dispatch  │   │  Hooks   │       │
│  │ Shaping   │   │(Stream)  │   │& Exec    │   │(Post-turn)│      │
│  └──────────┘   └──────────┘   └──────────┘   └──────────┘      │
│       │              │              │              │              │
│       │              │              │              │              │
│       └──────────────┴──────────────┴──────────────┘              │
│                              │                                    │
│                         ┌─────▼──────┐                            │
│                         │ Continuation│                           │
│                         │  Decision   │──> continue (loop again)  │
│                         └─────┬──────┘                            │
│                               │ stop                              │
│                               ▼                                    │
│                          return Terminal                            │
└─────────────────────────────────────────────────────────────────┘

文件: src/query.ts

  • query() 函数: 第 219-239 行 — 公共入口,封装 queryLoop 并处理 consumedCommandUuids
  • queryLoop() 函数: 第 241-1729 行 — 主循环体
  • QueryParams 类型: 第 181-199 行 — 循环的输入参数
  • State 类型: 第 204-217 行 — 跨迭代的可变状态

1.2 五种核心阶段

每一个 turn 循环包含以下阶段:

阶段 A: Pre-model Context Shaping (第 365-548 行)

在调用模型之前,对消息列表进行一系列上下文压缩和优化:

  1. Tool Result Budget (第 376-394 行): applyToolResultBudget() 限制每个消息中 tool_result 的总大小,防止工具输出膨胀。
  2. Snip Compact (第 400-410 行): snipCompactIfNeeded() — 被 HISTORY_SNIP 特性门控,裁剪历史消息中的冗余内容。
  3. Microcompact (第 413-426 行): deps.microcompact() — 对连续工具结果进行微压缩,减小上下文体积。
  4. Context Collapse (第 440-447 行): applyCollapsesIfNeeded() — 被 CONTEXT_COLLAPSE 门控,对历史消息进行投影式折叠。
  5. Auto-compact (第 454-543 行): deps.autocompact() — 全自动上下文压缩,当 Token 数超过阈值时触发。
  6. Blocking Limit Check (第 628-648 行): 计算是否已达到硬性阻塞限制,阻止 API 调用并返回 blocking_limit

阶段 B: Model Invocation (第 652-863 行)

见第 2 节详细分析。

阶段 C: Tool Dispatch & Execution (第 1360-1409 行)

  • 如果启用 StreamingToolExecutor,使用 getRemainingResults() 处理流式工具结果
  • 否则使用 runTools() 执行工具(通过 toolOrchestration.ts
  • 工具结果被收集到 toolResults 数组中

阶段 D: Stop Hooks (第 1267-1306 行)

handleStopHooks() 处理后处理管道(见第 4 节)。

阶段 E: Continuation Decision (第 1308-1357 行)

根据 token 预算、stop hooks 结果等决定是否继续循环。

1.3 状态管理

queryLoop 使用 State 类型(第 204-217 行)管理跨迭代的可变状态:

type State = {
  messages: Message[]
  toolUseContext: ToolUseContext
  autoCompactTracking: AutoCompactTrackingState | undefined
  maxOutputTokensRecoveryCount: number
  hasAttemptedReactiveCompact: boolean
  maxOutputTokensOverride: number | undefined
  pendingToolUseSummary: Promise<ToolUseSummaryMessage | null> | undefined
  stopHookActive: boolean | undefined
  turnCount: number
  transition: Continue | undefined
}

每次迭代开始时解构 state(第 311-321 行),在所有继续点(continue sites)通过 state = { ... }(第 1099-1116 行、第 1207-1221 行等)整体替换。

transition 字段记录上次迭代的继续原因,用于测试断言恢复路径是否正确触发。


2. 模型调用管道

2.1 callModel 实现

模型调用通过 deps.callModel()(第 659 行)进行,其类型为 typeof queryModelWithStreamingsrc/query/deps.ts 第 23 行)。

queryDeps.ts (第 21-30 行) 定义了四种依赖:

  • callModel: typeof queryModelWithStreaming — 流式 API 调用
  • microcompact: typeof microcompactMessages — 微压缩
  • autocompact: typeof autoCompactIfNeeded — 自动压缩
  • uuid: () => string — UUID 生成

productionDeps() (第 33-39 行) 提供生产环境实现。

2.2 流式事件处理

模型输出的流式事件在 for await (const message of deps.callModel({...})) 循环中处理(第 659-863 行):

事件类型 处理位置 说明
text_delta 由 claude.ts 封装 文本增量
tool_use 第 829-845 行 提取 tool_use 块,推入 toolUseBlocks
content_block 第 748-787 行 处理 content block,backfill tool_use input
message_stop 第 866-892 行 处理缓存的微压缩边界消息

关键逻辑:

  • Backfill tool_use input (第 748-787 行): 当工具定义包含 backfillObservableInput 时,对 tool_use 块进行输入回填(如展开文件路径)。
  • Withhold 机制 (第 799-825 行): 可恢复的错误(prompt-too-long、max-output-tokens、media-size-error)在流中被扣留(withhold),不 yield 给调用方,直到恢复机制确认无法恢复后才暴露。
  • Streaming Fallback (第 712-741 行): 当发生流式模型回退时,清空 previous assistant messages 和 tool results,创建新的 StreamingToolExecutor。

2.3 max_output_tokens 恢复机制

代码位置: 第 164 行、第 1188-1256 行

恢复步骤:
1. 第1次: 设置 maxOutputTokensOverride = ESCALATED_MAX_TOKENS (64K) 重试
          (第 1194-1221 行, 仅当 capEnabled 且第一次)
2. 第2-4次: 注入恢复消息 "Output token limit hit. Resume directly..."
            (第 1223-1252 行, 最多 3 次 = MAX_OUTPUT_TOKENS_RECOVERY_LIMIT)
3. 超出限制: 暴露扣留的错误消息并返回 (第 1254-1256 行)

如果用户设置了 CLAUDE_CODE_MAX_OUTPUT_TOKENS 环境变量,8K→64K 的自动升级会被跳过(第 1202 行)。

2.4 缓存控制

  • skipCacheWrite 参数(第 192 行)— 传递给 API 调用选项(第 697 行),控制是否跳过缓存写入。
  • pendingCacheEdits(第 423-425 行)— CACHED_MICROCOMPACT 特性门控,在 API 响应后使用实际 API 报告的 cache_deleted_input_tokens 生成边界消息(第 870-892 行)。

3. 工具调度与流式执行

3.1 StreamingToolExecutor 架构

文件: src/services/tools/StreamingToolExecutor.ts

StreamingToolExecutor 是一个类(第 40-519 行),实现工具的流式执行调度。它在模型仍输出内容时就开始执行已到达的工具。

模型流式输出工具调用
         │
         ▼
  StreamingToolExecutor.addTool()
         │
         ├── 并发安全工具(concurrency-safe)→ 并行执行
         └── 非并发安全工具 → 独占执行
         │
         ▼
  收集结果 → getCompletedResults() / getRemainingResults()

核心数据结构

type TrackedTool = {
  id: string
  block: ToolUseBlock
  assistantMessage: AssistantMessage
  status: ToolStatus        // 'queued' | 'executing' | 'completed' | 'yielded'
  isConcurrencySafe: boolean
  promise?: Promise<void>
  results?: Message[]
  pendingProgress: Message[]
  contextModifiers?: Array<(context: ToolUseContext) => ToolUseContext>
}

并发控制

  • addTool() (第 76-124 行): 将工具加入队列,立即触发 processQueue()
  • canExecuteTool() (第 129-135 行): 决定是否可以执行:
    • 如果没有正在执行的工具 → 总是可以
    • 如果工具是并发安全的且所有正在执行的工具也是并发安全的 → 可以
    • 否则 → 阻塞
  • processQueue() (第 140-150 行): 遍历队列,对每个 queued 工具检查执行条件。
  • getCompletedResults() (第 412-440 行): 非阻塞收集已完成的结果,保持顺序(非并发工具会阻断后续工具的 yield)。
  • getRemainingResults() (第 453-490 行): 等待所有工具完成,带进度唤醒。

Bash 错误级联

当 Bash 工具失败时(第 359-363 行),hasErrored 被置为 true,兄弟工具通过 siblingAbortController 被取消。这防止了在 mkdir 失败后继续执行依赖的命令。

进度通知

  • BashProgress: Bash 工具执行的 stdout/stderr 增量更新
  • AgentProgress: 子 agent 执行进度
  • MCPProgress: MCP 工具执行的进度

进度消息通过 pendingProgress 队列立即 yield(第 368-374 行),并通过 progressAvailableResolve 信号唤醒 getRemainingResults()

3.2 非流式工具执行 (runTools)

文件: src/services/tools/toolOrchestration.ts

StreamingToolExecutor 未启用时,使用 runTools() 函数(第 19-82 行)。

工具批处理分区

partitionToolCalls()(第 91-116 行)将工具调用分区为批次:

  • 并发安全批次: 多个工具并行执行(通过 runToolsConcurrently()
  • 非并发安全批次: 单个工具串行执行(通过 runToolsSerially()

最大并发数由 CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY 环境变量控制,默认为 10(第 8-12 行)。


4. Stop Hooks (后处理管道)

文件: src/query/stopHooks.ts

4.1 概要

handleStopHooks() 函数(第 65-473 行)在每一 turn 的模型响应结束后运行。它是一个 AsyncGeneratoryield 进度/附件消息,最终返回 StopHookResult

type StopHookResult = {
  blockingErrors: Message[]    // 阻断性错误(钩子注入的消息)
  preventContinuation: boolean // 是否阻止继续循环
}

4.2 执行流程

  1. 保存 cacheSafeParams (第 96-98 行)
  2. 模板作业分类 (第 108-132 行)
  3. Prompt 建议 (第 139 行) [fire-and-forget]
  4. Memory 提取 (第 141-153 行) [fire-and-forget]
  5. Auto-dream (第 154-156 行) [fire-and-forget]
  6. MCP 清理 (第 164-173 行)
  7. executeStopHooks() (第 180 行) — 主钩子执行
  8. Teammate hooks (第 335-453 行)

4.3 Stop Hooks 执行

executeStopHooks()(第 180 行)返回一个 generator,产生进度消息和阻断错误。

钩子结果处理(第 192-295 行):

  • 进度消息 (第 201-215 行): 收集每个钩子的 commandpromptText
  • 阻断错误 (第 257-267 行): 创建 createUserMessage({ isMeta: true }) 作为阻断消息
  • 继续阻止 (第 269-280 行): 生成 hook_stopped_continuation 附件
  • 中止检测 (第 283-294 行): 如果被中止,返回 { preventContinuation: true }

4.4 后台任务

任务 位置 说明
executePromptSuggestion() 第 139 行 生成提示建议(仅非 bare 模式)
executeExtractMemories() 第 141-153 行 提取记忆(EXTRACT_MEMORIES 门控)
executeAutoDream() 第 154-156 行 自动记忆整理
cleanupComputerUseAfterTurn() 第 164-173 行 MCP 计算机使用清理(CHICAGO_MCP 门控)

4.5 模板作业分类

当设置了 CLAUDE_JOB_DIR 环境变量时(第 110 行),jobClassifierModule!.classifyAndWriteState()(第 121 行)在每次 turn 后分类作业状态。加 60 秒超时(第 127-131 行)。

4.6 Teammate Hooks

在 teammate 模式下(第 335 行):

  1. TaskCompleted hooks (第 345-400 行): 对每个 in_progress 且属于当前 teammate 的任务执行 executeTaskCompletedHooks()
  2. TeammateIdle hooks (第 402-441 行): 执行 executeTeammateIdleHooks()

这两个钩子都支持 preventContinuationblockingErrors

4.7 阻断错误与继续抑制

  • blockingErrors: 由钩子注入的系统消息,作为当前 turn 的继续输入(第 1282-1306 行)
  • preventContinuation: 立即结束循环返回 stop_hook_prevented(第 1278 行)
  • 错误免入死亡螺旋 (第 1260-1264 行): 当 lastMessage 是 API 错误时,跳过 stop hooks

5. 继续决策

文件: src/query/tokenBudget.ts

5.1 checkTokenBudget

function checkTokenBudget(
  tracker: BudgetTracker,
  agentId: string | undefined,
  budget: number | null,       // getCurrentTurnTokenBudget()
  globalTurnTokens: number,    // getTurnOutputTokens()
): TokenBudgetDecision

第 45-93 行。

5.2 决策逻辑

1. 跳过条件: agentId 存在 OR budget 为 null/0 → stop (第 51-53 行)
2. 计算使用率 pct = turnTokens / budget * 100 (第 56 行)
3. 收益递减检测: 连续 3+ 次继续且每次增量 < 500 tokens (第 59-62 行)
4. 如果 pct < 90% 且非收益递减 → continue (第 66-75 行)
5. 否则 → stop (第 78-92 行)

5.3 90% 阈值

COMPLETION_THRESHOLD = 0.9(第 3 行): 当 token 消耗达到预算的 90% 时触发继续。

5.4 收益递减检测

DIMINISHING_THRESHOLD = 500(第 4 行): 当连续 3+ 次继续且每次增量 < 500 tokens,认为模型收益递减,提前停止。

5.5 集成到 queryLoop

queryLoop 中(src/query.ts 第 1308-1355 行):

if (feature('TOKEN_BUDGET')) {
  const decision = checkTokenBudget(budgetTracker!, ...)
  if (decision.action === 'continue') {
    // 注入 nudgemessage
    // incrementBudgetContinuationCount()
    // 设置 state.transition = { reason: 'token_budget_continuation' }
    // continue (继续循环)
  }
  // 否则记录 completionEvent
}
// return { reason: 'completed' }

5.6 任务预算 (taskBudget)

taskBudgetsrc/query.ts 第 197-198 行)是 API 端的 task_budget(output_config.task_budget, beta task-budgets-2026-03-13)。与 tokenBudget +500k 自动继续的不同。

  • 在每次压缩后计算 taskBudgetRemaining(第 508-515 行、第 1138-1146 行)
  • 传递给 API 调用(第 699-706 行)

6. 恢复机制

6.1 max_output_tokens 恢复

文件: src/query.ts

恢复阶段 触发条件 行为 行号
8K→64K 升级 首次命中上限,capEnabled 且无用户自定义 设置 maxOutputTokensOverride=64K,重试 第 1194-1221 行
恢复消息注入 已升级或 cap 关闭 注入 "Output token limit hit" 消息 第 1223-1252 行
限制耗尽 超过 3 次 暴露扣留的错误 第 1254-1256 行

MAX_OUTPUT_TOKENS_RECOVERY_LIMIT = 3(第 164 行)。

6.2 Context Collapse 压缩

文件: src/query.ts

当 API 返回 prompt-too-long 错误时(第 1085-1118 行):

  1. 首先尝试 contextCollapse.recoverFromOverflow()(第 1094 行) — 从已分阶段(staged)的折叠队列中释放
  2. 如果已经尝试过 collapse_drain_retry(第 1092 行),则跳过直接走 reactive compact

6.3 Reactive Compact

文件: src/query.ts

当 prompt-too-long 错误和 reactive compact 都启用时(第 1119-1175 行):

  1. 调用 reactiveCompact.tryReactiveCompact()(第 1120 行)
  2. 成功→构建压缩消息,设置 hasAttemptedReactiveCompact = true
  3. 失败→暴露错误消息

6.4 错误恢复策略总结

API 413 (prompt too long)
  ├── Context Collapse drain (第 1094 行)
  │     └── 失败→ fall through
  ├── Reactive Compact (第 1120 行)
  │     └── 失败→ 返回 prompt_too_long
  └── (如果两者都不可用) → 返回 blocking_limit

max_output_tokens
  ├── 8K→64K escalate (第 1194 行)
  ├── 恢复消息注入 x3 (第 1223 行)
  └── 暴露错误 (第 1254 行)

model fallback (第 893-953 行)
  └── 切换到备用模型,清理并重试

一般错误 (第 955-997 行)
  └── yield 错误消息,返回 model_error

7. QueryEngine.ts 的角色

文件: src/QueryEngine.ts

7.1 概述

QueryEngine 类(第 184-1177 行)封装了查询生命周期和会话状态,是 ask() 函数的核心引擎。它提取了在 headless/SDK 和 REPL 间共享的逻辑。

7.2 与 query.ts 的关系

  ask() 函数                          QueryEngine.submitMessage() 方法
    │                                       │
    │  创建 QueryEngine 实例                  │
    │  (第 1249-1285 行)                     │
    │                                       │
    └─── query() ────────────────────────────┘
          │
          │  AsyncGenerator
          ▼
      yield 消息流 (assistant/user/attachment/stream_event/...)
  • ask()(第 1186-1295 行)是一个便利包装器,创建 QueryEngine 实例并调用 submitMessage()
  • QueryEngine.submitMessage()(第 209-1156 行)处理完整的查询生命周期:
    1. 构建 ProcessUserInputContext(第 335-395 行)
    2. 处理用户输入(第 410-428 行)
    3. 记录 transcript(第 450-463 行)
    4. 调用 query()(第 675-686 行)
    5. 处理 query 产出的所有消息类型(第 757-969 行)
    6. 生成最终 result(第 1082-1155 行)

7.3 关键职责

  • 消息持久化: recordTranscript()(第 717-732 行)
  • 权限跟踪: wrappedCanUseTool() 包装(第 244-271 行)记录权限拒绝
  • SDK 消息规范化: normalizeMessage()(第 769、783、787 行)
  • 预算检查: USD 预算(第 972-1002 行)和结构化输出重试限制(第 1005-1048 行)
  • Snip 回放: snipReplay 回调(第 905-914 行)在 SDK 模式下处理 snip 边界

7.4 submitMessage 的消息处理

submitMessage()for await 循环处理 10+ 种消息类型:

消息类型 处理 行号
assistant push 到 mutableMessages,yield 规范化 第 761-769 行
user push,yield 规范化,turnCount++ 第 753-787 行
progress push,记录 transcript 第 771-783 行
stream_event 累积 usage,跟踪 stop_reason 第 788-827 行
attachment 处理结构化输出、max_turns、queued_command 第 829-893 行
system 处理 compact_boundary、api_error、snip 第 897-958 行
tool_use_summary yield 工具使用摘要 第 959-969 行

8. 工具执行引擎

文件: src/services/tools/toolExecution.ts

8.1 工具执行九步生命周期

runToolUse() 函数(第 337-490 行)实现工具的完整执行生命周期:

1. Tool Lookup & Validation
   │  findToolByName() (第 345 行)
   │  别名回退 (第 350-355 行)
   ▼
2. Abort Check
   │  abortController.signal.aborted (第 415 行)
   ▼
3. Input Validation (Zod)
   │  tool.inputSchema.safeParse() (第 615 行)
   ▼
4. Custom Validation
   │  tool.validateInput() (第 683 行)
   ▼
5. Pre-Tool Hooks
   │  runPreToolUseHooks() (第 800 行)
   ▼
6. Permission Check & User Confirmation
   │  resolveHookPermissionDecision() (第 921 行)
   │  canUseTool() (第 927 行)
   ▼
7. Tool Execution
   │  tool.call() (第 1207 行)
   ▼
8. Result Processing
   │  tool.mapToolResultToToolResultBlockParam() (第 1292 行)
   │  processToolResultBlock() (第 1415 行)
   ▼
9. Post-Tool Hooks
   │  runPostToolUseHooks() (第 1483 行)
   │  runPostToolUseFailureHooks() (第 1700 行)

8.2 详细步骤解析

步骤 1-2: 工具查找与中止检查

runToolUse()(第 337-490 行):

// 1. 查找工具 (第 345-355 行)
let tool = findToolByName(toolUseContext.options.tools, toolName)
if (!tool) {
  // 通过别名回退 (第 350-355 行)
}
// 2. 中止检查 (第 415-453 行)
if (toolUseContext.abortController.signal.aborted) {
  // yield "cancelled" 消息
}

步骤 3-4: 输入验证

checkPermissionsAndCallTool()(第 599-1745 行):

Zod Schema 验证(第 615-679 行):

  • tool.inputSchema.safeParse(input) 使用 Zod 验证模型输入
  • 失败时生成格式化的 Zod 错误并附加 schema-not-sent 提示(第 578-597 行)
  • buildSchemaNotSentHint(): 检测到延迟工具(deferred tool)的 schema 没有被发送到 API 时,提示模型使用 ToolSearch 重新加载

自定义验证(第 683-733 行):

  • 每个工具可以定义自己的 validateInput() 方法
  • 验证失败返回 isValidCall.result === false

步骤 5: Pre-Tool Hooks

文件: src/services/tools/toolHooks.ts

runPreToolUseHooks()(第 435-650 行):

返回多类型结果:

结果类型 说明
message 进度消息或附件消息
hookPermissionResult 钩子做出的权限决定 (allow/deny/ask)
hookUpdatedInput 钩子修改后的输入 (passthrough)
preventContinuation 阻止继续
stopReason 停止原因
additionalContext 额外的上下文消息
stop 立即停止

步骤 6: 权限检查

文件: src/services/tools/toolHooks.ts

resolveHookPermissionDecision()(第 332-433 行):

  • Hook allow: 仍然检查 settings.json 的 deny/ask 规则(第 373-385 行)
  • Hook deny: 直接拒绝(第 408-411 行)
  • 无钩子决定: 走正常权限流程,可能包含 forceDecision(第 413-432 行)
  • 需用户交互: 钩子批准后如果 requiresUserInteraction()requireCanUseTool,仍调用 canUseTool()(第 356-370 行)

canUseToolsrc/hooks/useCanUseTool.tsx 中实现(React hook),处理 interactive/coordinator/swarm 三种权限模式。

步骤 7: 工具执行

tool.call()(第 1207 行):

  • 使用处理后的输入调用工具
  • 通过 onToolProgress 回调报告进度
  • 使用 toolAbortController(第 301 行)实现 per-tool 取消

Bash 错误级联(第 359-363 行):

if (tool.block.name === BASH_TOOL_NAME) {
  this.hasErrored = true
  this.siblingAbortController.abort('sibling_error')
}

步骤 8: 结果处理

  • tool.mapToolResultToToolResultBlockParam()(第 1292 行)映射工具结果
  • processPreMappedToolResultBlock() / processToolResultBlock()(第 1409-1415 行)进行后处理
  • applyToolResultBudget()(第 379 行)限制工具结果大小

步骤 9: Post-Tool Hooks

文件: src/services/tools/toolHooks.ts

runPostToolUseHooks()(第 39-191 行):

  • 对 MCP 工具,支持 updatedMCPToolOutput
  • 支持 blockingErrorpreventContinuationadditionalContext

runPostToolUseFailureHooks()(第 193-319 行):

  • 工具失败时执行
  • 同样支持 blockingErrorpreventContinuationadditionalContext

8.3 错误分类与处理

classifyToolError()(第 150-171 行)将错误分类为安全的 telemetry 字符串:

  • TelemetrySafeError: 使用预审的 telemetryMessage
  • Node.js errno 错误: 记录 ENOENT 等代码
  • 已知错误类型: 使用构造函数名称
  • 未知错误: 降级为 "Error"

8.4 工具遥测

工具执行的每个阶段都会发出遥测事件:

事件 触发时机 代码位置
tengu_tool_use_error 工具不存在 第 372 行
tengu_tool_use_cancelled 工具被取消 第 416 行
tengu_tool_use_progress 进度更新 第 523 行
tengu_tool_use_can_use_tool_rejected 权限拒绝 第 1001 行
tengu_tool_use_can_use_tool_allowed 权限批准 第 1105 行
tengu_tool_use_success 工具执行成功 第 1331 行
tool_decision (OTel) 权限决策 第 962 行
tool_result (OTel) 工具结果 第 1381 行

9. 参考文件索引

文件 路径 核心内容
主查询循环 src/query.ts query(), queryLoop(), 完整 Agent 循环
查询配置 src/query/config.ts buildQueryConfig(), QueryConfig 类型
查询依赖 src/query/deps.ts QueryDeps, productionDeps()
停止钩子 src/query/stopHooks.ts handleStopHooks(), StopHookResult
Token 预算 src/query/tokenBudget.ts checkTokenBudget(), BudgetTracker
转换类型 src/query/transitions.ts Terminal, Continue 类型
查询引擎 src/QueryEngine.ts QueryEngine 类, ask() 函数
工具流式执行器 src/services/tools/StreamingToolExecutor.ts StreamingToolExecutor
工具执行 src/services/tools/toolExecution.ts runToolUse(), checkPermissionsAndCallTool()
工具编排 src/services/tools/toolOrchestration.ts runTools(), partitionToolCalls()
工具钩子 src/services/tools/toolHooks.ts runPreToolUseHooks(), runPostToolUseHooks(), resolveHookPermissionDecision()
权限检查 src/hooks/useCanUseTool.tsx useCanUseTool() React hook, 权限模式