{
  "projects": {
    "cc": {
      "label": "Claude Code 2.1.88 提取快照",
      "repo": "Aias00/claude-code-source-book",
      "commit": "08d220798172bb8161199e4cac9bc4aada3cca2e"
    },
    "dsh": {
      "label": "DeepSeek Harness",
      "repo": "deepseek-ai/deepseek-harness",
      "commit": "687f282e8625c6b8d11ff58211a90524be2e4317"
    },
    "pi": {
      "label": "Pi",
      "repo": "earendil-works/pi",
      "commit": "16f5f0af4d85ca583d045ceb5ed6d646fcaf7761"
    },
    "codex": {
      "label": "Codex",
      "repo": "openai/codex",
      "commit": "57d4fac64adbcaed0523ca6bf8d58c4ef6875157"
    }
  },
  "references": [
    {
      "id": "cc-entry",
      "project": "cc",
      "path": "source/entrypoints/cli.tsx",
      "start": 31,
      "end": 45,
      "url": "https://github.com/Aias00/claude-code-source-book/blob/08d220798172bb8161199e4cac9bc4aada3cca2e/source/entrypoints/cli.tsx#L31-L45",
      "sha256": "87d4d49ed7512cf225d074e8f41aa3fb2f69eed19b9199e7eb30ddfd252a324f",
      "excerpt": " * Fast-path for --version has zero imports beyond this file.\n */\nasync function main(): Promise<void> {\n  const args = process.argv.slice(2);\n\n  // Fast-path for --version/-v: zero module loading needed\n  if (args.length === 1 && (args[0] === '--version' || args[0] === '-v' || args[0] === '-V')) {\n    // MACRO.VERSION is inlined at build time\n    // biome-ignore lint/suspicious/noConsole:: intentional console output\n    console.log(`${MACRO.VERSION} (Claude Code)`);\n    return;\n  }\n\n  // For all other paths, load the startup profiler\n  const {\n",
      "excerpt_sha256": "420b9e2961248d289ad79f5474549e95d4bfdd7d86f1354087406b8f94274da1",
      "observation": "快速路径与动态导入将轻量参数处理和完整 CLI 加载分开。"
    },
    {
      "id": "cc-loop",
      "project": "cc",
      "path": "source/query.ts",
      "start": 239,
      "end": 253,
      "url": "https://github.com/Aias00/claude-code-source-book/blob/08d220798172bb8161199e4cac9bc4aada3cca2e/source/query.ts#L239-L253",
      "sha256": "74e0ce0d86cfd453add8dc1d15ccb6311b02964b8321e3721b8e71fbd87252ce",
      "excerpt": "}\n\nasync function* queryLoop(\n  params: QueryParams,\n  consumedCommandUuids: string[],\n): AsyncGenerator<\n  | StreamEvent\n  | RequestStartEvent\n  | Message\n  | TombstoneMessage\n  | ToolUseSummaryMessage,\n  Terminal\n> {\n  // Immutable params — never reassigned during the query loop.\n  const {\n",
      "excerpt_sha256": "354e1d505baf7a8ff7a4d950ce5c4147bbbdfde9c5014bfac70d77e9dd5af580",
      "observation": "异步生成器驱动对话循环；完整控制流需连同依赖与停止条件阅读。"
    },
    {
      "id": "cc-engine",
      "project": "cc",
      "path": "source/QueryEngine.ts",
      "start": 182,
      "end": 196,
      "url": "https://github.com/Aias00/claude-code-source-book/blob/08d220798172bb8161199e4cac9bc4aada3cca2e/source/QueryEngine.ts#L182-L196",
      "sha256": "7df34a6a6d106927403d49e3405dfaf70da37cae5b644b658ebaf0b877988af6",
      "excerpt": " * persists across turns.\n */\nexport class QueryEngine {\n  private config: QueryEngineConfig\n  private mutableMessages: Message[]\n  private abortController: AbortController\n  private permissionDenials: SDKPermissionDenial[]\n  private totalUsage: NonNullableUsage\n  private hasHandledOrphanedPermission = false\n  private readFileState: FileStateCache\n  // Turn-scoped skill discovery tracking (feeds was_discovered on\n  // tengu_skill_tool_invocation). Must persist across the two\n  // processUserInputContext rebuilds inside submitMessage, but is cleared\n  // at the start of each submitMessage to avoid unbounded growth across\n  // many turns in SDK mode.\n",
      "excerpt_sha256": "e44e11451bea819f27b15ca43af8e7ad62bdb50b019cc3cc461662c361c9b2f6",
      "observation": "会话级编排由 QueryEngine 提供，区别于单次模型请求。"
    },
    {
      "id": "cc-stream",
      "project": "cc",
      "path": "source/services/tools/StreamingToolExecutor.ts",
      "start": 38,
      "end": 52,
      "url": "https://github.com/Aias00/claude-code-source-book/blob/08d220798172bb8161199e4cac9bc4aada3cca2e/source/services/tools/StreamingToolExecutor.ts#L38-L52",
      "sha256": "ee17dce704af73787c9ed76dbbc638167521e5c1f68c9436149378bb3358601c",
      "excerpt": " * - Results are buffered and emitted in the order tools were received\n */\nexport class StreamingToolExecutor {\n  private tools: TrackedTool[] = []\n  private toolUseContext: ToolUseContext\n  private hasErrored = false\n  private erroredToolDescription = ''\n  // Child of toolUseContext.abortController. Fires when a Bash tool errors\n  // so sibling subprocesses die immediately instead of running to completion.\n  // Aborting this does NOT abort the parent — query.ts won't end the turn.\n  private siblingAbortController: AbortController\n  private discarded = false\n  // Signal to wake up getRemainingResults when progress is available\n  private progressAvailableResolve?: () => void\n\n",
      "excerpt_sha256": "c85a2b45142c6c94badaf6af04764cb90cb8d17b5b7439859e8c04837d1ddd78",
      "observation": "工具执行状态、进度与取消属于专门的执行器。"
    },
    {
      "id": "cc-permission",
      "project": "cc",
      "path": "source/hooks/useCanUseTool.tsx",
      "start": 25,
      "end": 39,
      "url": "https://github.com/Aias00/claude-code-source-book/blob/08d220798172bb8161199e4cac9bc4aada3cca2e/source/hooks/useCanUseTool.tsx#L25-L39",
      "sha256": "3689b30326118e94bb53a8cc1fa1761d1c0b1bff6489162f1dd0771ec8b8b953",
      "excerpt": "import { createPermissionContext, createPermissionQueueOps } from './toolPermission/PermissionContext.js';\nimport { logPermissionDecision } from './toolPermission/permissionLogging.js';\nexport type CanUseToolFn<Input extends Record<string, unknown> = Record<string, unknown>> = (tool: ToolType, input: Input, toolUseContext: ToolUseContext, assistantMessage: AssistantMessage, toolUseID: string, forceDecision?: PermissionDecision<Input>) => Promise<PermissionDecision<Input>>;\nfunction useCanUseTool(setToolUseConfirmQueue, setToolPermissionContext) {\n  const $ = _c(3);\n  let t0;\n  if ($[0] !== setToolPermissionContext || $[1] !== setToolUseConfirmQueue) {\n    t0 = async (tool, input, toolUseContext, assistantMessage, toolUseID, forceDecision) => new Promise(resolve => {\n      const ctx = createPermissionContext(tool, input, toolUseContext, assistantMessage, toolUseID, setToolPermissionContext, createPermissionQueueOps(setToolUseConfirmQueue));\n      if (ctx.resolveIfAborted(resolve)) {\n        return;\n      }\n      const decisionPromise = forceDecision !== undefined ? Promise.resolve(forceDecision) : hasPermissionsToUseTool(tool, input, toolUseContext, assistantMessage, toolUseID);\n      return decisionPromise.then(async result => {\n        if (result.behavior === \"allow\") {\n",
      "excerpt_sha256": "c945b03b284637ed0e0ccf83f0783c3452d46b4de5eeba41d24720a2a933a105",
      "observation": "工具授权是带工具输入和执行上下文的决策接口。"
    },
    {
      "id": "cc-budget",
      "project": "cc",
      "path": "source/utils/toolResultStorage.ts",
      "start": 922,
      "end": 936,
      "url": "https://github.com/Aias00/claude-code-source-book/blob/08d220798172bb8161199e4cac9bc4aada3cca2e/source/utils/toolResultStorage.ts#L922-L936",
      "sha256": "db2bf39064319eefccebf49cf5c4521b42a13bc63caf2c57b21113f6204e6bcd",
      "excerpt": " *   when the feature is off or no replacement occurred.\n */\nexport async function applyToolResultBudget(\n  messages: Message[],\n  state: ContentReplacementState | undefined,\n  writeToTranscript?: (records: ToolResultReplacementRecord[]) => void,\n  skipToolNames?: ReadonlySet<string>,\n): Promise<Message[]> {\n  if (!state) return messages\n  const result = await enforceToolResultBudget(messages, state, skipToolNames)\n  if (result.newlyReplaced.length > 0) {\n    writeToTranscript?.(result.newlyReplaced)\n  }\n  return result.messages\n}\n",
      "excerpt_sha256": "342a68a339e5487aa1e7958d91a4caf55ef413b17577b2b577d322a8ff882ed4",
      "observation": "工具输出预算与持久化替换不等同于模型摘要。"
    },
    {
      "id": "cc-compact",
      "project": "cc",
      "path": "source/services/compact/autoCompact.ts",
      "start": 158,
      "end": 172,
      "url": "https://github.com/Aias00/claude-code-source-book/blob/08d220798172bb8161199e4cac9bc4aada3cca2e/source/services/compact/autoCompact.ts#L158-L172",
      "sha256": "1946b5ea23fa2eda91955378641258fb8f19e7742f06ce17d6caae7f2d3c921a",
      "excerpt": "}\n\nexport async function shouldAutoCompact(\n  messages: Message[],\n  model: string,\n  querySource?: QuerySource,\n  // Snip removes messages but the surviving assistant's usage still reflects\n  // pre-snip context, so tokenCountWithEstimation can't see the savings.\n  // Subtract the rough-delta that snip already computed.\n  snipTokensFreed = 0,\n): Promise<boolean> {\n  // Recursion guards. session_memory and compact are forked agents that\n  // would deadlock.\n  if (querySource === 'session_memory' || querySource === 'compact') {\n    return false\n",
      "excerpt_sha256": "d7b8b99d03d1fb1bec2fc96e97e85fd23265220347d68c09e29b7fd575a6452b",
      "observation": "自动压缩有独立触发判断，不能把日志长度直接当作请求长度。"
    },
    {
      "id": "cc-storage",
      "project": "cc",
      "path": "source/utils/sessionStorage.ts",
      "start": 137,
      "end": 151,
      "url": "https://github.com/Aias00/claude-code-source-book/blob/08d220798172bb8161199e4cac9bc4aada3cca2e/source/utils/sessionStorage.ts#L137-L151",
      "sha256": "8a123ebce1ee72b9081d34b8f3697e5fcc9c7576df5b98e4206bb28414134412",
      "excerpt": " * messages on resume (see #14373, #23537).\n */\nexport function isTranscriptMessage(entry: Entry): entry is TranscriptMessage {\n  return (\n    entry.type === 'user' ||\n    entry.type === 'assistant' ||\n    entry.type === 'attachment' ||\n    entry.type === 'system'\n  )\n}\n\n/**\n * Entries that participate in the parentUuid chain. Used on the write path\n * (insertMessageChain, useLogMessages) to skip progress when assigning\n * parentUuid. Old transcripts with progress already in the chain are handled\n",
      "excerpt_sha256": "2ab2ac16ca879afe8c29aa74d944e078d74dff6b9393d2e315a2a99f59956936",
      "observation": "持久化条目有自身类型边界，不是所有 UI 进度都等于对话正文。"
    },
    {
      "id": "dsh-agent",
      "project": "dsh",
      "path": "packages/core/agent-loop/src/agent.ts",
      "start": 96,
      "end": 110,
      "url": "https://github.com/deepseek-ai/deepseek-harness/blob/687f282e8625c6b8d11ff58211a90524be2e4317/packages/core/agent-loop/src/agent.ts#L96-L110",
      "sha256": "4add12f5c22bb1b8cf1dbc239c9b09fa3351feff2c936cb2b8900036468bd01b",
      "excerpt": "\n/** Drives one session through turn and step boundaries. */\nexport class ReactLoopAgent implements Agent {\n  readonly inbox: ReactLoopInbox\n  private phase: Phase\n  private activityDone: Promise<void> = Promise.resolve()\n\n  /** The agent-scoped registration boundary; the lifecycle owner unwinds it after the driver exits. */\n  readonly scope: Scope\n  readonly ctx: Context\n\n  /** Fused dispatcher, built once in the constructor so hot-path dispatches never allocate. */\n  private readonly dispatch: AgentEventDispatch\n\n  /** Whether this loop instance has appended its initial/resume request anchor. */\n",
      "excerpt_sha256": "2cb0b371385e552e45d52df354ba7b38dbf5d06741b828e68815ecffa432ffea",
      "observation": "默认驱动器围绕 session、inbox、scope 与 phase 组织运行。"
    },
    {
      "id": "dsh-session",
      "project": "dsh",
      "path": "packages/core/session/src/index.ts",
      "start": 982,
      "end": 996,
      "url": "https://github.com/deepseek-ai/deepseek-harness/blob/687f282e8625c6b8d11ff58211a90524be2e4317/packages/core/session/src/index.ts#L982-L996",
      "sha256": "c1f08f7dcf4075eeebb13e6ea06b3f348bfeb85b8a5d4e4bfd1c3b93c1959332",
      "excerpt": "   * @returns a fresh array of the shared, frozen derived history.\n   */\n  deriveMessages(): Message[] {\n    const surface = this.surface\n    const nodes = surface.nodes\n    const generation = surface.contentGeneration\n    if (generation !== this.derivedGeneration) {\n      this.derived = []\n      this.derivedNodes = 0\n      this.derivedGeneration = generation\n    }\n    for (const seq of nodes.slice(this.derivedNodes)) {\n      // Surface sequences are built from this.log — seq is always a valid\n      // index by construction. The non-null assertion expresses that invariant.\n      // oxlint-disable-next-line typescript/no-non-null-assertion\n",
      "excerpt_sha256": "34b250dce5982dc94ab193661231f1f82a28cea233305b13cbb5298cb767c43a",
      "observation": "模型历史由会话日志的有效 surface 派生；缓存受 generation 管理。"
    },
    {
      "id": "dsh-scheduler",
      "project": "dsh",
      "path": "packages/core/agent-loop/src/tool-calls.ts",
      "start": 58,
      "end": 72,
      "url": "https://github.com/deepseek-ai/deepseek-harness/blob/687f282e8625c6b8d11ff58211a90524be2e4317/packages/core/agent-loop/src/tool-calls.ts#L58-L72",
      "sha256": "5c7e8d8ff0028b436efdd13e5dffa4801d2311c211c3af039e7dab705f87b303",
      "excerpt": " * @param acceptContext - accepts committed result context for the next step boundary.\n */\nexport async function executeToolCalls(\n  ctx: Context,\n  turn: number,\n  step: number,\n  toolCalls: ToolCallBlock[],\n  signal: AbortSignal,\n  acceptContext: (context: UserMessage) => void,\n): Promise<{ concluded: boolean }> {\n  const agent = ctx.agents.requireInitiator()\n  const { session } = agent\n\n  // Inputs are distinct because tools/execute wrappers may replace `exec.signal`.\n  const planned: PlannedCall[] = toolCalls.map(block => ({\n",
      "excerpt_sha256": "e175eb1de28f79d1374800092dc225701867ffa05041fccc2d3a573d00f2a9da",
      "observation": "调度区分独占屏障和有界并行，完整实现在同文件。"
    },
    {
      "id": "dsh-registry",
      "project": "dsh",
      "path": "packages/core/tools/src/index.ts",
      "start": 1309,
      "end": 1323,
      "url": "https://github.com/deepseek-ai/deepseek-harness/blob/687f282e8625c6b8d11ff58211a90524be2e4317/packages/core/tools/src/index.ts#L1309-L1323",
      "sha256": "398bcdeb221e450d088510830b77d99a513e65ab31e40ade71688a19cdf5e6aa",
      "excerpt": "   * @returns the fail-closed scheduling mode.\n   */\n  executionMode(exec: ToolExecutionInput): ToolExecutionMode {\n    const tool = this.resolveExecution(exec.name, exec.agent, exec.parent !== undefined)\n    if (!tool?.isConcurrencySafe) return { kind: 'exclusive' }\n    try {\n      const concurrencySafe: unknown = tool.isConcurrencySafe(exec.arguments)\n      return concurrencySafe === true ? { kind: 'parallel' } : { kind: 'exclusive' }\n    } catch {\n      return { kind: 'exclusive' }\n    }\n  }\n\n  /**\n   * Run the `tools/ptc-dispatch-log` waterfall over one settled sub-dispatch\n",
      "excerpt_sha256": "916e67e94061cc4a6a3b04ebbc4bccb40ea5875fb677a9f78f91200b1c165cbf",
      "observation": "并发安全声明缺失、异常或不为 true 时回退独占。"
    },
    {
      "id": "dsh-events",
      "project": "dsh",
      "path": "packages/core/agent/src/dispatch.ts",
      "start": 52,
      "end": 66,
      "url": "https://github.com/deepseek-ai/deepseek-harness/blob/687f282e8625c6b8d11ff58211a90524be2e4317/packages/core/agent/src/dispatch.ts#L52-L66",
      "sha256": "6dc2702311305b9ecc8c8a932417bb7929f7313722fbb432a899e53d16efc6e0",
      "excerpt": " * the agent itself injected into the payload.\n */\nexport interface AgentEventDispatch {\n  /**\n   * Fire-and-forget notification in the agent's scope. Every listener is\n   * invoked; synchronous throws and returned-promise rejections are logged and\n   * contained per listener, so a notification cannot veto lifecycle progress\n   * or starve a later observer.\n   * @param name - the agent-subject event to emit.\n   * @param payload - the event's payload fields; `agent` is injected.\n   */\n  emit<K extends AgentSubjectEvent>(name: K, payload: PayloadRest<K>): void\n  /**\n   * Awaited in-order dispatch (Cordis `serial`) in the agent's scope.\n   * @param name - the agent-subject event to dispatch.\n",
      "excerpt_sha256": "94e5aad01e8aa4ab1d488680a63768a83bf2c0dbad3f5d7a0c7f78243254f7a3",
      "observation": "通知 emit、等待 serial 与包围执行 waterfall 的语义不同。"
    },
    {
      "id": "dsh-lifecycle",
      "project": "dsh",
      "path": "packages/core/agent-loop/src/index.ts",
      "start": 102,
      "end": 116,
      "url": "https://github.com/deepseek-ai/deepseek-harness/blob/687f282e8625c6b8d11ff58211a90524be2e4317/packages/core/agent-loop/src/index.ts#L102-L116",
      "sha256": "3ea0262656c8ddcaa3be315c150bdc2af09371031c3c471d4ded511e21c6e86b",
      "excerpt": "\n/** Factory-level ownership: live agent teardowns plus config startup work. */\nclass FactoryOwnership {\n  private accepting = true\n  private readonly teardown = new AbortController()\n  private readonly inactive = Promise.withResolvers<void>()\n  private readonly liveAgents = new Set<() => Promise<void>>()\n  private startupTasks = new Set<Promise<void>>()\n\n  constructor(private readonly fiber: Context['fiber']) {}\n\n  /** Aborts (reason: `agent loop is not active` error) when factory teardown begins. */\n  get signal(): AbortSignal {\n    return this.teardown.signal\n  }\n",
      "excerpt_sha256": "a58b800026bd8627cadf4340a38358bf88cc26a04b7c62fd6b6d57fea03091a0",
      "observation": "插件工厂追踪启动任务和活跃代理，承担有序卸载责任。"
    },
    {
      "id": "dsh-generation",
      "project": "dsh",
      "path": "packages/session/session-persistence-jsonl/src/generation.ts",
      "start": 253,
      "end": 267,
      "url": "https://github.com/deepseek-ai/deepseek-harness/blob/687f282e8625c6b8d11ff58211a90524be2e4317/packages/session/session-persistence-jsonl/src/generation.ts#L253-L267",
      "sha256": "43a400aaa47be789173ef4d5dd3226bce374cbfac300c2bff199b5a7d108efd6",
      "excerpt": " * @returns the stable bytes (or the committed prefix) and their stat identity.\n */\nexport async function readStableJsonlFile(\n  path: string,\n  signal?: AbortSignal,\n): Promise<StablePhysicalFile> {\n  return defaultGenerationRuntime.readStable(path, signal)\n}\n\nasync function readStableSnapshot(\n  path: string,\n  signal: AbortSignal | undefined,\n  fs: GenerationFileSystem,\n): Promise<StablePhysicalFile> {\n  signal?.throwIfAborted()\n",
      "excerpt_sha256": "8c4d23a92e535c59b852b1e9ea8b1b0be6127eb8dadd0bcd91c864b3000c5462",
      "observation": "JSONL generation 与文件稳定性在持久化提供方实现。"
    },
    {
      "id": "dsh-provider",
      "project": "dsh",
      "path": "packages/llm/llm-deepseek/src/transport.ts",
      "start": 20,
      "end": 34,
      "url": "https://github.com/deepseek-ai/deepseek-harness/blob/687f282e8625c6b8d11ff58211a90524be2e4317/packages/llm/llm-deepseek/src/transport.ts#L20-L34",
      "sha256": "7d1f6ed8fe861ee71ba2d0c6a2a9e8512ddc1b6dc17d43a8795ab520a38746b6",
      "excerpt": " * @returns a stable error consumed by LlmRuntime and llm-retry.\n */\nexport function providerError(raw: unknown, status: number | undefined, headers?: Headers): LlmError {\n  const envelope = typeof raw === 'object' && raw !== null ? raw as Record<string, unknown> : {}\n  const error = typeof envelope.error === 'object' && envelope.error !== null ? envelope.error as Record<string, unknown> : {}\n  const message = typeof error.message === 'string' ? error.message : `DeepSeek Messages request failed (${status ?? 'stream error'})`\n  const type = typeof error.type === 'string' ? error.type : ''\n  const detail = `${type} ${typeof error.code === 'string' ? error.code : ''} ${message}`\n  let code: string\n  if (status === 401 || status === 403 || ['authentication_error', 'permission_error'].includes(type)) code = 'AUTH'\n  else if (isQuotaExceededError(detail) || status === 402) code = 'QUOTA'\n  else if (status === 429 || type === 'rate_limit_error') code = 'RATE_LIMIT'\n  else if (isContextWindowExceededError(detail)) code = 'CONTEXT_WINDOW_EXCEEDED'\n  else if (status === 400 || status === 413 || type === 'invalid_request_error') code = 'INVALID_REQUEST'\n  else if ((status !== undefined && status >= 500) || ['api_error', 'overloaded_error'].includes(type)) code = 'SERVER'\n",
      "excerpt_sha256": "bcfed33c06508a4f87162a1ab6b91cd587460a5ca85a2202a2224e8323f5db74",
      "observation": "供应商传输错误转换成框架统一的 LlmError。"
    },
    {
      "id": "dsh-sandbox",
      "project": "dsh",
      "path": "packages/sandbox/sandbox/src/index.ts",
      "start": 123,
      "end": 137,
      "url": "https://github.com/deepseek-ai/deepseek-harness/blob/687f282e8625c6b8d11ff58211a90524be2e4317/packages/sandbox/sandbox/src/index.ts#L123-L137",
      "sha256": "46592025ce36d04ff8d1bfa9d6594dd8d1527883649ccf40ff7a169e94e68dc6",
      "excerpt": " * failure.\n */\nexport const SANDBOX_UNAVAILABLE = 'SANDBOX_UNAVAILABLE'\n\n/**\n * Thrown when {@link SandboxProvider.confine} cannot enforce the requested\n * mode. Carries {@link SANDBOX_UNAVAILABLE} through the structured error\n * channel.\n */\nexport class SandboxUnavailableError extends HarnessError {\n  constructor(mode: ConfinedSandboxMode, detail?: string) {\n    super(\n      `sandbox mode \"${mode}\" is requested but no sandbox backend is usable on this host; `\n      + 'refusing to run the command unconfined. Install bubblewrap or run a Landlock-enforcing '\n      + 'kernel (Linux), ensure sandbox-exec is usable (macOS), or ensure the ACL '\n",
      "excerpt_sha256": "021f7c824d58f796550d5273cbd6bbea8a7f942172b914648b4f65fe8cb23eef",
      "observation": "沙箱不可用具有显式失败类型；不能默认为拥有隔离。"
    },
    {
      "id": "pi-agent",
      "project": "pi",
      "path": "packages/agent/src/agent.ts",
      "start": 371,
      "end": 385,
      "url": "https://github.com/earendil-works/pi/blob/16f5f0af4d85ca583d045ceb5ed6d646fcaf7761/packages/agent/src/agent.ts#L371-L385",
      "sha256": "7024a3145a6ebc951a0f030164adb1dfb12d33d6e0dbbac15ef0efda49c87457",
      "excerpt": "\tasync prompt(message: AgentMessage | AgentMessage[]): Promise<void>;\n\tasync prompt(input: string, images?: ImageContent[]): Promise<void>;\n\tasync prompt(input: string | AgentMessage | AgentMessage[], images?: ImageContent[]): Promise<void> {\n\t\tif (this.activeRun) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Agent is already processing a prompt. Use steer() or followUp() to queue messages, or wait for completion.\",\n\t\t\t);\n\t\t}\n\t\tconst messages = this.normalizePromptInput(input, images);\n\t\tawait this.runPromptMessages(messages);\n\t}\n\n\t/** Continue from the current transcript. The last message must be a user or tool-result message. */\n\tasync continue(): Promise<void> {\n\t\tif (this.activeRun) {\n",
      "excerpt_sha256": "fe77a95007ecddd3b7c2754349703293ce4112d5197cb3ca66315ee20137b47b",
      "observation": "Agent 阻止同时启动第二个 prompt，运行中输入走 steer/followUp。"
    },
    {
      "id": "pi-loop",
      "project": "pi",
      "path": "packages/agent/src/agent-loop.ts",
      "start": 161,
      "end": 175,
      "url": "https://github.com/earendil-works/pi/blob/16f5f0af4d85ca583d045ceb5ed6d646fcaf7761/packages/agent/src/agent-loop.ts#L161-L175",
      "sha256": "28a2b03e34a7e32f004aa851e54d3b5be9dad71c392205614cbc9abdf3a9020a",
      "excerpt": " * Main loop logic shared by agentLoop and agentLoopContinue.\n */\nasync function runLoop(\n\tinitialContext: AgentContext,\n\tnewMessages: AgentMessage[],\n\tinitialConfig: AgentLoopConfig,\n\tsignal: AbortSignal | undefined,\n\temit: AgentEventSink,\n\tstreamFunction: StreamFn,\n): Promise<void> {\n\tlet currentContext = initialContext;\n\tlet config = initialConfig;\n\tlet lastCompletedTurn: PrepareNextTurnContext | undefined;\n\tlet explicitContinuation = false;\n\t// Check for steering messages at start (user may have typed while waiting)\n",
      "excerpt_sha256": "376a9e8ef1dcb3846545f09f0771a2bc8ff7f7b3b48b5978cdd84885170db1a9",
      "observation": "循环、模型流与宿主上下文转换可以分开组合。"
    },
    {
      "id": "pi-convert",
      "project": "pi",
      "path": "packages/agent/src/agent-loop.ts",
      "start": 388,
      "end": 402,
      "url": "https://github.com/earendil-works/pi/blob/16f5f0af4d85ca583d045ceb5ed6d646fcaf7761/packages/agent/src/agent-loop.ts#L388-L402",
      "sha256": "28a2b03e34a7e32f004aa851e54d3b5be9dad71c392205614cbc9abdf3a9020a",
      "excerpt": "\t// Apply context transform if configured (AgentMessage[] → AgentMessage[])\n\tlet messages = context.messages;\n\tif (config.transformContext) {\n\t\tmessages = await config.transformContext(messages, signal);\n\t}\n\n\t// Convert to LLM-compatible messages (AgentMessage[] → Message[])\n\tconst llmMessages = await config.convertToLlm(messages);\n\n\tconst llmContext = normalizeContext({ messages: llmMessages });\n\n\t// Resolve API key (important for expiring tokens)\n\tconst resolvedApiKey =\n\t\t(config.getApiKey ? await config.getApiKey(config.model.provider) : undefined) || config.apiKey;\n\n",
      "excerpt_sha256": "676968d5374e63de073a722dd356cd14ff92e3db63e5850ddef23539e66efd94",
      "observation": "先变换应用上下文，再转换为模型兼容消息。"
    },
    {
      "id": "pi-truncated",
      "project": "pi",
      "path": "packages/agent/src/agent-loop.ts",
      "start": 266,
      "end": 280,
      "url": "https://github.com/earendil-works/pi/blob/16f5f0af4d85ca583d045ceb5ed6d646fcaf7761/packages/agent/src/agent-loop.ts#L266-L280",
      "sha256": "28a2b03e34a7e32f004aa851e54d3b5be9dad71c392205614cbc9abdf3a9020a",
      "excerpt": "\t\t\t\t// them all instead of executing potentially borked calls.\n\t\t\t\tconst executedToolBatch =\n\t\t\t\t\tmessage.stopReason === \"length\"\n\t\t\t\t\t\t? await failToolCallsFromTruncatedMessage(toolCalls, emit)\n\t\t\t\t\t\t: await executeToolCalls(currentContext, message, config, signal, emit);\n\t\t\t\ttoolResults.push(...executedToolBatch.messages);\n\t\t\t\thasMoreToolCalls = !executedToolBatch.terminate;\n\n\t\t\t\tfor (const result of toolResults) {\n\t\t\t\t\tcurrentContext.messages.push(result);\n\t\t\t\t\tnewMessages.push(result);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlastCompletedTurn = {\n",
      "excerpt_sha256": "3002687ed1e48ceea19357f0fd5acba2ecadc42177d2da7175b8486f8d887484",
      "observation": "截断响应中的工具调用走失败结果，不直接执行潜在不完整参数。"
    },
    {
      "id": "pi-order",
      "project": "pi",
      "path": "packages/agent/src/agent-loop.ts",
      "start": 644,
      "end": 658,
      "url": "https://github.com/earendil-works/pi/blob/16f5f0af4d85ca583d045ceb5ed6d646fcaf7761/packages/agent/src/agent-loop.ts#L644-L658",
      "sha256": "28a2b03e34a7e32f004aa851e54d3b5be9dad71c392205614cbc9abdf3a9020a",
      "excerpt": "\t}\n\n\tconst orderedFinalizedCalls = await Promise.all(\n\t\tfinalizedCalls.map((entry) => (typeof entry === \"function\" ? entry() : Promise.resolve(entry))),\n\t);\n\tconst messages: ToolResultMessage[] = [];\n\tfor (const finalized of orderedFinalizedCalls) {\n\t\tconst toolResultMessage = createToolResultMessage(finalized);\n\t\tawait emitToolResultMessage(toolResultMessage, emit);\n\t\tmessages.push(toolResultMessage);\n\t}\n\n\treturn {\n\t\tmessages,\n\t\tterminate: shouldTerminateToolBatch(orderedFinalizedCalls),\n",
      "excerpt_sha256": "a47a22cfd645030f051b9266c7706ca462b265968de2447d9ab89742e97dfb82",
      "observation": "并行结果整理回模型原调用顺序，区别于工具完成事件顺序。"
    },
    {
      "id": "pi-stream-contract",
      "project": "pi",
      "path": "packages/agent/src/types.ts",
      "start": 31,
      "end": 45,
      "url": "https://github.com/earendil-works/pi/blob/16f5f0af4d85ca583d045ceb5ed6d646fcaf7761/packages/agent/src/types.ts#L31-L45",
      "sha256": "2e116ef60fdaca4e26be5a1ace8d8b47f545d648d365de60b8c9f9d1ba629ee4",
      "excerpt": " *   final AssistantMessage with stopReason \"error\" or \"aborted\" and errorMessage.\n */\nexport type StreamFn = (\n\tmodel: Model<Api>,\n\tcontext: TranscriptContext,\n\toptions?: SimpleStreamOptions,\n) => AssistantMessageEventStream | Promise<AssistantMessageEventStream>;\n\n/**\n * Configuration for how tool calls from a single assistant message are executed.\n *\n * - \"sequential\": each tool call is prepared, executed, and finalized before the next one starts.\n * - \"parallel\": tool calls are prepared sequentially, then allowed tools execute concurrently.\n *   `tool_execution_end` is emitted in tool completion order after each tool is finalized,\n *   while tool-result message artifacts are emitted later in assistant source order.\n",
      "excerpt_sha256": "49ae7c23a3c5fa44bf75ca74ccac3d2c11027aa4b7067c4e567588b9436c28c3",
      "observation": "模型流函数是注入的协议边界；错误契约见定义前注释。"
    },
    {
      "id": "pi-session",
      "project": "pi",
      "path": "packages/coding-agent/src/core/session-manager.ts",
      "start": 574,
      "end": 588,
      "url": "https://github.com/earendil-works/pi/blob/16f5f0af4d85ca583d045ceb5ed6d646fcaf7761/packages/coding-agent/src/core/session-manager.ts#L574-L588",
      "sha256": "450d82c529933214e088b8422f00061815e617f352f6c834689787a314064bff",
      "excerpt": "\n/** Build the finalized model context from the canonical session projection. */\nexport function buildSessionContext(\n\tentries: SessionEntry[],\n\tleafId?: string | null,\n\tbyId?: Map<string, SessionEntry>,\n): SessionContext {\n\tconst { messages, thinkingLevel, model } = buildSessionProjection(entries, leafId, byId);\n\treturn { messages, thinkingLevel, model };\n}\n\n/**\n * Compute the default session directory for a cwd.\n * Encodes cwd into a safe directory name under ~/.pi/agent/sessions/.\n */\n",
      "excerpt_sha256": "67aa6e344d522fe6eca6e1df842c58dc702cd96ba354d6eeade1a473da92a2b9",
      "observation": "会话条目树被解析为当前有效模型上下文。"
    },
    {
      "id": "pi-compaction",
      "project": "pi",
      "path": "packages/coding-agent/src/core/compaction/compaction.ts",
      "start": 857,
      "end": 871,
      "url": "https://github.com/earendil-works/pi/blob/16f5f0af4d85ca583d045ceb5ed6d646fcaf7761/packages/coding-agent/src/core/compaction/compaction.ts#L857-L871",
      "sha256": "f5bbc427e337be708bd15297806c0acaf7cb0ee65cc4af77e6e48c3e3937894f",
      "excerpt": "}\n\nexport function prepareCompaction(\n\tpathEntries: SessionEntry[],\n\tsettings: CompactionSettings,\n): CompactionPreparation | undefined {\n\tif (pathEntries.length > 0 && pathEntries[pathEntries.length - 1].type === \"compaction\") {\n\t\treturn undefined;\n\t}\n\n\tconst projection = buildSessionProjection(pathEntries);\n\tconst projectedEntries = projection.entries;\n\tconst sourceEntries = projectedEntries.map((entry) => entry.sourceEntry);\n\t// The newest compaction is projected first. Older compaction entries can still\n\t// occur in its retained raw range, but their projected contribution is empty.\n",
      "excerpt_sha256": "687ec710ccfd02df690af7cf322d3b6e34abbfc80c2407e8266ebd2abe252a96",
      "observation": "压缩先准备范围，摘要生成在另一执行阶段。"
    },
    {
      "id": "pi-read",
      "project": "pi",
      "path": "packages/coding-agent/src/core/tools/read.ts",
      "start": 84,
      "end": 98,
      "url": "https://github.com/earendil-works/pi/blob/16f5f0af4d85ca583d045ceb5ed6d646fcaf7761/packages/coding-agent/src/core/tools/read.ts#L84-L98",
      "sha256": "c3c64f7105599455d3066568074796e2ddb143cb210da4981b0eb632aa3d2811",
      "excerpt": "}\n\nexport function createReadToolDefinition(\n\tcwd: string,\n\toptions?: ReadToolOptions,\n): ToolDefinition<typeof readSchema, ReadToolDetails | undefined> {\n\tconst autoResizeImages = options?.autoResizeImages ?? true;\n\tconst fallbackResizeOptions = options?.resizeOptions;\n\tconst ops = options?.operations ?? defaultReadOperations;\n\treturn {\n\t\tname: \"read\",\n\t\tlabel: \"read\",\n\t\tdescription: `Read the contents of a file. Supports text files and images (jpg, png, gif, webp, bmp). Images are sent as attachments. For text files, output is truncated to ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). Use offset/limit for large files. When you need the full file, continue with offset until complete.`,\n\t\tpromptSnippet: readToolSystemPromptContribution.snippet,\n\t\tpromptGuidelines: [...readToolSystemPromptContribution.guidelines],\n",
      "excerpt_sha256": "940f486cabf35a4226c00f72c73b81c5d2425b0e43067d76e624df1e6e56ae0a",
      "observation": "读取工具的声明、执行与展示可按定义入口继续追踪。"
    },
    {
      "id": "pi-extension",
      "project": "pi",
      "path": "packages/coding-agent/src/core/extensions/runner.ts",
      "start": 362,
      "end": 376,
      "url": "https://github.com/earendil-works/pi/blob/16f5f0af4d85ca583d045ceb5ed6d646fcaf7761/packages/coding-agent/src/core/extensions/runner.ts#L362-L376",
      "sha256": "3cd6d1ad18e8e4c7adf722aed9291bc64f06e3a7d461755c21e3cba4819f4e5e",
      "excerpt": "};\n\nexport class ExtensionRunner {\n\tprivate extensions: Extension[];\n\tprivate runtime: ExtensionRuntime;\n\tprivate uiContext: ExtensionUIContext;\n\tprivate mode: ExtensionMode = \"print\";\n\tprivate cwd: string;\n\tprivate sessionManager: SessionManager;\n\tprivate modelRegistry: ModelRegistry;\n\tprivate errorListeners: Set<ExtensionErrorListener> = new Set();\n\tprivate getModel: () => Model<any> | undefined = () => undefined;\n\tprivate getScopedModels: () => readonly ScopedModel[] = () => [];\n\tprivate isIdleFn: () => boolean = () => true;\n\tprivate isProjectTrustedFn: () => boolean = () => true;\n",
      "excerpt_sha256": "e280ba4ef3c1cfb8314ec3fbf52e9d415547d57da5c4fe60a5cfea5b32c3d54e",
      "observation": "应用扩展有自己的运行器，不能与底层 Agent 钩子直接等同。"
    },
    {
      "id": "codex-input",
      "project": "codex",
      "path": "codex-rs/core/src/codex_thread.rs",
      "start": 415,
      "end": 429,
      "url": "https://github.com/openai/codex/blob/57d4fac64adbcaed0523ca6bf8d58c4ef6875157/codex-rs/core/src/codex_thread.rs#L415-L429",
      "sha256": "8bb0072b4c30a3b736f4b898cbae5a949301283d6bb4e6a74e0f5b01781d6daf",
      "excerpt": "    /// turn, or declined it without recording or enqueueing the input.\n    /// User input and named standalone function-call outputs are accepted.\n    pub async fn start_or_steer_turn(\n        &self,\n        request: impl Into<WithTurnExtensionData<TurnInputRequest>>,\n    ) -> CodexResult<TurnInputSubmission> {\n        self.submit_turn_input_with_mode(request, TurnInputMode::StartOrSteer)\n            .await\n    }\n\n    /// Starts a regular turn only when the thread is idle.\n    ///\n    /// Core declines the input without recording or enqueueing it when idle\n    /// work cannot start.\n    pub async fn start_turn_if_idle(\n",
      "excerpt_sha256": "6d6c3c6e2289cde1c58979d8f1b6e3f718a5ee0c2c08a9376469073f59631d43",
      "observation": "输入提交先进入会话控制边界，而不是直接请求模型。"
    },
    {
      "id": "codex-turn",
      "project": "codex",
      "path": "codex-rs/core/src/session/turn.rs",
      "start": 171,
      "end": 185,
      "url": "https://github.com/openai/codex/blob/57d4fac64adbcaed0523ca6bf8d58c4ef6875157/codex-rs/core/src/session/turn.rs#L171-L185",
      "sha256": "076bf9522cba976a9b171d3a33403dfb7927330a73fe66afd4e8648f4b1c3629",
      "excerpt": "///   conversation history and consider the turn complete.\n///\npub(crate) async fn run_turn(\n    sess: Arc<Session>,\n    turn_context: Arc<TurnContext>,\n    mut input: Vec<TurnInput>,\n    mcp_startup_requirements: &mut McpStartupRequirements,\n    prewarmed_client_session: Option<ModelClientSession>,\n    cancellation_token: CancellationToken,\n) -> CodexResult<Option<String>> {\n    let auto_compaction_enabled = sess\n        .services\n        .thread_extension_data\n        .get::<AutoCompactionDisabled>()\n        .is_none();\n",
      "excerpt_sha256": "5e73fa850041c26ccc40c70ab30d0b14f090b5781207584dfeb7defede037f9c",
      "observation": "Turn 编排模型会话、上下文准备与取消。"
    },
    {
      "id": "codex-followup",
      "project": "codex",
      "path": "codex-rs/core/src/session/turn.rs",
      "start": 608,
      "end": 622,
      "url": "https://github.com/openai/codex/blob/57d4fac64adbcaed0523ca6bf8d58c4ef6875157/codex-rs/core/src/session/turn.rs#L608-L622",
      "sha256": "076bf9522cba976a9b171d3a33403dfb7927330a73fe66afd4e8648f4b1c3629",
      "excerpt": "                .instrument(trace_span!(\"run_turn.collect_post_sampling_state\"))\n                .await;\n                let needs_follow_up = model_needs_follow_up || has_pending_input;\n                let token_limit_reached = token_status.token_limit_reached;\n\n                super::async_compaction::maybe_start(\n                    &sess,\n                    &step_context,\n                    &world_state,\n                    if needs_follow_up {\n                        CompactionPhase::MidTurn\n                    } else {\n                        CompactionPhase::PostTurn\n                    },\n                    &cancellation_token,\n",
      "excerpt_sha256": "bcb265acedd22a07e46c60ec3907be0c2a7e43e1e3bfec5d38b52a6fa281499e",
      "observation": "继续生成既可能由模型工作触发，也可能由待处理输入触发。"
    },
    {
      "id": "codex-router",
      "project": "codex",
      "path": "codex-rs/core/src/tools/router.rs",
      "start": 83,
      "end": 97,
      "url": "https://github.com/openai/codex/blob/57d4fac64adbcaed0523ca6bf8d58c4ef6875157/codex-rs/core/src/tools/router.rs#L83-L97",
      "sha256": "7345f8d2c467637e3d646d5510770457db89e4259e0515d5175de363e2c9c79e",
      "excerpt": "\n/// One finalized tool plan: its advertised surfaces and matching executable runtimes.\npub struct ToolRouter {\n    registry: ToolRegistry,\n    model_visible_specs: Arc<[ToolSpec]>,\n    tool_mode: ToolMode,\n    code_mode_tool_names: BTreeMap<String, ToolName>,\n    tool_namespaces_info: Option<TurnToolNamespacesInfo>,\n    can_manage_children: bool,\n}\n\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\npub(crate) enum ToolSuggestPresentation {\n    ListTool,\n    RecommendationContext,\n",
      "excerpt_sha256": "82012982182454ed3fcef7ae7d61d82a8939b4568ac4bc0e297771b09c017de0",
      "observation": "模型可见工具规格与执行注册表组成一份完成的工具计划。"
    },
    {
      "id": "codex-orchestrator",
      "project": "codex",
      "path": "codex-rs/core/src/tools/orchestrator.rs",
      "start": 1,
      "end": 13,
      "url": "https://github.com/openai/codex/blob/57d4fac64adbcaed0523ca6bf8d58c4ef6875157/codex-rs/core/src/tools/orchestrator.rs#L1-L13",
      "sha256": "8996f718b818804473c151a8a643747c2b5ab69b05f4630eee143fac7daa0bb5",
      "excerpt": "//! Coordinates tool approval, sandbox selection, and retries after sandbox denial.\n//! Guardian approval applies to the reviewed authority; escalating a sandboxed\n//! attempt requires a fresh review of the retry.\nuse crate::config::NetworkProxySpec;\nuse crate::guardian::GuardianReviewContext;\nuse crate::network_policy_decision::network_approval_context_from_payload;\nuse crate::sandboxing::SandboxPermissions;\nuse crate::tools::approvals::ApprovalAction;\nuse crate::tools::approvals::ApprovalContext;\nuse crate::tools::approvals::ApprovalResolutionSource;\nuse crate::tools::flat_tool_name;\nuse crate::tools::network_approval::ActiveNetworkApproval;\nuse crate::tools::network_approval::DeferredNetworkApproval;\n",
      "excerpt_sha256": "dbef9cd0408104624c7ef467ea7299fdeda7330e6fd533d7ccbb6f6a71bf6a51",
      "observation": "编排器协调审批、沙箱选择与受限失败后的重试。"
    },
    {
      "id": "codex-parallel",
      "project": "codex",
      "path": "codex-rs/core/src/tools/parallel.rs",
      "start": 49,
      "end": 63,
      "url": "https://github.com/openai/codex/blob/57d4fac64adbcaed0523ca6bf8d58c4ef6875157/codex-rs/core/src/tools/parallel.rs#L49-L63",
      "sha256": "f575c018ab1452d99ccf9fa4630e5af5e92bbc9eb3e5457ea17ab5be8ae946d0",
      "excerpt": "    step_context: Arc<StepContext>,\n    tracker: SharedTurnDiffTracker,\n    parallel_execution: Arc<RwLock<()>>,\n}\n\nimpl ToolCallRuntime {\n    pub(crate) fn new(\n        session: Arc<Session>,\n        step_context: Arc<StepContext>,\n        tracker: SharedTurnDiffTracker,\n    ) -> Self {\n        Self {\n            session,\n            step_context,\n            tracker,\n",
      "excerpt_sha256": "1672711951479ce3a5aa53efe6d129fb663ce699b2de16b625bfa069f6cce49d",
      "observation": "执行调度共享读写锁状态；具体并发资格须查看分派路径。"
    },
    {
      "id": "codex-process",
      "project": "codex",
      "path": "codex-rs/core/src/unified_exec/process_manager.rs",
      "start": 877,
      "end": 891,
      "url": "https://github.com/openai/codex/blob/57d4fac64adbcaed0523ca6bf8d58c4ef6875157/codex-rs/core/src/unified_exec/process_manager.rs#L877-L891",
      "sha256": "7eba3d82a54ad77cb989991ead28b39fe4aa1df24ddea020a0a36adb2d0fca5a",
      "excerpt": "        )\n    )]\n    pub(crate) async fn write_stdin(\n        &self,\n        context: &UnifiedExecContext,\n        request: WriteStdinRequest<'_>,\n    ) -> Result<ExecCommandToolOutput, UnifiedExecError> {\n        let result = self.write_stdin_inner(context, request).await;\n        let outcome = match &result {\n            Ok(output) if output.process_id.is_some() => \"yielded\",\n            Ok(_) => \"exited\",\n            Err(_) if context.cancellation_token.is_cancelled() => \"cancelled\",\n            Err(_) => \"failed\",\n        };\n        tracing::Span::current().record(\"outcome\", outcome);\n",
      "excerpt_sha256": "12c2faabbf3ddd4b593ebb765b4c95f503b2a37d6dbca8e491e518c5211df6b4",
      "observation": "长进程使用 process_id 等句柄继续交互，不等于一次同步命令。"
    },
    {
      "id": "codex-compact",
      "project": "codex",
      "path": "codex-rs/core/src/compact.rs",
      "start": 115,
      "end": 129,
      "url": "https://github.com/openai/codex/blob/57d4fac64adbcaed0523ca6bf8d58c4ef6875157/codex-rs/core/src/compact.rs#L115-L129",
      "sha256": "7501febae5a93a943e22c17ddb4009d6fea587cef40c6d5c6cf1b0754737be0d",
      "excerpt": "}\n\npub(crate) async fn run_inline_auto_compact_task(\n    sess: Arc<Session>,\n    turn_context: Arc<TurnContext>,\n    replacement_step_context: Arc<StepContext>,\n    world_state: Arc<WorldState>,\n    reason: CompactionReason,\n    phase: CompactionPhase,\n) -> CodexResult<()> {\n    let prompt = turn_context\n        .config\n        .compact_prompt\n        .as_deref()\n        .unwrap_or(SUMMARIZATION_PROMPT)\n",
      "excerpt_sha256": "8cbd5c7b76c6a4f37c8ad0223cf0c8a16c5d4600c74f170187ed55cf471fa585",
      "observation": "上下文压缩是独立任务，具有执行与替换历史的边界。"
    },
    {
      "id": "codex-events",
      "project": "codex",
      "path": "codex-rs/protocol/src/protocol.rs",
      "start": 1467,
      "end": 1481,
      "url": "https://github.com/openai/codex/blob/57d4fac64adbcaed0523ca6bf8d58c4ef6875157/codex-rs/protocol/src/protocol.rs#L1467-L1481",
      "sha256": "9dc4ca7be855139716a72f1d291b5829affc07a19394647d1d9bbb09d4091941",
      "excerpt": "#[ts(tag = \"type\")]\n#[strum(serialize_all = \"snake_case\")]\npub enum EventMsg {\n    /// Error while executing a submission\n    Error(ErrorEvent),\n\n    /// Warning issued while processing a submission. Unlike `Error`, this\n    /// indicates the turn continued but the user should still be notified.\n    Warning(WarningEvent),\n\n    /// Provider-owned authentication recovery has started for the current turn.\n    AuthRecoveryStarted(AuthRecoveryEvent),\n\n    /// Provider-owned authentication recovery has completed for the current turn.\n    AuthRecoveryCompleted(AuthRecoveryEvent),\n",
      "excerpt_sha256": "cc1ea06efd64af65754d038ef3eefc14bf4843125c3269fb4e71d690d32c6b9f",
      "observation": "协议事件承载核心和前端之间的状态，而不是靠解析终端文本。"
    }
  ]
}
