814 lines
20 KiB
Markdown
814 lines
20 KiB
Markdown
# 核心模块详解
|
||
|
||
本文件说明:详细分析 Claude Code 的核心源文件,理解其实现原理。
|
||
|
||
## 1. main.tsx - CLI 入口点
|
||
|
||
### 1.1 功能概述
|
||
|
||
`main.tsx` 是 Claude Code 应用程序的入口点,负责:
|
||
|
||
- CLI 参数解析
|
||
- 应用程序初始化
|
||
- REPL(Read-Eval-Print Loop)启动
|
||
- 各种启动前检查和配置
|
||
|
||
### 1.2 启动流程
|
||
|
||
```typescript
|
||
// 1. 启动性能分析
|
||
profileCheckpoint('main_tsx_entry')
|
||
|
||
// 2. MDM 设置预读取(并行)
|
||
startMdmRawRead()
|
||
|
||
// 3. Keychain 凭据预读取(并行)
|
||
startKeychainPrefetch()
|
||
|
||
// 4. 初始化遥测
|
||
initializeTelemetryAfterTrust()
|
||
|
||
// 5. 获取引导数据
|
||
const bootstrapData = await fetchBootstrapData()
|
||
|
||
// 6. 启动 REPL
|
||
launchRepl()
|
||
```
|
||
|
||
### 1.3 关键导入
|
||
|
||
```typescript
|
||
import { Command as CommanderCommand } from '@commander-js/extra-typings'
|
||
import React from 'react'
|
||
import chalk from 'chalk'
|
||
import { getTools } from './tools.js'
|
||
import { getCommands, filterCommandsForRemoteMode } from './commands.js'
|
||
import { getSystemContext, getUserContext } from './context.js'
|
||
```
|
||
|
||
### 1.4 核心配置初始化
|
||
|
||
```typescript
|
||
// 权限模式设置
|
||
const initialPermissionMode = await initialPermissionModeFromCLI()
|
||
|
||
// 工具权限上下文初始化
|
||
initializeToolPermissionContext({
|
||
mode: initialPermissionMode,
|
||
additionalWorkingDirectories: new Map(),
|
||
alwaysAllowRules: {},
|
||
alwaysDenyRules: {},
|
||
alwaysAskRules: {},
|
||
isBypassPermissionsModeAvailable: false,
|
||
})
|
||
|
||
// 获取工具列表
|
||
const tools = getTools(appState.toolPermissionContext)
|
||
|
||
// 获取命令列表
|
||
const commands = await getCommands(cwd)
|
||
```
|
||
|
||
## 2. QueryEngine.ts - LLM 查询引擎核心
|
||
|
||
### 2.1 功能概述
|
||
|
||
`QueryEngine` 是 Claude Code 的核心查询处理类,负责:
|
||
|
||
- 管理对话生命周期(每个对话一个 QueryEngine 实例)
|
||
- 处理用户消息提交
|
||
- 执行 API 调用循环
|
||
- 处理流式响应
|
||
- 编排工具执行
|
||
- 管理会话状态(消息、Token 使用等)
|
||
|
||
### 2.2 类结构
|
||
|
||
```typescript
|
||
export class QueryEngine {
|
||
private config: QueryEngineConfig
|
||
private mutableMessages: Message[] // 对话消息列表
|
||
private abortController: AbortController // 中断控制器
|
||
private permissionDenials: SDKPermissionDenial[] // 权限拒绝记录
|
||
private totalUsage: NonNullableUsage // 累计 Token 使用
|
||
private hasHandledOrphanedPermission = false
|
||
private readFileState: FileStateCache // 文件读取缓存
|
||
private discoveredSkillNames = new Set<string>()
|
||
private loadedNestedMemoryPaths = new Set<string>()
|
||
}
|
||
```
|
||
|
||
### 2.3 核心方法:submitMessage()
|
||
|
||
这是处理用户输入的主要方法:
|
||
|
||
```typescript
|
||
async *submitMessage(
|
||
prompt: string | ContentBlockParam[],
|
||
options?: { uuid?: string; isMeta?: boolean },
|
||
): AsyncGenerator<SDKMessage, void, unknown>
|
||
```
|
||
|
||
**执行流程**:
|
||
|
||
1. **初始化阶段**
|
||
```typescript
|
||
this.discoveredSkillNames.clear()
|
||
setCwd(cwd)
|
||
|
||
// 获取系统提示词
|
||
const { defaultSystemPrompt, userContext, systemContext } =
|
||
await fetchSystemPromptParts({ tools, mainLoopModel, ... })
|
||
```
|
||
|
||
2. **处理用户输入**
|
||
```typescript
|
||
const { messages, shouldQuery, allowedTools, model, resultText } =
|
||
await processUserInput({
|
||
input: prompt,
|
||
mode: 'prompt',
|
||
context: processUserInputContext,
|
||
})
|
||
|
||
// 更新权限规则
|
||
setAppState(prev => ({
|
||
...prev,
|
||
toolPermissionContext: {
|
||
...prev.toolPermissionContext,
|
||
alwaysAllowRules: { command: allowedTools }
|
||
}
|
||
}))
|
||
```
|
||
|
||
3. **构建系统提示**
|
||
```typescript
|
||
const systemPrompt = asSystemPrompt([
|
||
...(customPrompt ?? defaultSystemPrompt),
|
||
...(memoryMechanicsPrompt ?? []), // 记忆机制提示
|
||
...(appendSystemPrompt ?? [])
|
||
])
|
||
```
|
||
|
||
4. **查询循环**
|
||
```typescript
|
||
for await (const message of query({
|
||
messages,
|
||
systemPrompt,
|
||
userContext,
|
||
systemContext,
|
||
canUseTool: wrappedCanUseTool,
|
||
})) {
|
||
// 处理各种消息类型
|
||
switch (message.type) {
|
||
case 'assistant': /* 记录助手消息 */ break
|
||
case 'progress': /* 进度更新 */ break
|
||
case 'user': /* 用户消息 */ break
|
||
case 'stream_event': /* 流式事件 */ break
|
||
case 'attachment': /* 附件处理 */ break
|
||
}
|
||
}
|
||
```
|
||
|
||
### 2.4 流式响应处理
|
||
|
||
QueryEngine 处理多种流式事件:
|
||
|
||
```typescript
|
||
if (message.type === 'stream_event') {
|
||
// message_start: 新消息开始
|
||
if (message.event.type === 'message_start') {
|
||
currentMessageUsage = EMPTY_USAGE
|
||
currentMessageUsage = updateUsage(currentMessageUsage, message.event.message.usage)
|
||
}
|
||
|
||
// message_delta: 消息增量更新
|
||
if (message.event.type === 'message_delta') {
|
||
currentMessageUsage = updateUsage(currentMessageUsage, message.event.usage)
|
||
if (message.event.delta.stop_reason != null) {
|
||
lastStopReason = message.event.delta.stop_reason
|
||
}
|
||
}
|
||
|
||
// message_stop: 消息结束
|
||
if (message.event.type === 'message_stop') {
|
||
this.totalUsage = accumulateUsage(this.totalUsage, currentMessageUsage)
|
||
}
|
||
}
|
||
```
|
||
|
||
### 2.5 思考模式 (Thinking Mode)
|
||
|
||
Claude Code 支持 Claude 的思考模式:
|
||
|
||
```typescript
|
||
const initialThinkingConfig: ThinkingConfig = thinkingConfig
|
||
? thinkingConfig
|
||
: shouldEnableThinkingByDefault() !== false
|
||
? { type: 'adaptive' } // 自适应思考
|
||
: { type: 'disabled' } // 禁用
|
||
```
|
||
|
||
思考规则(注释中的说明):
|
||
1. 包含思考或编辑块的消息必须在 `max_thinking_length > 0` 的查询中
|
||
2. 思考块不能是消息块中的最后一个
|
||
3. 思考块必须在整个助手轨迹中保留
|
||
|
||
### 2.6 错误恢复机制
|
||
|
||
```typescript
|
||
// USD 预算超限检查
|
||
if (maxBudgetUsd !== undefined && getTotalCost() >= maxBudgetUsd) {
|
||
yield {
|
||
type: 'result',
|
||
subtype: 'error_max_budget_usd',
|
||
...
|
||
}
|
||
return
|
||
}
|
||
|
||
// 最大轮次检查
|
||
if (maxTurns && nextTurnCount > maxTurns) {
|
||
yield { type: 'result', subtype: 'error_max_turns', ... }
|
||
return
|
||
}
|
||
|
||
// 结构化输出重试限制
|
||
if (callsThisQuery >= maxRetries) {
|
||
yield { type: 'result', subtype: 'error_max_structured_output_retries', ... }
|
||
return
|
||
}
|
||
```
|
||
|
||
## 3. Tool.ts - 工具基类和接口定义
|
||
|
||
### 3.1 工具接口定义
|
||
|
||
```typescript
|
||
export type Tool<
|
||
Input extends AnyObject = AnyObject,
|
||
Output = unknown,
|
||
P extends ToolProgressData = ToolProgressData,
|
||
> = {
|
||
// 工具名称
|
||
readonly name: string
|
||
|
||
// 可选别名(用于工具重命名后的向后兼容)
|
||
aliases?: string[]
|
||
|
||
// 工具搜索提示词
|
||
searchHint?: string
|
||
|
||
// 核心执行方法
|
||
call(
|
||
args: z.infer<Input>,
|
||
context: ToolUseContext,
|
||
canUseTool: CanUseToolFn,
|
||
parentMessage: AssistantMessage,
|
||
onProgress?: ToolCallProgress<P>,
|
||
): Promise<ToolResult<Output>>
|
||
|
||
// 获取工具描述
|
||
description(
|
||
input: z.infer<Input>,
|
||
options: {...}
|
||
): Promise<string>
|
||
|
||
// 输入 Schema
|
||
readonly inputSchema: Input
|
||
|
||
// 输入 JSON Schema(用于 MCP 工具)
|
||
readonly inputJSONSchema?: ToolInputJSONSchema
|
||
|
||
// 输出 Schema
|
||
outputSchema?: z.ZodType<unknown>
|
||
}
|
||
```
|
||
|
||
### 3.2 工具权限方法
|
||
|
||
```typescript
|
||
// 验证输入是否有效
|
||
validateInput?(
|
||
input: z.infer<Input>,
|
||
context: ToolUseContext,
|
||
): Promise<ValidationResult>
|
||
|
||
// 检查权限
|
||
checkPermissions(
|
||
input: z.infer<Input>,
|
||
context: ToolUseContext,
|
||
): Promise<PermissionResult>
|
||
|
||
// 准备权限匹配器
|
||
preparePermissionMatcher?(
|
||
input: z.infer<Input>,
|
||
): Promise<(pattern: string) => boolean>
|
||
```
|
||
|
||
### 3.3 工具渲染方法
|
||
|
||
```typescript
|
||
// 渲染工具使用消息
|
||
renderToolUseMessage(
|
||
input: Partial<z.infer<Input>>,
|
||
options: { theme: ThemeName; verbose: boolean; commands?: Command[] }
|
||
): React.ReactNode
|
||
|
||
// 渲染工具结果消息
|
||
renderToolResultMessage?(
|
||
content: Output,
|
||
progressMessagesForMessage: ProgressMessage<P>[],
|
||
options: {...}
|
||
): React.ReactNode
|
||
|
||
// 渲染工具使用标签
|
||
renderToolUseTag?(input: Partial<z.infer<Input>>): React.ReactNode
|
||
|
||
// 渲染进度消息
|
||
renderToolUseProgressMessage?(
|
||
progressMessagesForMessage: ProgressMessage<P>[],
|
||
options: {...}
|
||
): React.ReactNode
|
||
```
|
||
|
||
### 3.4 buildTool 工厂函数
|
||
|
||
```typescript
|
||
const TOOL_DEFAULTS = {
|
||
isEnabled: () => true,
|
||
isConcurrencySafe: (_input?: unknown) => false,
|
||
isReadOnly: (_input?: unknown) => false,
|
||
isDestructive: (_input?: unknown) => false,
|
||
checkPermissions: async () => ({ behavior: 'allow', updatedInput: input }),
|
||
toAutoClassifierInput: (_input?: unknown) => '',
|
||
userFacingName: (_input?: unknown) => '',
|
||
}
|
||
|
||
export function buildTool<D extends AnyToolDef>(def: D): BuiltTool<D> {
|
||
return {
|
||
...TOOL_DEFAULTS,
|
||
userFacingName: () => def.name,
|
||
...def,
|
||
} as BuiltTool<D>
|
||
}
|
||
```
|
||
|
||
### 3.5 工具权限上下文
|
||
|
||
```typescript
|
||
export type ToolPermissionContext = {
|
||
mode: PermissionMode // 'default' | 'auto' | 'bypass' | 'plan'
|
||
additionalWorkingDirectories: Map<string, AdditionalWorkingDirectory>
|
||
alwaysAllowRules: ToolPermissionRulesBySource
|
||
alwaysDenyRules: ToolPermissionRulesBySource
|
||
alwaysAskRules: ToolPermissionRulesBySource
|
||
isBypassPermissionsModeAvailable: boolean
|
||
isAutoModeAvailable?: boolean
|
||
strippedDangerousRules?: ToolPermissionRulesBySource
|
||
shouldAvoidPermissionPrompts?: boolean
|
||
awaitAutomatedChecksBeforeDialog?: boolean
|
||
prePlanMode?: PermissionMode
|
||
}
|
||
```
|
||
|
||
## 4. commands.ts - 命令注册中心
|
||
|
||
### 4.1 功能概述
|
||
|
||
`commands.ts` 是 Claude Code 的命令注册中心,管理所有 slash commands(以 `/` 开头的命令)。
|
||
|
||
### 4.2 命令类型
|
||
|
||
```typescript
|
||
type CommandType =
|
||
| 'prompt' // 展开为提示发送给模型
|
||
| 'local' // 本地执行,返回文本
|
||
| 'local-jsx' // 本地执行,渲染 Ink UI
|
||
```
|
||
|
||
### 4.3 命令定义结构
|
||
|
||
```typescript
|
||
interface Command {
|
||
type: CommandType
|
||
name: string
|
||
aliases?: string[]
|
||
description: string
|
||
contentLength: number
|
||
source: 'builtin' | 'plugin' | 'bundled' | 'mcp' | ...
|
||
availability?: ('claude-ai' | 'console')[]
|
||
// ...
|
||
}
|
||
```
|
||
|
||
### 4.4 命令加载流程
|
||
|
||
```typescript
|
||
// 1. 获取技能目录命令
|
||
const skillDirCommands = await getSkillDirCommands(cwd)
|
||
|
||
// 2. 获取插件命令
|
||
const pluginCommands = await getPluginCommands()
|
||
|
||
// 3. 获取内置命令
|
||
const builtinCommands = COMMANDS()
|
||
|
||
// 4. 合并并过滤
|
||
const allCommands = [
|
||
...bundledSkills,
|
||
...builtinPluginSkills,
|
||
...skillDirCommands,
|
||
...workflowCommands,
|
||
...pluginCommands,
|
||
...pluginSkills,
|
||
...COMMANDS(),
|
||
]
|
||
|
||
// 5. 检查可用性要求
|
||
const filteredCommands = allCommands.filter(cmd =>
|
||
meetsAvailabilityRequirement(cmd)
|
||
)
|
||
|
||
// 6. 检查是否启用
|
||
.filter(cmd => isCommandEnabled(cmd))
|
||
```
|
||
|
||
### 4.5 远程安全命令
|
||
|
||
```typescript
|
||
export const REMOTE_SAFE_COMMANDS: Set<Command> = new Set([
|
||
session, exit, clear, help, theme, color, vim,
|
||
cost, usage, copy, btw, feedback, plan,
|
||
keybindings, statusline, stickers, mobile,
|
||
])
|
||
```
|
||
|
||
### 4.6 命令查找
|
||
|
||
```typescript
|
||
export function findCommand(
|
||
commandName: string,
|
||
commands: Command[],
|
||
): Command | undefined {
|
||
return commands.find(
|
||
_ =>
|
||
_.name === commandName ||
|
||
getCommandName(_) === commandName ||
|
||
_.aliases?.includes(commandName)
|
||
)
|
||
}
|
||
```
|
||
|
||
## 5. context.ts - 系统/用户上下文收集
|
||
|
||
### 5.1 功能概述
|
||
|
||
`context.ts` 负责收集系统上下文和用户上下文,这些上下文会被预置到每个对话的开头。
|
||
|
||
### 5.2 Git 状态收集
|
||
|
||
```typescript
|
||
export const getGitStatus = memoize(async (): Promise<string | null> => {
|
||
// 检查是否是 Git 仓库
|
||
const isGit = await getIsGit()
|
||
if (!isGit) return null
|
||
|
||
// 并行获取多个 Git 信息
|
||
const [branch, mainBranch, status, log, userName] = await Promise.all([
|
||
getBranch(),
|
||
getDefaultBranch(),
|
||
execFileNoThrow(gitExe(), ['status', '--short'], ...),
|
||
execFileNoThrow(gitExe(), ['log', '--oneline', '-n', '5'], ...),
|
||
execFileNoThrow(gitExe(), ['config', 'user.name'], ...),
|
||
])
|
||
|
||
return [
|
||
`Current branch: ${branch}`,
|
||
`Main branch: ${mainBranch}`,
|
||
`Git user: ${userName}`,
|
||
`Status:\n${truncatedStatus}`,
|
||
`Recent commits:\n${log}`,
|
||
].join('\n\n')
|
||
})
|
||
```
|
||
|
||
### 5.3 系统上下文
|
||
|
||
```typescript
|
||
export const getSystemContext = memoize(async () => {
|
||
const gitStatus = await getGitStatus()
|
||
|
||
// 缓存破坏注入(仅用于调试)
|
||
const injection = feature('BREAK_CACHE_COMMAND')
|
||
? getSystemPromptInjection()
|
||
: null
|
||
|
||
return {
|
||
...(gitStatus && { gitStatus }),
|
||
...(injection && { cacheBreaker: `[CACHE_BREAKER: ${injection}]` }),
|
||
}
|
||
})
|
||
```
|
||
|
||
### 5.4 用户上下文
|
||
|
||
```typescript
|
||
export const getUserContext = memoize(async () => {
|
||
// 获取 CLAUDE.md 文件内容
|
||
const shouldDisableClaudeMd = isEnvTruthy(process.env.CLAUDE_CODE_DISABLE_CLAUDE_MDS)
|
||
|| (isBareMode() && getAdditionalDirectoriesForClaudeMd().length === 0)
|
||
|
||
const claudeMd = shouldDisableClaudeMd
|
||
? null
|
||
: getClaudeMds(filterInjectedMemoryFiles(await getMemoryFiles()))
|
||
|
||
// 缓存 CLAUDE.md 内容供自动模式分类器使用
|
||
setCachedClaudeMdContent(claudeMd || null)
|
||
|
||
return {
|
||
...(claudeMd && { claudeMd }),
|
||
currentDate: `Today's date is ${getLocalISODate()}.`,
|
||
}
|
||
})
|
||
```
|
||
|
||
### 5.5 上下文缓存
|
||
|
||
所有上下文函数都使用 `memoize` 进行缓存,确保在一次对话中只计算一次:
|
||
|
||
```typescript
|
||
export const getSystemContext = memoize(async () => {...})
|
||
export const getUserContext = memoize(async () => {...})
|
||
export const getGitStatus = memoize(async () => {...})
|
||
```
|
||
|
||
## 6. cost-tracker.ts - Token 成本追踪
|
||
|
||
### 6.1 功能概述
|
||
|
||
`cost-tracker.ts` 负责追踪和计算 API 调用的 Token 使用量和成本。
|
||
|
||
### 6.2 核心数据结构
|
||
|
||
```typescript
|
||
type StoredCostState = {
|
||
totalCostUSD: number
|
||
totalAPIDuration: number
|
||
totalAPIDurationWithoutRetries: number
|
||
totalToolDuration: number
|
||
totalLinesAdded: number
|
||
totalLinesRemoved: number
|
||
lastDuration: number | undefined
|
||
modelUsage: { [modelName: string]: ModelUsage }
|
||
}
|
||
|
||
type ModelUsage = {
|
||
inputTokens: number
|
||
outputTokens: number
|
||
cacheReadInputTokens: number
|
||
cacheCreationInputTokens: number
|
||
webSearchRequests: number
|
||
costUSD: number
|
||
contextWindow: number
|
||
maxOutputTokens: number
|
||
}
|
||
```
|
||
|
||
### 6.3 成本计算
|
||
|
||
```typescript
|
||
export function addToTotalSessionCost(
|
||
cost: number,
|
||
usage: Usage,
|
||
model: string,
|
||
): number {
|
||
const modelUsage = addToTotalModelUsage(cost, usage, model)
|
||
addToTotalCostState(cost, modelUsage, model)
|
||
|
||
// 发送到 Statsig 计数器
|
||
getCostCounter()?.add(cost, { model })
|
||
getTokenCounter()?.add(usage.input_tokens, { ...attrs, type: 'input' })
|
||
getTokenCounter()?.add(usage.output_tokens, { ...attrs, type: 'output' })
|
||
|
||
// 处理 Advisor 使用量
|
||
for (const advisorUsage of getAdvisorUsage(usage)) {
|
||
const advisorCost = calculateUSDCost(advisorUsage.model, advisorUsage)
|
||
totalCost += addToTotalSessionCost(advisorCost, advisorUsage, advisorUsage.model)
|
||
}
|
||
return totalCost
|
||
}
|
||
```
|
||
|
||
### 6.4 成本格式化
|
||
|
||
```typescript
|
||
export function formatTotalCost(): string {
|
||
const costDisplay = formatCost(getTotalCostUSD())
|
||
|
||
return chalk.dim(`
|
||
Total cost: ${costDisplay}
|
||
Total duration (API): ${formatDuration(getTotalAPIDuration())}
|
||
Total duration (wall): ${formatDuration(getTotalDuration())}
|
||
Total code changes: ${linesAdded} lines added, ${linesRemoved} lines removed
|
||
${formatModelUsage()}
|
||
`)
|
||
}
|
||
```
|
||
|
||
### 6.5 会话成本保存/恢复
|
||
|
||
```typescript
|
||
// 保存当前会话成本到项目配置
|
||
export function saveCurrentSessionCosts(fpsMetrics?: FpsMetrics): void {
|
||
saveCurrentProjectConfig(current => ({
|
||
...current,
|
||
lastCost: getTotalCostUSD(),
|
||
lastAPIDuration: getTotalAPIDuration(),
|
||
lastLinesAdded: getTotalLinesAdded(),
|
||
lastLinesRemoved: getTotalLinesRemoved(),
|
||
lastModelUsage: Object.fromEntries(...),
|
||
lastSessionId: getSessionId(),
|
||
}))
|
||
}
|
||
|
||
// 恢复会话成本
|
||
export function restoreCostStateForSession(sessionId: string): boolean {
|
||
const data = getStoredSessionCosts(sessionId)
|
||
if (!data) return false
|
||
setCostStateForRestore(data)
|
||
return true
|
||
}
|
||
```
|
||
|
||
## 7. query.ts - 查询管道
|
||
|
||
### 7.1 功能概述
|
||
|
||
`query.ts` 是核心的查询处理管道,负责:
|
||
|
||
- 消息流式 API 调用
|
||
- 工具调用编排
|
||
- 自动压缩
|
||
- 错误恢复
|
||
|
||
### 7.2 主查询循环
|
||
|
||
```typescript
|
||
export async function* query(
|
||
params: QueryParams,
|
||
): AsyncGenerator<...> {
|
||
const consumedCommandUuids: string[] = []
|
||
const terminal = yield* queryLoop(params, consumedCommandUuids)
|
||
return terminal
|
||
}
|
||
|
||
async function* queryLoop(
|
||
params: QueryParams,
|
||
consumedCommandUuids: string[],
|
||
): AsyncGenerator<...> {
|
||
let state: State = {
|
||
messages: params.messages,
|
||
toolUseContext: params.toolUseContext,
|
||
autoCompactTracking: undefined,
|
||
maxOutputTokensRecoveryCount: 0,
|
||
// ...
|
||
}
|
||
|
||
while (true) {
|
||
// 1. 上下文压缩
|
||
const { compactionResult } = await deps.autocompact(...)
|
||
|
||
// 2. API 调用循环
|
||
for await (const message of deps.callModel({...})) {
|
||
if (message.type === 'assistant') {
|
||
assistantMessages.push(message)
|
||
// 处理工具调用块
|
||
}
|
||
}
|
||
|
||
// 3. 工具执行
|
||
if (needsFollowUp) {
|
||
const toolUpdates = runTools(toolUseBlocks, ...)
|
||
for await (const update of toolUpdates) {
|
||
// 处理工具结果
|
||
}
|
||
}
|
||
|
||
// 4. 递归继续
|
||
state = { ...state, messages: [...messages, ...assistantMessages, ...toolResults] }
|
||
}
|
||
}
|
||
```
|
||
|
||
### 7.3 工具执行编排
|
||
|
||
```typescript
|
||
// 两种工具执行模式
|
||
if (streamingToolExecutor) {
|
||
// 流式工具执行:在模型流式输出的同时执行工具
|
||
logEvent('tengu_streaming_tool_execution_used', {...})
|
||
} else {
|
||
// 批量工具执行:等待模型完全响应后执行
|
||
logEvent('tengu_streaming_tool_execution_not_used', {...})
|
||
}
|
||
|
||
const toolUpdates = streamingToolExecutor
|
||
? streamingToolExecutor.getRemainingResults()
|
||
: runTools(toolUseBlocks, assistantMessages, canUseTool, toolUseContext)
|
||
```
|
||
|
||
### 7.4 错误恢复机制
|
||
|
||
```typescript
|
||
// 1. 模型回退
|
||
if (innerError instanceof FallbackTriggeredError && fallbackModel) {
|
||
currentModel = fallbackModel
|
||
attemptWithFallback = true
|
||
continue
|
||
}
|
||
|
||
// 2. Prompt Too Long 恢复
|
||
if (isWithheld413) {
|
||
// 尝试排空上下文折叠
|
||
const drained = contextCollapse.recoverFromOverflow(...)
|
||
if (drained.committed > 0) {
|
||
state = { ...state, messages: drained.messages }
|
||
continue
|
||
}
|
||
|
||
// 尝试响应式压缩
|
||
const compacted = await reactiveCompact.tryReactiveCompact(...)
|
||
if (compacted) {
|
||
// ...
|
||
}
|
||
}
|
||
|
||
// 3. Max Output Tokens 恢复
|
||
if (maxOutputTokensRecoveryCount < MAX_OUTPUT_TOKENS_RECOVERY_LIMIT) {
|
||
const recoveryMessage = createUserMessage({
|
||
content: `Output token limit hit. Resume directly...`
|
||
})
|
||
state = { ...state, messages: [...messages, recoveryMessage] }
|
||
continue
|
||
}
|
||
```
|
||
|
||
### 7.5 上下文压缩
|
||
|
||
```typescript
|
||
// Snip(去除)压缩
|
||
if (feature('HISTORY_SNIP')) {
|
||
const snipResult = snipModule!.snipCompactIfNeeded(messagesForQuery)
|
||
messagesForQuery = snipResult.messages
|
||
snipTokensFreed = snipResult.tokensFreed
|
||
}
|
||
|
||
// 微压缩
|
||
const microcompactResult = await deps.microcompact(messagesForQuery, ...)
|
||
messagesForQuery = microcompactResult.messages
|
||
|
||
// 自动压缩
|
||
const { compactionResult } = await deps.autocompact(
|
||
messagesForQuery,
|
||
toolUseContext,
|
||
{ systemPrompt, userContext, systemContext, toolUseContext },
|
||
querySource,
|
||
tracking,
|
||
snipTokensFreed,
|
||
)
|
||
```
|
||
|
||
### 7.6 工具使用摘要
|
||
|
||
```typescript
|
||
// 为耗时的 Haiku 调用生成工具使用摘要
|
||
if (config.gates.emitToolUseSummaries && toolUseBlocks.length > 0) {
|
||
const summary = await generateToolUseSummary({
|
||
tools: toolInfoForSummary,
|
||
signal: toolUseContext.abortController.signal,
|
||
lastAssistantText,
|
||
})
|
||
|
||
// 异步生成,不阻塞下一个 API 调用
|
||
nextPendingToolUseSummary = summary.then(s =>
|
||
s ? createToolUseSummaryMessage(summary, toolUseIds) : null
|
||
)
|
||
}
|
||
```
|
||
|
||
## 8. 总结
|
||
|
||
这七个核心文件共同构成了 Claude Code 的核心架构:
|
||
|
||
| 文件 | 职责 |
|
||
|------|------|
|
||
| `main.tsx` | CLI 入口,应用程序初始化 |
|
||
| `QueryEngine.ts` | 对话生命周期管理,消息处理 |
|
||
| `Tool.ts` | 工具基类和接口定义 |
|
||
| `commands.ts` | Slash 命令注册和管理 |
|
||
| `context.ts` | 系统/用户上下文收集 |
|
||
| `cost-tracker.ts` | Token 成本追踪 |
|
||
| `query.ts` | API 调用管道,工具编排 |
|
||
|
||
理解这些核心模块是深入研究 Claude Code 源码的基础。
|