Claude-Code源代码解读
Claude-Code的核心流程为:
用户输入 -> QueryEngine -> Agent-Loop
其中
QueryEngine: 管理会话的模块 定义于QueryEngine.tsAgent-Loop: Agent最重要的循环. 定义于query.ts
QueryEngine.ts
负责:
整个conversation的历史
将用户的输入进行分类 比如普通消息 或者
/model等命令构造Context 这一步很重要 组装了各种层级的上下文 各种工具的列表 各种插件的列表
进入Agent Loop
统计运行时的状态 比如权限, token花的钱, 最大循环 防止无限循环
将模型传回的事件进行分类 比如模型要调用MCP 或者skill 或者cli等 将模型的消息转换为工具调用类型
流程为:
submitMessage()接收输入 -> 将系统命令/model等与自然语言消息分类
-> getSystemContext(),getUserContext()构造Context -> 封装tools commands Agents等
-> 构造query()参数 -> 调用query() -> 持续接收query的事件并消耗 进行工具调用等
QueryEngineConfig
QueryEngine 所需要的整个 Agent Runtime 的接口.
export type QueryEngineConfig = {
cwd: string
tools: Tools
commands: Command[]
mcpClients: MCPServerConnection[]
agents: AgentDefinition[]
canUseTool: CanUseToolFn
getAppState: () => AppState
setAppState: (f: (prev: AppState) => AppState) => void
initialMessages?: Message[]
readFileCache: FileStateCache
customSystemPrompt?: string
appendSystemPrompt?: string
userSpecifiedModel?: string
fallbackModel?: string
thinkingConfig?: ThinkingConfig
maxTurns?: number
maxBudgetUsd?: number
taskBudget?: { total: number }
jsonSchema?: Record<string, unknown>
verbose?: boolean
replayUserMessages?: boolean
/** Handler for URL elicitations triggered by MCP tool -32042 errors. */
handleElicitation?: ToolUseContext['handleElicitation']
includePartialMessages?: boolean
setSDKStatus?: (status: SDKStatus) => void
abortController?: AbortController
orphanedPermission?: OrphanedPermission
/**
* Snip-boundary handler: receives each yielded system message plus the
* current mutableMessages store. Returns undefined if the message is not a
* snip boundary; otherwise returns the replayed snip result. Injected by
* ask() when HISTORY_SNIP is enabled so feature-gated strings stay inside
* the gated module (keeps QueryEngine free of excluded strings and testable
* despite feature() returning false under bun test). SDK-only: the REPL
* keeps full history for UI scrollback and projects on demand via
* projectSnippedView; QueryEngine truncates here to bound memory in long
* headless sessions (no UI to preserve).
*/
snipReplay?: (
yieldedSystemMsg: Message,
store: Message[],
) => { messages: Message[]; executed: boolean } | undefined
}
for await (const message of query(...))
接收query()产生的事件流 然后维护状态
for await (const message of query({...})) {
// 1. 保存/更新 conversation 状态
if (message.type === 'assistant' ||
message.type === 'user') {
messages.push(message)
mutableMessages.push(message)
}
// 2. 处理模型输出
if (message.type === 'assistant') {
// 把内部消息转换成 SDK 对外消息
yield normalizeMessage(message)
continue
}
// 3. 处理流式输出
if (message.type === 'stream_event') {
// 更新 token usage
// 更新 stop_reason
if (includePartialMessages) {
yield message
}
continue
}
// 4. 处理工具/其他附件产生的事件
if (message.type === 'attachment') {
messages.push(message)
mutableMessages.push(message)
if (message.attachment.type === 'structured_output') {
保存 structured output
}
if (message.attachment.type === 'max_turns_reached') {
yield ERROR_MAX_TURNS
return
}
continue
}
// 5. 处理系统事件
if (message.type === 'system') {
if (message.subtype === 'compact_boundary') {
压缩/清理 conversation
yield compact_boundary
}
if (message.subtype === 'api_error') {
yield api_retry
}
continue
}
// 6. 处理工具调用摘要
if (message.type === 'tool_use_summary') {
yield tool_use_summary
continue
}
// 7. 检查全局限制
if (超过 maxBudgetUsd) {
yield ERROR_MAX_BUDGET
return
}
if (超过 structured_output retry limit) {
yield ERROR_MAX_RETRIES
return
}
}
query.ts
Agent-Loop的主要定义
async function* query(context) {
messages = context.messages
while (true) {
// ① 把当前完整上下文发送给模型
response = await callLLM({
messages,
tools,
systemPrompt,
})
// ② 处理模型产生的内容
for (const block of response) {
if (block.type === "text") {
yield assistant_message(block)
}
if (block.type === "tool_use") {
// ③ 模型决定调用工具
toolResult = await executeTool(
block.name,
block.input
)
// ④ 把工具结果加入 conversation
messages.push(
assistant_tool_use(block)
)
messages.push(
tool_result(toolResult)
)
}
}
// ⑤ 如果模型没有要求继续调用工具
if (!response.hasToolUse) {
break
}
// 否则回到 while,再次调用 LLM
}
}
context.ts
在QueryEngine调用query()之前 将提示词封装.
封装后的提示词包含以下层级
┌──────────────────────────────────────┐
│ System Prompt │
│ │
│ ├─ Claude Code 核心系统指令 │
│ ├─ 工具使用规则 │
│ ├─ Agent 行为规范 │
│ ├─ Tool / MCP 相关说明 │
│ ├─ Skill / Command 相关说明 │
│ └─ User/System Context │
│ ├─ git status │
│ ├─ CLAUDE.md │
│ ├─ 当前日期 │
│ └─ cache breaker(特殊情况) │
├──────────────────────────────────────┤
│ Conversation History │
│ │
│ ├─ user messages │
│ ├─ assistant messages │
│ ├─ tool_use │
│ ├─ tool_result │
│ ├─ progress │
│ └─ compact boundary 后的历史 │
├──────────────────────────────────────┤
│ Current User Message │
│ │
│ └─ 用户这一次输入 │
├──────────────────────────────────────┤
│ Tools │
│ │
│ ├─ Bash │
│ ├─ Read │
│ ├─ Edit │
│ ├─ Write │
│ ├─ Glob │
│ ├─ Grep │
│ └─ MCP tools │
├──────────────────────────────────────┤
│ Commands / Skills / Agents │
│ │
│ ├─ slash commands (/model ...) │
│ ├─ skills │
│ └─ sub-agents │
└──────────────────────────────────────┘
system prompt
在constants/prompts.ts
function getSimpleIntroSection(outputStyleConfig: OutputStyleConfig | null): string {
return `
You are an interactive agent that helps users ${
outputStyleConfig !== null
? 'according to your "Output Style" below, which describes how you should respond to user queries.'
: 'with software engineering tasks.'
} Use the instructions below and the tools available to you to assist the user.
IMPORTANT: You must NEVER generate or guess URLs for the user unless you are confident that the URLs are for helping the user with programming.`
}
state/AppStateStore.ts
运行时状态
核心为下面的层级
AppStateStore
│
├── Model
│ ├── model
│ ├── thinking
│ └── effort
│
├── Tools
│ ├── MCP tools
│ ├── commands
│ └── tool permissions
│
├── Agents
│ ├── agent definitions
│ ├── tasks
│ ├── teammates
│ └── agent registry
│
├── Plugins
│ ├── enabled plugins
│ ├── plugin commands
│ └── plugin errors
│
├── Session
│ ├── hooks
│ ├── messages / initial message
│ ├── todos
│ └── notifications
│
├── Files
│ ├── file history
│ └── attribution
│
└── Runtime
├── permissions
├── remote state
├── speculation
└── various feature state
AppStateStore
│
├── settings
│ ├── 用户配置
│ ├── 权限配置
│ ├── 模型配置
│ └── 其他 CLI / UI settings
│
├── model state
│ ├── mainLoopModel
│ ├── mainLoopModelForSession
│ ├── thinkingEnabled
│ ├── effortValue
│ ├── fastMode
│ └── advisorModel
│
├── tool / permission state
│ ├── toolPermissionContext
│ ├── denialTracking
│ ├── workerSandboxPermissions
│ ├── pendingWorkerRequest
│ ├── pendingSandboxRequest
│ ├── replBridgePermissionCallbacks
│ └── channelPermissionCallbacks
│
├── MCP state
│ ├── mcp.clients
│ ├── mcp.tools
│ ├── mcp.commands
│ ├── mcp.resources
│ └── pluginReconnectKey
│
├── Plugin state
│ ├── plugins.enabled
│ ├── plugins.disabled
│ ├── plugins.commands
│ ├── plugins.errors
│ ├── plugins.installationStatus
│ └── plugins.needsRefresh
│
├── Agent state
│ ├── agentDefinitions
│ ├── agentNameRegistry
│ ├── standaloneAgentContext
│ ├── teamContext
│ ├── tasks
│ ├── todos
│ ├── inbox
│ └── remoteAgentTaskSuggestions
│
├── Conversation / Session state
│ ├── initialMessage
│ ├── sessionHooks
│ ├── notifications
│ ├── elicitation
│ ├── promptSuggestion
│ ├── skillImprovement
│ └── authVersion
│
├── File / Git state
│ ├── fileHistory
│ └── attribution
│
├── UI state
│ ├── verbose
│ ├── expandedView
│ ├── isBriefOnly
│ ├── footerSelection
│ ├── activeOverlays
│ ├── spinnerTip
│ ├── statusLineText
│ ├── selectedIPAgentIndex
│ └── coordinatorTaskIndex
│
├── Remote / Bridge state
│ ├── remoteSessionUrl
│ ├── remoteConnectionStatus
│ ├── remoteBackgroundTaskCount
│ ├── replBridgeEnabled
│ ├── replBridgeConnected
│ ├── replBridgeSessionActive
│ ├── replBridgeSessionUrl
│ ├── replBridgeError
│ └── ...
│
├── Speculation state
│ ├── speculation
│ └── speculationSessionTimeSavedMs
│
├── Tmux / Browser / Computer-use state
│ ├── tungsten...
│ ├── bagel...
│ └── computerUseMcpState
│
└── Ultraplan state
├── ultraplanLaunching
├── ultraplanSessionUrl
├── ultraplanPendingChoice
├── ultraplanLaunchPending
└── isUltraplanMode
Tool.ts
工具抽象层
统一工具的输入 输出 上下文与权限语义