Grok Bot 核心流程解读
Grok Bot 核心流程解读
本文解读 source/ 中 Grok Bot(Grok Bot 0.18 重构版)的核心运行流程:从一条用户消息进入系统,到模型产生回复、执行工具、把结果发回用户,中间经历的状态机、循环、重试与总结机制。
面向对象:想理解这套 TypeScript 代码如何串起来的读者。文中所有路径均为仓库内相对路径。
1. 整体架构与进程拓扑
Grok Bot 是一个 Electron 桌面应用,逻辑上分成多层(对应 source/ 下的目录):
渲染进程 (shipped renderer, frontend/)
│ preload RPC (source/electron-preload/)
▼
Electron 主进程 (source/electron-main/)
│ 设置/密钥/认证/插件生命周期、远程 box 连接器、本地 Docker 连接器
▼
node-agent-coordinator (source/node-agent-coordinator/)
│ transcript 路由、流式 activity、reaction、routed MCP bridge、推理路由
▼
host (source/host/) —— 宿主运行器、system prompt 组装、auto-review、沙箱管理
│
├── runner/ (turn-run-shell / sand-agent-runner / turn-agent-composition)
│
▼
packages/agent (source/packages/agent/) —— Agent 核心:turn 循环、工具执行、总结、prompt 渲染
│
├── box-exec-daemon / local-exec-daemon —— 命令执行守护进程(远程 box 或本地 Docker)
▼
推理后端(inference): Cursor / Claude Code / Codex / OpenRouter
source/electron-main/:桌面生命周期、设置、认证、box 连接器、coordinator 所有权、RPC handler。source/electron-preload/:暴露给 UI 的窄受信桥。source/host/:推理、工具、MCP、设置、turn 执行。source/node-agent-coordinator/:transcript 路由、流式 activity、reaction、routed MCP bridge。source/shared/:共享契约、设置、协议、provider 辅助。source/packages/agent/:Agent 核心(本文重点)。
2. 核心概念与关键类型
2.1 几个中心类
| 类 / 文件 | 职责 |
|---|---|
AnysphereAgent(source/packages/agent/index.ts) | package 级 Agent 根,持有 action handler 注册表,入口为 runStream |
AbstractUserMessageActionHandler(source/packages/agent/actions/user-message-action/abstract-user-message-action-handler.ts) | 用户消息处理的核心基类:runStep、runTurnLoop、单步/分步执行 |
UserMessageActionHandler(同目录 user-message-action-handler.ts) | 具体实现:initializeConversation(组装 prompt)、handle |
ConversationStateHandle(source/packages/agent/state.ts) | 会话状态:turn、step、pending tool call、token 详情、模式 |
ToolSetHandle(source/packages/agent/tools/core.ts) | 工具集合:静态/动态/可执行工具、描述属性 |
InteractionHandler(source/packages/agent/interaction-handler.ts) | 把模型流(text/thinking/tool-call)翻译成 UI 更新(interaction updates) |
SummarizationOrchestrator(source/packages/agent/summarization-orchestrator.ts) | 背景/阻塞总结的编排 |
SandAgentRunner(source/host/runner/sand-agent-runner.ts) | 宿主侧的 agent 运行器(把宿主资源接进 packages/agent) |
2.2 Turn / Step / Action / Mode
- Action:一次“要执行什么”的请求。
AnysphereAgent里用一个Map注册了多种 action handler,runStream根据action.action.case选 handler:userMessageAction、resumeAction、summarizeAction、shellCommandAction、cancelAction、executePlanAction、goalContinuationAction、subscriptionNotificationAction、asyncAskQuestionCompletionAction、backgroundTaskCompletionAction、backgroundShellAction、backgroundSubagentAction。
- Turn:一个用户消息(或等价触发)驱动的一轮完整工作,可包含多个 step。
- Step:一次模型调用 + 随后的工具执行/结果回填。
- Mode(
AgentMode,见source/packages/agent/mode-processing.ts):AGENT/ASK/PLAN/DEBUG/TRIAGE/PROJECT/MULTITASK。模式决定部分 prompt 与工具过滤(例如 ASK 模式过滤编辑类工具)。
2.3 状态与消息
- 会话状态序列化为
ConversationStateStructure(protobuf,source/packages/proto/generated/agent/v1/agent_pb.js),在ConversationStateHandle中解包为可操作的 turn/step 引用。 - 消息用
CoreMessage(role: system/user/assistant/tool+ content parts),在 redacted / unredacted 两种形式间转换(隐私分级,见source/packages/redaction/)。 rootPromptExecutor(RedactedPromptToolExecutor/SimplePromptToolExecutor)持有并追加 prompt 消息,是模型调用与消息历史的唯一入口。
3. 一个回合(Turn)的完整生命周期
3.1 入口:AnysphereAgent.runStream
source/packages/agent/index.ts:
- 创建
RedactedPromptToolExecutor(promptSession.getExecutor())。 - 从序列化状态恢复
ConversationStateHandle(fromConversationStateStructure,加载 root prompt blobs)。 - 根据
action.action.case取出 handler。 runOne()执行 handler 的handle(),然后进入一个while(true)循环:从conversationActionReceiver.peek()取排队中的 action 逐个执行(每个排队的 action 都重新构建 state handler)。- 最后
interactionListener.sendUpdate(turnEnded(...)),flushPostTurnEndedWork,blobStore.flush。
3.2 UserMessageActionHandler.handle
source/packages/agent/actions/user-message-action/user-message-action-handler.ts:
async handle(ctx, action, rootPromptExecutor, stateHandler, mcpTools, onStateUpdate, options) {
await reactivatePausedGoalOnUserMessage(...) // 若之前目标被暂停,先恢复
const { turn, mergedMcpTools, requestContext } = await this.initializeConversation(...)
await this.runTurnLoop(ctx, rootPromptExecutor, stateHandler, turn, ...)
return await stateHandler.computeNewStructure(ctx) // 返回新状态
}
initializeConversation 是 prompt 组装的核心,顺序为:
resolveRequestContext—— 解析请求上下文(规则、env、git 仓库信息、MCP 描述等)。- 合并 request context 工具与 MCP 工具。
configAny.toolsGenerator(...)生成ToolSetHandle。- 处理
prependUserMessages(前置用户消息)。 - 生成 system prompt(
configAny.systemPromptGenerator({...}, toolSetHandle),见 PROMPTS.md)。 - 生成 UserInfo(第一条 user 消息,见 PROMPTS.md)—— 仅当首轮或需要重渲染时。
- 组装历史消息(conversation history、prior messages、被中断的 pending tool call)。
stateHandler.createAgentTurn(...)创建主 turn,设置 mode。
3.3 runTurnLoop:turn 级循环
abstract-user-message-action-handler.ts 中的 runTurnLoop:
for step in 0..maxSteps(package 默认 `MAX_AGENT_STEPS = 1000`,宿主 sand agent 用 `SAND_AGENT_MAX_STEPS = 5000`):
1. 若 mode 变化 → 追加 mode reminder(processModeSystemReminder)
2. executeStepWithMetrics → runStep(一次模型调用 + 工具执行)
3. applyPostStepProcessing(追加响应消息、reminder 注入、checkpoint 持久化)
4. 消费排队中的 action / 队列用户消息(consumeQueuedUserMessagesAndMaybeCreateNewTurns)
5. 可能注入 CLI reflect-general 后续 turn、Agent Store 冲突 barrier
6. 判断 hasEnded(无 tool call 且无排队消息,或到达 maxSteps)
7. 若结束 → 处理 background summarization 持久化/丢弃、发送 stepCompleted、收尾
8. 否则继续下一 step
关键点:
- mode 变化 会通过
stateHandler.generateModeChangeContent生成提醒注入(<system_reminder>形式)。 - 循环退出 条件是“本轮没有 tool call 且没有排队消息”。
doNotFailOnMaxSteps控制到达上限时是报错还是停止。 - 每 step 结束后都会持久化 checkpoint(
computeNewStructure+onStateUpdate,支持 fire-and-forget)。 - 收尾阶段统计 todo 完成情况、turn 时长、tool call 数量等指标,并触发 prompt suggestion(如果开启)。
3.4 runStep:一次模型调用 + 工具执行
runStep 是单次 step 的核心:
- 构建
InteractionHandler(绑定 interaction listener、turn、invocationId、thinking style、loop detection)。 - 解析当前 mode(
resolveCurrentStepMode)。 toolsGenerator(...)生成工具集。- 取
initialMessages(当前 root prompt executor 的消息)。 trackPromptTokenUsage记录 prompt token 使用。rootPromptExecutor.executeToolStream(...)—— 真正的模型流式调用 + 工具执行。interactionHandler.consumeStream(...)消费全流(text-delta / thinking-delta / tool-call)。- 更新 token 详情(
setTokenDetails)。 - 检查空响应(empty response)并可能触发重试(见 3.7)。
- 返回
{ hasToolCall, responseMessages }。
3.5 executeToolStream:模型调用与工具执行循环
source/packages/agent/tool-stream-executor.ts:
streamModelAndCollectToolCalls请求模型,流式产出文本/思考/工具调用。- 若模型返回 tool call:
executeDeferredToolCall逐个执行工具(source/packages/agent/tool-stream-executor.ts中的executeDeferredToolCall,见 3.6)。 SimplePromptToolExecutor/RedactedPromptToolExecutor是 executor 的两种包装(后者按 privacy mode 对消息做 redact)。- 相关方法:
executeToolStream(模型流 + 工具)、executeModelStreamOnly(仅模型,不分步)、executeDeferredToolCall(执行单个延迟工具调用)。
3.6 工具执行:executeDeferredToolCall 与 ToolSetHandle
- 工具通过
toolsGenerator生成,返回ToolSetHandle(source/packages/agent/tools/core.ts):getStaticTools()/getAllTools()/getToolExecutionSet()(model-visible + additional executable)。- 静态工具按
toolIdentifier组织(WRITE、READ、SHELL、STR_REPLACE、APPLY_PATCH、TASK、SEND_MESSAGE、GREP、GLOB、MCP、REFLECT、ASK_QUESTION等,见source/packages/agent/tools/all-tools.ts)。
- 工具执行会经过:
- 权限/auto-review 门(宿主的
sand-auto-review.ts等,命令执行前安全检查)。 InteractionHandler.recordToolCallResult(把结果作为 tool message 回填给模型)。executeToolResultOrError/renderToolResultOrError(错误分类与结果渲染,tools/core.ts)。
- 权限/auto-review 门(宿主的
3.7 重试与容错
AbstractUserMessageActionHandler 内置三层重试:
runWithMaxTokensRetry:捕获OutputTokensLimitExceededError,追加<system_reminder>Your response was cut off...后重试;同时处理空响应重试(EmptyResponseRetryError)与单消息循环(AgentLoopError)。runWithSummarizationRetry:在 token 超限 / 图片超限 / proactive 总结阈值触发时,执行阻塞式总结(WaitForCompletion)压缩上下文后重试,最多 5 次。- 空响应分类:模型产出空文本时按“最后一条消息角色 / 是否有 thinking / 是否欠 SendMessage”等维度分类(
retry_tool_result/retry_user_msg/retry_no_output_tokens/retry_thinking_only/fallthrough),决定是否注入 continuation message 重试。
3.8 applyPostStepProcessing:step 收尾
- 若有 tool call 且配置了 reminders →
applyRemindersToToolResults(把 reminder 注入工具结果)。 - 可选 tool-call id 打标(
appendToolCallIdTagsToToolResults)。 turn.appendPromptMessages(...)追加本 step 的响应消息。- 可选
messageHistoryModifier重写历史。 - 可选 grind phase override 时重建 system prompt。
- 持久化 checkpoint(
computeNewStructure+onStateUpdate)。
4. 单步 / 分步(split-step)执行模型
除了 runStream 的全流程,AnysphereAgent 还暴露分步接口,供宿主把“模型调用”和“工具执行”拆开(例如把工具执行放到宿主侧做 auto-review):
| 方法 | 作用 |
|---|---|
runSingleStep | 执行一个完整 step(模型 + 工具),返回 hasToolCall |
runModelStep | 只跑模型,返回 toolCallDescriptors + splitStepData |
executeToolCall | 执行单个工具调用(基于 splitStepData 的 allowlist) |
prepareSubagent | 为 subagent 工具调用做准备 |
finalizeStep | 汇总模型响应 + 工具结果,收尾 step |
对应的 handler 内方法(AbstractUserMessageActionHandler):
runSingleStep / runModelStep / runModelOnlyStep / executeToolCall / buildToolExecutionContext / finalizeStep。
这一模型用于宿主(host)侧的 turn-run-shell / sand-agent-runner:宿主需要在下发工具执行前做 auto-review 等安全检查。
5. 总结(Summarization)
SummarizationOrchestrator(source/packages/agent/summarization-orchestrator.ts)+ source/packages/agent-summarization/ 负责在上下文逼近 token 上限时压缩历史:
- 背景总结(Background):step 结束后异步触发(
shouldStartBackgroundSummarization),不阻塞当前 turn。 - 持久化(BackgroundAndPersistIfCompleted):总结完成后写回状态(threshold 满足时)。
- 阻塞等待(WaitForCompletion):token 严重超限 / 图片超限 / 模型报 token 错误时,阻塞到总结完成再继续。
- 触发原因(
triggerReason):approaching_token_limit/approaching_image_limit/significantly_over_token_limit/input_token_limit_error/fallback_on_limit_error/self_summary_completed/force_dev_testing等。 - 自总结(self-summary)失败时可回退到外部模型总结(
forceExternalModel)。
runTurnLoop 在 turn 结束时根据“是否满足持久化阈值”“总结是否已完成”决定持久化或丢弃([summarization-persist] / [summarization-discard] 日志)。
6. Action Handler 注册表
AnysphereAgent 构造函数(source/packages/agent/index.ts)注册:
| case | Handler | 说明 |
|---|---|---|
userMessageAction | UserMessageActionHandler | 主用户消息 |
subscriptionNotificationAction | SubscriptionNotificationActionHandler | 订阅通知(复用 user handler) |
goalContinuationAction | GoalContinuationActionHandler | 目标继续 |
resumeAction | ResumeActionHandler | 恢复 |
summarizeAction | SummarizeActionHandler | 手动总结 |
shellCommandAction | ShellCommandActionHandler | Shell 命令 |
cancelAction | CancelActionHandler | 取消 |
executePlanAction | ExecutePlanActionHandler | 执行计划 |
asyncAskQuestionCompletionAction | AsyncAskQuestionCompletionActionHandler | 异步问题完成 |
backgroundTaskCompletionAction | BackgroundTaskCompletionActionHandler | 后台任务完成 |
backgroundShellAction | BackgroundShellActionHandler | 后台 shell |
backgroundSubagentAction | BackgroundSubagentActionHandler | 后台 subagent |
7. 推理路由(Inference Router)
重构版新增了“推理路由”,在 Settings → Router 选择后端(source/node-agent-coordinator/inference-router.ts、source/shared/inference-router.ts、source/host/extensions/inference/provider-session.ts):
| Provider | 说明 | 工具支持 |
|---|---|---|
cursor | 默认,复用已有 Grok Bot/Cursor 会话 | 原生工具 + 插件 |
claude-code | 复用本地 Claude Code 登录 | 经 routed MCP bridge 的 Grok Bot MCP 工具 |
codex | 复用本地 ChatGPT/Codex 登录 | Direct Responses transport + Grok Bot 工具 |
openrouter | API key(经桌面 secrets bridge 保存) | Grok Bot 工具执行循环 |
createCoordinatorInferenceRouter在sendPrompt时对非 cursor provider 走runRoutedProviderText,把 Grok Bot 工具以 MCP/工具定义形式交给对应 provider 执行。createRoutedMcpBridge(source/node-agent-coordinator/routed-mcp-bridge.ts)为 claude-code 提供mcp__grok_bot_plugins__*工具。- 用量记录在
settings.json(recordInferenceUsage,见source/shared/inference-router.ts的SandInferenceRouterUsage)。
8. 沙箱与执行守护进程
source/box-exec-daemon/:远程 box 执行守护进程(命令在远程沙箱中执行)。source/local-exec-daemon/:本地执行守护进程。- 本地 Docker 沙箱(Settings → Use local Docker VM):宿主 box 与执行 daemon 跑在自有本地容器中,仅绑定 loopback 端口,挂载 content-addressed 产物只读,连接前校验,随设置生命周期启停。
- 命令执行默认先经 auto-review 安全检查(
source/host/runner/sand-auto-review.ts等),被拦截时按 system prompt 中的规则适配或升级审批(详见 PROMPTS.md 的“安全/Auto-review”小节)。
9. 阅读建议
按下面顺序读源码最快上手:
source/packages/agent/index.ts(入口 + handler 注册)source/packages/agent/actions/user-message-action/user-message-action-handler.ts(initializeConversation+handle)source/packages/agent/actions/user-message-action/abstract-user-message-action-handler.ts(runTurnLoop/runStep/ 重试)source/packages/agent/tool-stream-executor.ts(模型流 + 工具执行)source/packages/agent/tools/core.ts(ToolSetHandle)source/packages/agent/state.ts(ConversationStateHandle)source/packages/agent/summarization-orchestrator.ts(总结)source/host/runner/system-prompt-assembly.ts+source/host/runner/system-prompt.ts(system prompt,配合 PROMPTS.md)source/node-agent-coordinator/inference-router.ts(推理路由)
Prompt 体系的详细解读见 PROMPTS
,行为特点见 CHARACTER
,执行面见 EXECUTION
,安全机制见 SAFETY
,多智能体与路由见 AGENTS
,运行时机制见 RUNTIME
。