AgentSession 详细分析

1. 一句话结论

AgentSession 是 interactive、print、rpc 三种运行模式共享的"单会话编排器"。它持有并驱动一个 Agent,把 Agent 的底层事件转换为三类结果:

  1. 写入 SessionManager 的持久化条目;
  2. 分发给扩展的 ExtensionRunner 事件;
  3. 分发给宿主 UI 的 AgentSessionEvent。

在此之上,它负责一次 prompt 从准备、执行、重试、压缩到结算的完整生命周期,并管理队列、工具装载、模型/thinking、bash 执行、树导航和会话统计。

核心设计取向是:会话树投影(session projection)是模型上下文的权威来源 。Agent 的 state.messages 只是当前投影的一份可执行副本,AgentSession 在压缩、上下文编辑、边界写入、树导航、自定义消息追加等位置主动用投影刷新它。

2. 在整体架构中的位置

复制代码
┌──────────────────────────────────────────────────────────────┐
│ InteractiveMode / PrintMode / RpcMode / SDK 调用方            │
│  - prompt / steer / followUp / sendCustomMessage             │
│  - subscribe(AgentSessionEvent)                              │
│  - bindExtensions(...)                                       │
└───────────────────────────┬──────────────────────────────────┘
                            │
┌───────────────────────────▼──────────────────────────────────┐
│ AgentSession                                                 │
│  - 运行状态、队列、压缩、重试、工具注册、扩展绑定              │
│  - 事件转换、持久化、投影刷新                                  │
└───────┬──────────────────────┬──────────────────────┬────────┘
        │                      │                      │
        ▼                      ▼                      ▼
┌───────────────┐   ┌──────────────────┐   ┌──────────────────┐
│ Agent         │   │ SessionManager   │   │ ExtensionRunner  │
│ - 状态/循环    │   │ - JSONL 条目      │   │ - 事件/命令/工具  │
│ - 事件流       │   │ - 树/投影         │   │ - UI/资源         │
└───────────────┘   └──────────────────┘   └──────────────────┘
        │
        ▼
┌──────────────────────────────────────────────────────────────┐
│ ModelRuntime / SettingsManager / ResourceLoader / CacheWarmer │
└──────────────────────────────────────────────────────────────┘

AgentSession 不创建 Agent,而是接收已经构造好的 Agent(sdk.ts:411)。创建顺序是:

复制代码
createAgentSession()
  → new Agent({ initialState, convertToLlm, streamFn, ... })   sdk.ts:411
  → 恢复/写入 model_change、thinking_level_change              sdk.ts:448-459
  → new AgentSession({ agent, sessionManager, ... })            sdk.ts:461

AgentSessionRuntime 则负责在 /new、/resume、/fork、/import 时销毁旧 AgentSession 并重建新的;它不参与单会话内部逻辑。两者关系见 AGENT_SESSION_RUNTIME_ANALYSIS.md。

3. 公开契约与状态模型

3.1 构造配置

AgentSessionConfig(agent-session.ts:252-300)的关键字段:

字段 作用
agent 已构造的 Agent 实例
sessionManager 会话树与 JSONL 持久化
settingsManager 全局/项目设置
cwd 会话工作目录,用于工具和系统提示
modelRuntime 认证、模型目录、虚拟模型路由
resourceLoader 扩展、skills、prompts、themes、context files
scopedModels --models 指定的模型循环范围
customTools SDK 注入的工具定义
initialActiveToolNames 初始激活工具
usesDefaultTools 是否从 defaultTools 设置恢复装载
defaultToolModifiers --tools 的 +name/-name 修饰
allowedToolNames / excludedToolNames 工具允许/排除模式
baseToolsOverride 替换内置工具集合
extensionRunnerRef 让 Agent 侧读取当前 ExtensionRunner 的可变引用
sessionStartEvent 绑定扩展时 emit 的 session_start 元数据
cacheWarmer 提示缓存预热器

3.2 内部状态分组

分组 代表字段 说明
运行状态 _isAgentRunActive、_agentRunAbortRequested、_idleWaitPromise 一次 run 从 _startRun 到 agent_settled
队列 _steeringMessages、_followUpMessages、_pendingNextTurnMessages、_pendingCustomMessages 显示用文本与待注入消息
压缩 _compactionAbortController、_autoCompactionAbortController、_branchSummaryAbortController、_overflowRecoveryAttempted 手动/自动压缩与分支摘要
重试 _retryAbortController、_retryAttempt、_failedResponse 指数退避与"被省略的失败响应"
Bash _bashAbortControllers、_pendingBashMessages 流式期间延迟写入
扩展 _extensionRunner、_extensionUIContext、_extensionMode、命令/中止/关闭/错误回调 宿主绑定
工具 _toolRegistry、_toolDefinitions、_pendingToolNames、_hiddenDeclarations 定义优先的注册表
提示词 _baseSystemPromptOptions、_runSystemPromptOptions 基础提示与本次 run 的覆盖
事件 _eventListeners、_entryIdsByMessage、_boundaryDispatchedMessages 公共监听与消息到条目映射
缓存 _cacheWarmer onWarmed 时发出 entry_appended

3.3 关键 getter 的语义

Getter 语义
isStreaming _isAgentRunActive,包含 before_agent_start、运行、重试等待、压缩后的继续
isIdle !isStreaming && !isCompacting;不包含正在运行的 bash
isCompacting 手动压缩、自动压缩、分支摘要任一进行中
model / thinkingLevel 直接读 Agent state
routedModel 虚拟模型选择下,最近一次成功响应使用的物理模型
systemPrompt 用 _runSystemPromptOptions(若存在)或基础选项实时构建
messages Agent state 中的消息,即当前投影
sessionFile / sessionId / sessionName 转发 SessionManager

4. 构造流程

构造函数(agent-session.ts:486-527)按固定顺序完成:

  1. 保存配置字段,初始化队列、工具、扩展引用;
  2. 订阅 Agent 事件:agent.subscribe(this._handleAgentEvent);
  3. 安装工具钩子 _installAgentToolHooks();
  4. 安装下一轮刷新 _installAgentNextTurnRefresh();
  5. 安装请求投影 _installAgentRequestProjection();
  6. 安装边界钩子 _installAgentBoundaryHooks();
  7. 安装隐藏声明投影 _installHiddenDeclarationsProjection();
  8. 安装强制提示投影 _installAgentForcedPromptProjection();
  9. _buildRuntime() 创建 ExtensionRunner、工具定义与注册表;
  10. 如果 usesDefaultTools,从 transcript 恢复工具装载。

这些"安装"本质上是对 Agent 的可选回调做包装:

Agent 回调 AgentSession 用途
beforeToolCall / afterToolCall 扩展 tool_call / tool_result 钩子与图像归一化
prepareRequest 用会话投影替换请求上下文、虚拟模型路由、溢出前压缩
prepareNextTurnWithContext 下一轮 assistant 请求前压缩、刷新提示与工具装载
finishTurn 在 turn_end 前分发可操作边界
transformContext 隐藏声明过滤、强制系统提示投影

5. 事件管线

5.1 单次 Agent 事件的处理顺序

_handleAgentEvent(agent-session.ts:1104-1200)是唯一入口:

复制代码
Agent event
  │
  ├─ 1. 特殊状态处理
  │     - agent_start 且已请求 abort → agent.abort()
  │     - toolResult message_start → 合并 nested tool call 记录与 usage
  │     - agent_end → 清空 nested 记录
  │     - user message_start → 从 steering/followUp 显示队列移除
  │
  ├─ 2. _emitExtensionEvent(event)   // 先扩展
  │
  ├─ 3. _emit(public event)          // 后宿主;agent_end 附带 willRetry
  │
  └─ 4. 持久化
        - message_end: custom → custom_message;其余 → message
        - assistant message_end: 更新 lastAssistant、重置重试计数
        - turn_end: 记录 toolResults、flush pending custom messages

顺序上的两个关键点:

  1. 扩展先于公共监听器 。测试 emits extension events before public event subscribers 覆盖。
  2. 扩展 handler 是 await 的 ,因此 message_end 的替换会在持久化之前完成。测试 keeps persisted assistant/toolResult message order when extension message_end handlers yield 覆盖了慢 handler 下的顺序。

5.2 事件类型

AgentSessionEvent(agent-session.ts:196-237)在 AgentEvent 之上增加:

事件 触发点
agent_settled run 完全结算后(扩展与公共各一次)
queue_update steering/followUp 队列变化
compaction_start / compaction_end 手动或自动压缩
entry_appended 绕过 message 事件直接写入条目时
session_info_changed 会话重命名
thinking_level_changed thinking 等级实际变化
auto_retry_start / auto_retry_end 模型请求重试
summarization_retry_* 压缩/分支摘要内部重试
bash_execution_update bash 输出增量

agent_end 被重写为带 willRetry 的版本;willRetry 由 _willRetryAfterAgentEnd(:1202)计算:未 abort、重试已启用、未超过上限、最后一条 assistant 是可重试错误。

5.3 持久化映射

message_end(agent-session.ts:1148-1189)的映射规则:

消息 role 写入方法
custom appendCustomMessageEntry(customType, content, display, details)
system / user / assistant / toolResult appendMessage(message)
bashExecution / compactionSummary / branchSummary 由各自路径写入,不走这里

写入后把消息对象映射到条目 ID,供边界事件和恢复省略使用(_entryIdsByMessage)。

5.4 message_end 替换的原地语义

扩展可以通过 message_end 返回替换消息。_replaceMessageInPlace(:1271-1285)不是替换引用,而是:

  1. 删除目标对象的所有自有属性;
  2. 把替换对象的属性赋给目标对象。

原因在注释里写明:Agent core 在 emit message_end 之前已经把最终消息对象放进 state;后续 turn/agent 事件、监听器以及 appendMessage(event.message) 都引用同一个对象。原地修改能保证所有引用看到同一份替换结果。

替换内容若 content 为 null/缺失,会被归一化为 [],避免未类型化扩展把非法消息写入历史。

5.5 条目 ID 解析

_findPersistedMessageEntryId(:1218-1239)依次尝试:

  1. _entryIdsByMessage 弱映射;
  2. 反向扫描当前分支中的 message 条目,比较对象身份;
  3. 通过 Agent state 中的消息索引,在投影条目中逐条计数定位源条目。

解析失败时,边界事件会报错,恢复省略会抛错,避免"以为持久化了但实际没有"。

5.6 结算

_emitAgentSettled(:1079-1101):

  1. 通知 cache warmer;
  2. 清除 _isAgentRunActive;
  3. 先扩展、后公共地 emit agent_settled;
  4. 执行 _deferredSettledActions(在结算期间调用 prompt() 或带 triggerTurn 的 sendCustomMessage() 会被延迟到这里);
  5. 如果空闲,resolve waitForIdle()。

prompt() 在 _isEmittingAgentSettled 为 true 时直接把自己加入延迟队列(:2059-2062),避免在结算过程中启动新 run。

6. Prompt 生命周期

6.1 prompt() 前置处理

prompt(text, options)(agent-session.ts:2058-2141)按顺序做:

  1. 结算期延迟 :如果正在 emit agent_settled,延迟到结算完成。
  2. 扩展命令 :文本以 / 开头且允许展开时,先尝试 _tryExecuteExtensionCommand。命中则立即执行,不消耗模型请求。
  3. 手动压缩互斥 :_compactionAbortController 存在时直接抛错,要求等待压缩结束。
  4. input 扩展钩子 :_runInputHandlers 可 handled、transform 或放行。source 默认 interactive;流式时会带上 streamingBehavior。
  5. skill 与模板展开 :
    • /skill:name args 读取 skill 文件,去掉 frontmatter,包成 <skill name location>...</skill>;
    • 其余文本走 expandPromptTemplate。
  6. 流式排队 :如果 isStreaming:
    • 未指定 streamingBehavior 抛错;
    • followUp 走 _queueFollowUp;
    • steer 走 _queueSteer;
    • 返回前调用 preflightResult("queued")。
  7. 模型与认证校验:无模型、无认证、OAuth 失效分别给出明确错误。
  8. 启动 run :_startRun({ messageType: "user", prompt, images }, ...)。

preflightResult 是 RPC 模式观察"被接受后如何分发"的内部钩子,被拒绝时不会调用。

6.2 _startRun():一次 run 的外层循环

_startRun(:1837-1882)的结构:

ts 复制代码
this._isAgentRunActive = true;
this._agentRunAbortRequested = false;

messages = await this._prepareRun(trigger);   // 失败则复位 active 并抛出

flush pending bash/custom;
onStarted?.();

this._failedResponse = undefined;
this._recordSelection();
this._pendingToolNames.clear();

try {
  await this.agent.prompt(messages);

  while (!this._agentRunAbortRequested) {
    if (await this._handlePostAgentRun()) {
      if (abort) break;
      await this.agent.continue();
      continue;
    }
    if (abort || !(await this._runBeforeSettleBoundary())) break;
    if (abort) break;
    await this.agent.continue();
  }
} finally {
  if (abort) this._finishCancelledRetry();
  this._failedResponse = undefined;
  this._runSystemPromptOptions = undefined;
  flush pending bash/custom;
  await this._emitAgentSettled();
}

要点:

  • run 在 _prepareRun 之前就算"忙",所以 before_agent_start 期间发送的消息会进入队列而不是启动第二个 run;期间请求的 abort 会在 agent_start 时生效。
  • _handlePostAgentRun 返回 true 表示"需要再跑一次":可重试错误、压缩后的继续、或仍有排队消息。
  • agent_before_settle 边界只在 post-run 不再继续时执行;它也可以要求继续。
  • 无论成功、失败还是 abort,finally 都会结算并 resolve idle。

6.3 _prepareRun():构造起始消息

_prepareRun(:1890-1941):

  1. 如果存在最后一条 assistant,先 _checkCompaction(lastAssistant, false)。skipAbortedCheck=false 表示 aborted 响应也参与检查,用于捕获"上次被中止导致上下文过大"的情况。
  2. emitBeforeAgentStart(trigger, baseOptions):
    • 扩展可以修改 systemPromptOptions、返回 messages、返回 systemPrompt。
  3. 工具选择处理:
    • 如果 handler 显式修改了 selectedTools,以 handler 为准;
    • 否则以当前活动工具为准,避免 setActiveTools() 被回滚。
  4. 构造起始消息:
    • custom trigger:直接放入自定义消息;
    • 普通 prompt:先归一化图片,再把图片提示拼到文本后,构造 user message;
    • 追加 _pendingNextTurnMessages 并清空;
    • 追加 handler 返回的 custom messages;
  5. _preparePromptAndToolLoadout 生成系统提示补丁;如果有补丁,放在消息最前面;
  6. 保存 _runSystemPromptOptions 供本轮请求投影和 systemPrompt getter 使用。

图片归一化放在 before_agent_start 之后,是为了让扩展选择的模型决定 resize profile(:1912-1914 注释)。

6.4 _handlePostAgentRun():每次循环的决策

_handlePostAgentRun(:1943-1981)顺序:

  1. 取出并清空 _lastAssistantMessage / _lastAssistantToolResults;
  2. 已 abort:结束取消中的重试,返回 false;
  3. 没有 assistant:返回 agent.hasQueuedMessages();
  4. 可重试错误:_prepareRetry 成功则设置 _failedResponse 并返回 true;
  5. 非可重试错误且 _retryAttempt > 0:emit auto_retry_end { success: false } 并清零;
  6. _checkCompaction(message, true, toolResults) 返回 true 则继续;
  7. 否则返回是否有排队消息。

注意第 6 步的 skipAbortedCheck=true:post-run 不会因为 aborted 消息触发压缩。

6.5 _runBeforeSettleBoundary()

agent_before_settle 是一个"run 即将结束但还可以继续"的扩展边界(:1983-2005):

  1. 无 handler 时直接返回是否有排队消息;
  2. 设置 _isBeforeSettle;
  3. emit boundary,携带 outcome(completed / aborted / error);
  4. 提交 drafts、flush pending custom;
  5. 如果 hook 期间 abort,返回 false;
  6. 如果要求继续但最终上下文不可运行(没有非 system 消息、最后一条是 assistant,且没有 pending custom 或排队消息),报错并停止。

6.6 一次 prompt 的完整时序

复制代码
prompt(text)
  │
  ├─ 扩展命令? ──是──> 执行并返回
  ├─ 手动压缩中? ──是──> 抛错
  ├─ input handlers(handled/transform)
  ├─ skill / template 展开
  ├─ isStreaming? ──是──> steer/followUp 入队并返回
  ├─ 模型/认证校验
  └─ _startRun
       │
       ├─ _prepareRun
       │    ├─ 预压缩检查
       │    ├─ before_agent_start
       │    ├─ 图片归一化
       │    ├─ 组装 user/custom 消息
       │    └─ 系统提示补丁
       │
       ├─ agent.prompt(messages)
       │    └─ agent-loop:流式响应、工具执行、turn_end
       │
       ├─ 循环:
       │    ├─ 可重试错误 → 退避 → agent.continue()
       │    ├─ 溢出/阈值 → 压缩 → agent.continue()
       │    ├─ 有排队消息 → agent.continue()
       │    └─ agent_before_settle 要求继续 → agent.continue()
       │
       └─ finally:flush、清状态、agent_settled

7. 系统提示与工具装载

7.1 定义优先的工具注册表

_buildRuntime(:3636-3688)建立:

  • _baseToolDefinitions:内置工具或 baseToolsOverride 转换出的定义;
  • _extensionRunner:扩展运行时;
  • _toolDefinitions / _toolRegistry:_refreshToolRegistry 构建的定义表和可执行工具表;
  • 初始活动工具:initialActiveToolNames 或默认 read/bash/edit/write。

_refreshToolRegistry(:3525-3623)的输入有三类:

  1. 扩展注册的工具(runner.getAllRegisteredTools());
  2. SDK customTools;
  3. 内置工具定义。

它同时生成:

  • _toolPromptSnippets:一行工具说明,进入系统提示;
  • _toolPromptGuidelines:工具使用规则;
  • _toolRegistry:包装后的 AgentTool,供 Agent 执行。

7.2 工具的五个曝光级别

ToolExposure(extensions/types.ts:516):

级别 含义
direct 激活后声明给模型,可直接调用
model-only 声明给模型,但不一定直接执行
codemode 不声明,只能通过 ctx.executeTool() 被其他工具调用
deferred 不声明,按需由 tool_search 等工具加载
hidden 完全不可见,也不能激活

_getCallableTools(:1567-1572)的规则:

  • codemode 和 deferred 始终可调用;
  • direct 只有在当前活动集合中才可调用;
  • model-only / hidden 不在其中。

7.3 允许/排除与 MCP 特例

_isAllowedTool(:1542-1546):

  1. 命中 excludedToolNames → 不允许;
  2. 没有 allowlist 或命中 allowlist → 允许;
  3. 否则,如果 allowlist 不针对 MCP,则 MCP 工具仍保留注册(供 codemode/tool_search 使用)。

_isActivatable(:1554-1557)进一步限制:未被 allowlist 命中的 MCP 工具,只有在"不是 direct 曝光且 tool_search 已注册"时才能被激活。

这解释了为什么 --tools 没写 mcp__* 时,MCP 工具仍然存在但不会直接出现在模型工具列表里。

7.4 装载(loadout)与 prepareLoadout

_applyToolLoadout(:1580-1625):

  1. 过滤未知、hidden、不可激活的工具;
  2. 收集带 prepareLoadout 的活动工具;
  3. 构建 ToolLoadout(declared / callable / registered / exposure / namespace / guidelines);
  4. 调用每个 hook,收集描述覆盖与 hiddenDeclarations;
  5. 设置 agent.state.tools。

hook 抛错会通过 emitError 报出,但不会中断装载。

_hiddenDeclarations 是"声明给模型的工具列表中需要隐藏的项"。_installHiddenDeclarationsProjection(:1772-1790)在 transformContext 中过滤系统消息里的 toolsAdded / toolsRemoved,保证请求中的工具声明与装载一致。

7.5 系统提示的增量更新

_preparePromptAndToolLoadout(:1743-1755):

  1. 先应用工具装载;
  2. 用当前消息中的系统提示 sections 与目标 sections 做 diff;
  3. 有变化时返回一个 role: "system"、content: ""、带 sections 的消息。

这条系统消息不是完整提示,而是"与模型当前持有的提示之间的补丁"。Agent loop 会把系统消息作为上下文的一部分发送,buildSystemPrompt 在读取时重建完整文本。

7.6 强制提示投影

before_agent_start 可以返回 systemPrompt,要求本轮请求以该文本开头。直接把它作为中途系统消息会保留原来的头部提示,因此 _installAgentForcedPromptProjection(:1792-1807)在 transformContext 末尾:

  • 如果 _runSystemPromptOptions.forceSystemPrompt 有值;
  • 构造一个 head system message,内容为强制文本,携带当前 toolsAdded;
  • 过滤掉其余所有 system message。

这样 transcript 仍保存结构化 sections,只有实际请求被投影成强制文本。

7.7 从 transcript 恢复工具

_restoreToolsFromTranscript(:1815-1825):

  1. 清空 pending;
  2. 读取当前系统消息的 toolsAdded;
  3. 应用 +name / -name 修饰;
  4. 过滤 allowlist;
  5. 设为 pending 并 _setActiveTools(names)。

未注册的工具会留在 _pendingToolNames,等注册时由 _refreshToolRegistry 激活;_startRun 在发起请求前清空 pending,避免永远等待一个不会出现的工具。

7.8 嵌套工具调用

_executeNestedToolCall(:731-765)是 ctx.executeTool() 的实现:

  • 惰性创建 NestedToolCallRunner;
  • 复用 runToolCall,但传入父调用 ID;
  • beforeToolCall / afterToolCall 都带 parentToolCallId;
  • 事件同时发给扩展和公共监听器;
  • 嵌套调用的 usage 与调用记录在 toolResult 的 message_start 时合并到结果消息。

这保证 codemode、tool_search 等"工具调用工具"的场景仍然走统一的权限、钩子和事件管线。

8. 队列、消息注入与并发

8.1 steering 与 followUp

方法 语义 交付时机
steer() 打断当前方向 当前 assistant turn 的工具调用完成后、下一次 LLM 请求前
followUp() 追加后续任务 当前 run 没有更多工具调用和 steering 后

两者都经过 _queueUserInput(:2203-2230):

  1. 拒绝扩展命令(扩展命令不能排队);
  2. input handlers;
  3. skill/template 展开;
  4. 写入显示队列并调用 agent.steer / agent.followUp。

显示队列在对应 user message 的 message_start 时移除,保证 UI 先看到队列更新。

队列模式来自设置:

  • steeringMode / followUpMode:all 或 one-at-a-time;
  • setSteeringMode / setFollowUpMode 会写回设置。

clearQueue 同时清空显示队列和 Agent 队列。

8.2 sendCustomMessage() 的四种情况

sendCustomMessage(:2323-2359)的分支:

状态 triggerTurn 行为
流式中 未显式 false deliverAs: followUp → followUp;否则 steer
流式中 false 放入 _pendingCustomMessages,等 turn 结束(工具结果之后)再追加
空闲 true _startRun({ messageType: "custom" });若正在结算则延迟
空闲 false 立即追加,emit 公共 message_start / message_end

deliverAs: "nextTurn" 优先于以上分支,放入 _pendingNextTurnMessages,在下一次 _prepareRun 中与起始消息一起发送。

流式中延迟追加的原因在注释中写明:立即追加会把消息插在 assistant tool call 与 tool result 之间,部分 provider 在重放时会拒绝这种顺序。

8.3 自定义消息的两条事件路径

  • 进入 Agent loop 的 custom message:走完整 Agent 事件管线,扩展和公共监听器都会收到。
  • 空闲且不触发 turn 的 custom message:_appendCustomMessage(:2361-2371)直接写 SessionManager 并只 emit 公共 message_start / message_end,不经过扩展事件分发。

这是代码中的一处不对称,宿主若依赖扩展观察所有消息事件,需要注意。

8.4 bash 消息的延迟写入

recordBashResult(:3909-3930):

  • 流式中:放入 _pendingBashMessages;
  • 空闲:立即 appendMessage 并刷新投影。

_startRun 在开始前和 finally 中都会 flush,保证 bash 输出不会插进工具调用与结果之间。

8.5 并发保护

AgentSession 没有内部锁,但有几个约束:

  1. prompt() 在流式中必须指定 streamingBehavior,否则抛错;
  2. 手动压缩期间禁止 prompt();
  3. navigateTree() 在流式或压缩期间抛错;
  4. abort() 会等待 idle;
  5. 结算期间的 prompt() / 触发型 custom message 被延迟。

测试 AgentSession concurrent prompt guard 覆盖了并发 prompt、流式 steer/followUp、慢扩展 handler 下的持久化顺序。

9. 压缩

9.1 手动压缩 compact()

compact(customInstructions?)(:2794-2939):

  1. 先 await abort(),中止当前 run 并等待 idle;
  2. 创建 _compactionAbortController,emit compaction_start { reason: "manual" };
  3. 需要模型;
  4. prepareCompaction(branchEntries, settings):
    • 最后一条已经是 compaction → 抛 "Already compacted";
    • 无法切分 → 抛 "Nothing to compact";
  5. session_before_compact 扩展钩子:
    • cancel → 抛 "Compaction cancelled";
    • 提供 compaction → 使用扩展结果,fromExtension = true;
  6. 否则走 _runDefaultCompaction;
  7. 检查 abort;
  8. appendCompaction(...);
  9. _refreshFinalizedContext();
  10. emit session_compact;
  11. 先清除手动压缩状态,再 emit compaction_end,允许监听器在事件里提交新 prompt;
  12. 失败时 emit compaction_end 与 session_compact_failed,然后重新抛出。

手动压缩不会自动重试或继续被打断的 turn。

9.2 自动压缩的三个入口

_checkCompaction(:2977-3115)区分三种情况:

情况 条件 行为
溢出 + 重试 上下文溢出或可恢复的 length stop,且响应未正常结束 省略失败响应,压缩,agent.continue() 重试一次
溢出不重试 响应正常结束但上下文溢出 压缩,保留已完成响应,不重试
阈值不重试 上下文 token 超过 contextWindow - reserveTokens 压缩,不重试

关键保护:

  1. 溢出与 length stop 判定要求消息来自当前模型。切换模型后,旧模型的溢出错误不会触发新模型的溢出恢复。
  2. 消息不能早于最近一次压缩。避免压缩后第一条 prompt 被旧 usage 再次触发。
  3. 存在 context_edit 时改用投影估算;错误响应或零 usage 时改用消息估算,避免直接使用不可信的 usage。
  4. 溢出恢复只尝试一次 。_overflowRecoveryAttempted 为 true 时直接报失败,避免无限循环。
  5. 恢复省略是持久的 。_omitRecoveryAttempt(:1241-1257)为失败响应及其工具结果追加 context_edit(replacement = null),让它们保留在原始历史中但从模型投影中消失。

阈值计算:

ts 复制代码
contextTokens > contextWindow - reserveTokens

默认 reserveTokens = 16384,keepRecentTokens = 20000(compaction.ts:126-130)。

9.3 自动压缩执行

_runAutoCompaction(:3127-3274):

  1. 取模型和设置;无模型直接返回 false;
  2. prepareCompaction;无法准备返回 false;
  3. 创建 _autoCompactionAbortController,emit compaction_start;
  4. session_before_compact 可取消或提供结果;
  5. 默认压缩或扩展结果;
  6. appendCompaction、刷新投影、emit session_compact;
  7. emit compaction_end;
  8. 返回:
    • willRetry 为 true → 让外层继续;
    • 否则如果有排队消息 → 继续一次以交付消息;
  9. 失败时 emit compaction_end(带错误)和 session_compact_failed,返回 false。

9.4 下一轮请求前的压缩

_compactBeforeNextAssistantResponse(:777-786)在 prepareNextTurnWithContext 中执行:

  • 只对非虚拟模型做阈值检查;
  • 虚拟模型在 prepareRequest 中按实际路由模型检查;
  • 压缩后用新的投影消息替换上下文。

9.5 分支摘要

navigateTree(:3994-4186)在树导航时可选摘要:

  1. 流式或压缩中禁止;
  2. 目标就是当前 leaf → no-op;
  3. collectEntriesForBranchSummary 收集旧 leaf 到公共祖先之间的条目;
  4. session_before_tree 可取消、提供 summary、覆盖指令/label;
  5. 否则 generateBranchSummary,使用与压缩相同的重试策略;
  6. 目标如果是 user message 或 custom message,leaf 设为父节点,文本回填编辑器;
  7. 有摘要时 branchWithSummary,无摘要时 branch 或 resetLeaf;
  8. _refreshFinalizedContext() 和 _restoreToolsFromTranscript();
  9. emit session_tree。

10. 重试

10.1 判定

_isRetryableError(:3739-3743):

  • 先排除上下文溢出(由压缩处理);
  • 其余交给 isRetryableAssistantError。

10.2 退避与省略

_prepareRetry(:3792-3832):

  1. 读取 retry 设置;未启用返回 false;
  2. _retryAttempt++;超过 maxRetries 时回退计数并返回 false;
  3. retryDelayMs(settings, attempt) 计算延迟;
  4. emit auto_retry_start;
  5. _omitRecoveryAttempt(message) 把失败响应从模型投影中省略;
  6. 用 _retryAbortController 可中止地 sleep;
  7. 成功返回 true,调用方 agent.continue()。

_failedResponse 保存被省略的失败响应,_installAgentRequestProjection 在重试请求中把它作为 failed 传给虚拟模型路由(:823-828)。

10.3 结束与取消

  • 非 error 的 assistant 响应且 _retryAttempt > 0 → emit auto_retry_end { success: true } 并清零(:1178-1187)。
  • 非可重试错误且 attempt > 0 → emit 失败事件并清零(:1964-1972)。
  • abort → _finishCancelledRetry emit "Retry cancelled"。
  • abortRetry() 只中止 sleep。

10.4 摘要重试

压缩和分支摘要共享 _summarizationRetryCallbacks(:3751-3774),把重试过程映射为:

  • summarization_retry_scheduled
  • summarization_retry_attempt_start(带 source)
  • summarization_retry_finished

使用与 agent turn 相同的 retry 预算和退避,避免一次瞬时流错误让整个压缩失败。

11. 模型与 thinking

11.1 认证

_getRequiredRequestAuth(:533-571):

  • 调 modelRuntime.getAuth;
  • 有 apiKey 或 headers 时,允许 baseUrl 覆盖;
  • 过滤值为 null 的 header(表示删除);
  • OAuth 失败给出 /login 指引;
  • 否则给出 formatNoApiKeyFoundMessage。

_getSummarizationRequestAuth(:573-610):

  • 虚拟模型先路由到物理模型;
  • 如果 Agent 使用自定义 streamFunction,认证失败时允许继续(自定义实现可能自带认证);
  • 否则返回解析后的模型、认证和 thinking level。

11.2 setModel() 与 cycleModel()

setModel(:2507-2527):

  1. checkAuth,失败抛错;
  2. 计算新模型的 thinking level;
  3. 写 agent.state.model;
  4. appendModelChange(始终写入会话);
  5. options.persist 时写全局默认,并加入非空 scoped 列表;
  6. setThinkingLevel;
  7. emit model_select。

cycleModel(:2549-2630):

  • 有 scoped models 时只在 scoped 中循环,并保留每个 scoped 的 thinking 偏好;
  • 否则在可用模型快照中循环;
  • 只有一个模型时返回 undefined;
  • 默认只改会话,不写全局。

11.3 thinking level

setThinkingLevel(:2642-2665):

  1. 取模型支持等级;
  2. 不在支持列表时 clampThinkingLevel;
  3. 只有实际变化才 appendThinkingLevelChange、emit 公共 thinking_level_changed 与扩展 thinking_level_select;
  4. options.persist 时把"请求值"写入全局默认(不是 clamp 后的值)。

_getThinkingLevelForModelSwitch(:2699-2711)优先级:

  1. 显式传入;
  2. 目标模型的 per-model 设置;
  3. 全局默认;
  4. 当前会话值;
  5. DEFAULT_THINKING_LEVEL。

11.4 虚拟模型路由

虚拟模型不是真实 provider/model,而是路由器。相关逻辑:

  • routedModel(:1456-1461):从最近成功响应找物理模型;
  • _limitsModel(:641-643):压缩、图片等限制使用路由后的模型;
  • _modelForMessage(:616-620):判断一条 assistant 消息是否属于当前模型;
  • _recordSelection(:629-638):当分支隐含的选择与当前不同,且涉及虚拟模型时,写入 model_change,保证 resume 能恢复;
  • _installAgentRequestProjection(:788-845):
    • 用投影替换请求上下文;
    • 调用 resolveModel 得到实际模型与 thinking;
    • 持久化路由器状态变化(VIRTUAL_MODEL_STATE_ENTRY);
    • 如果路由后的模型超过阈值,先压缩再重新准备请求。

只有用户消息开始新 turn 时使用 reason: "user";扩展消息跟随其后时使用 continuation;重试使用 retry 并带 failed 响应。

12. 扩展系统集成

12.1 绑定

bindExtensions(bindings)(:3288-3312):

  1. 只在字段非 undefined 时更新绑定,允许部分更新;
  2. _applyExtensionBindings 设置 UI context、命令上下文、错误监听;
  3. emit _sessionStartEvent;
  4. reportUnhandledMcpServers();
  5. extendResourcesFromExtensions(...)。

_sessionStartEvent 默认 { type: "session_start", reason: "startup" }。运行时替换后由宿主重新绑定,因此新会话会收到自己的 session_start。

12.2 注入给扩展的核心能力

_bindExtensionCore(:3390-3523)把 AgentSession 的能力绑定给 ExtensionRunner:

能力 行为
sendMessage / sendUserMessage 转发到 AgentSession,错误通过 runner 报出
appendEntry 写 custom entry 并 emit entry_appended
setSessionName / getSessionName 会话命名
setLabel 给条目加 label
getActiveTools / getAllTools / setActiveTools / refreshTools 工具查询与修改
setModel / getThinkingLevel / setThinkingLevel 模型控制
abort / shutdown 中止或请求宿主退出
compact 异步手动压缩,带 onComplete/onError
getSystemPrompt / getSystemPromptOptions 读取当前提示
executeTool / getCallableTools 嵌套工具调用
registerProvider / registerNativeProvider / registerVirtualModel 等 动态注册,随后刷新当前模型

12.3 重载 reload()

reload(:3690-3729)不替换会话对象,只替换扩展运行时和工具:

  1. 记录旧 runner 与 flag values;
  2. emit session_shutdown { reason: "reload" };
  3. invalidate 旧 runner;
  4. settingsManager.reload();
  5. 同步队列模式;
  6. resetApiProviders();
  7. resourceLoader.reload();
  8. 计算新增的 default tools;
  9. 把当前活动工具加入 pending;
  10. _buildRuntime(...) 重建 runner 和工具;
  11. 如果有绑定,执行 beforeSessionStart,emit session_start { reason: "reload" },报告 MCP,扩展资源。

重载期间旧扩展上下文会失效,扩展必须把后续工作放到重载之后。

12.4 扩展命令与资源

  • _tryExecuteExtensionCommand(:2146-2170):解析命令名,取 createCommandContext(),执行;错误通过 emitError 报出,但仍视为已处理。
  • _expandSkillCommand(:2177-2201):读取 skill 文件并包装。
  • extendResourcesFromExtensions(:3314-3336):resources_discover 返回的 skill/prompt/theme 路径以 temporary 作用域加入 ResourceLoader,并重建系统提示。

13. 持久化与上下文投影

13.1 投影是权威来源

_refreshFinalizedContext(:939-945):

  1. sessionManager.buildSessionProjection();
  2. 建立"消息对象 → 源条目 ID"映射;
  3. agent.state.messages = projection.messages。

调用点包括:

场景 位置
手动压缩后 compact()
自动压缩后 _runAutoCompaction()
恢复省略 _omitRecoveryAttempt()
边界 drafts 提交 _commitBoundaryDrafts()
直接追加 custom message _appendCustomMessage()
bash 消息 flush _flushPendingBashMessages()
树导航 navigateTree()
运行时 setup 后 AgentSessionRuntime 调 refreshContext()

refreshContext() 是公开入口,供会话替换的 setup 阶段重建 transcript。

13.2 投影模型

buildSessionProjection(session-manager.ts:543-573):

  1. 从 leaf 沿父链构建路径;
  2. 取路径上的 thinking level 和 model;
  3. buildContextEntries 处理压缩边界、分支摘要、context edit;
  4. 对每个源条目生成 ProjectedSessionEntry:
    • sourceEntry:原始条目;
    • messages:投影后的消息(可能为空);
  5. 返回 entries、扁平化 messages、thinkingLevel、model。

这使压缩、上下文编辑、恢复省略都不需要修改原始历史,只影响投影。

13.3 条目类型与写入 API

SessionManager 的条目包括:

  • message
  • thinking_level_change
  • model_change
  • usage
  • compaction
  • branch_summary
  • custom
  • custom_message
  • label
  • session_info
  • context_edit

AgentSession 使用的主要写入 API:

API 用途
appendMessage 普通消息与 bashExecution
appendCustomMessageEntry 扩展 custom message
appendCustomEntry 扩展 custom 数据
appendCompaction 压缩摘要
appendModelChange 模型切换
appendThinkingLevelChange thinking 切换
appendContextEdit 恢复省略或边界替换
appendLabelChange 条目标签
appendSessionInfo 会话名称

13.4 树导航

navigateTree 的 leaf 规则:

  • 目标是 user message:leaf = 父节点,文本回填编辑器;
  • 目标是 custom message:leaf = 父节点,文本回填编辑器;
  • 其他目标:leaf = 目标本身。

有摘要时摘要条目挂在新 leaf 位置;无摘要且目标为根时 resetLeaf()。

14. Bash、统计、导出与其它能力

14.1 Bash

executeBash(:3871-3903):

  • 创建独立的 abort controller;
  • 应用 shellCommandPrefix;
  • 用 sessionManager.getCwd() 作为工作目录;
  • 支持注入 BashOperations(远程执行);
  • 输出增量通过回调与 bash_execution_update 事件发出;
  • 结果交给 recordBashResult。

abortBash 中止所有活动 bash;isBashRunning / hasPendingBashMessages 提供状态。

14.2 统计与上下文使用

getSessionStats(:4213-4265):

  • 遍历所有条目,不只当前分支,因此包含被压缩掉的历史;
  • 统计 user/assistant/toolResult/toolCalls;
  • 累加 usage 条目、branch summary/compaction 的 usage、toolResult usage、assistant usage;
  • contextUsage 来自 getContextUsage()。

getContextUsage(:4267-4310):

  • 无模型或无 contextWindow → undefined;
  • 最近一次压缩之后没有有效 assistant usage → { tokens: null, percent: null };
  • 否则用 estimateProjectedContextTokens 计算。

14.3 导出与报告

方法 作用
exportToHtml 导出 HTML,支持扩展工具渲染器和主题
exportToJsonl 导出当前分支为 JSONL
summarizeForBugReport 用当前模型生成 bug report 摘要
getLastAssistantText 供 /copy 使用

14.4 缓存预热

  • cacheWarmingStatus 读取 warmer 状态;
  • setCacheWarmingMode 写设置并立即协调;
  • onWarmed 时 emit entry_appended;
  • dispose 时取消并清空回调。

15. 生命周期、失败语义与边界条件

15.1 abort()

abort(:2464-2474):

  1. 如果 run 活跃,设置 _agentRunAbortRequested;
  2. 中止 retry、compaction、branch summary;
  3. 如果在 before-settle 中,标记 _abortDuringBeforeSettle;
  4. agent.abort();
  5. await waitForIdle()。

15.2 dispose()

dispose(:1397-1418):

  1. 尽力中止 retry/compaction/branch/bash/agent;
  2. extensionRunner.invalidate(...),错误信息明确要求使用替换后的新 ctx;
  3. 断开 Agent 订阅;
  4. 清空公共监听器;
  5. 取消 cache warmer;
  6. cleanupSessionResources(sessionId)。

它不等待 idle;运行时替换路径会先 await session.abort() 再 dispose,退出路径则直接 dispose。因此退出时未完成的 turn 不保证像替换路径那样完成持久化。

15.3 失败语义

场景 结果
_prepareRun 失败 _isAgentRunActive 复位,flush 队列,抛出
agent.prompt / 循环失败 finally 结算后抛出
手动压缩失败 emit compaction_end + session_compact_failed,重新抛出
自动压缩失败 emit 事件,返回 false,run 继续按失败响应处理
重试耗尽 emit auto_retry_end { success: false }
溢出恢复失败 emit compaction_end + session_compact_failed,结束
扩展 handler 抛错 tool_call 直接抛;命令错误通过 emitError;边界错误记录后按不可继续处理

15.4 值得注意的边界

  1. isIdle 不包含 bash 。用户可以运行 ! 命令而会话仍被视为 idle;abort() 不会调用 abortBash(),取消用户主动运行的 bash 需要显式调用 abortBash() 或 dispose()。
  2. 流式中的 custom message 默认是 steer 。sendCustomMessage 未显式 triggerTurn: false 时,默认按 steer 排队。
  3. pending 工具只等一次 run 。_startRun 在请求前清空 _pendingToolNames,未注册的工具不会永久挂起。
  4. 直接追加的 custom message 不走扩展 message 事件。见 8.3。
  5. _runSystemPromptOptions 在 run 结束后清空 。systemPrompt getter 之后回落到基础提示。
  6. _failedResponse 只用于下一次请求 。_installAgentRequestProjection 读取后立即清空。
  7. 虚拟模型的 model_change 记录有条件。物理选择通常由响应本身记录,只有涉及虚拟模型时才额外写入。
  8. 上下文溢出恢复只一次。第二次仍溢出会明确报错,要求减少上下文或换更大窗口模型。
  9. 压缩后上下文使用量未知 。直到压缩后出现新的有效 assistant usage,getContextUsage 返回 null。
  10. 树导航会恢复工具装载 。导航后调用 _restoreToolsFromTranscript(),因此分支记录的工具列表会重新生效。

16. 设计评价

优点

  1. 职责集中但不越界

    AgentSession 管理会话编排,不负责 CLI 参数、认证存储、项目信任;这些留在 AgentSessionRuntime 和工厂闭包中。

  2. 投影作为单一事实来源

    压缩、上下文编辑、恢复省略都通过 SessionManager 条目表达,Agent state 在固定点刷新。这样持久化、恢复和请求投影共用同一套逻辑。

  3. 事件顺序有明确契约

    扩展先于公共监听器;message_end 替换在持久化前完成;agent_settled 在所有 handler 之后。多个回归测试保护这些顺序。

  4. 压缩与重试的边界处理细致

    区分"溢出但有响应""溢出且失败""阈值压缩""length stop 恢复",并用 context_edit 持久化省略,避免重放时再次触发。

  5. 工具装载模型表达力强

    五种曝光级别、allowlist/exclude、pending 工具、prepareLoadout、从 transcript 恢复,覆盖了内置工具、MCP、codemode、tool_search 的组合。

  6. 扩展能力完整

    扩展可以观察事件、修改消息、拦截工具、注入消息、注册模型/工具/资源、执行嵌套工具,并有明确的 stale 上下文保护。

代价与风险

  1. 状态机复杂

    _isAgentRunActive、_isBeforeSettle、_isEmittingAgentSettled、多个 abort controller 和 pending 队列共同决定行为。理解一次 run 的完整时序需要跨多个方法阅读。

  2. 隐式顺序约束多

    例如:

    • 先 abort 再压缩;
    • 先 flush 再结算;
    • 先扩展事件再持久化;
    • 先提交边界 drafts 再判断能否继续;
    • 先清除压缩状态再 emit compaction_end。
      这些顺序大多靠注释和测试维持,类型系统无法强制。
  3. 部分路径存在不对称

    直接追加的 custom message 不走扩展 message 事件;bash 消息不 emit message_end;不同来源的消息经过不同的事件路径。

  4. 没有内部并发锁

    并发 prompt / navigateTree 靠显式检查和调用方约定,而不是状态机拒绝。扩展或 SDK 误用可能造成交错。

  5. 投影刷新是手动的

    新增一条绕过 message_end 的写入路径时,必须记得调用 _refreshFinalizedContext(),否则 Agent state 与 SessionManager 会不一致。

  6. dispose 与 abort 语义不同

    退出路径不保证未完成 turn 的持久化结算,宿主需要显式先 abort。

总体而言,AgentSession 是一个"事件驱动的会话状态机 + 投影刷新器":它把 Agent 的通用循环适配成 coding agent 需要的持久化、压缩、重试、扩展和工具语义。复杂度主要来自这些横切关注点的交织,而不是单个算法。

17. 关键不变量

以下是代码中反复依赖、修改时必须保持的约束:

  1. 一条消息在持久化前必须已经完成扩展 message_end 处理。
  2. message_end 替换必须原地修改对象,否则 Agent state、事件监听器和持久化会看到不同对象。
  3. 压缩、上下文编辑、恢复省略之后必须刷新投影。
  4. 任何会写入条目的路径都必须推进 leaf 或显式刷新(SessionManager 的 append 会推进 leaf)。
  5. _pendingCustomMessages 只能在 turn 结束后 flush,否则会插在 tool call 与 tool result 之间。
  6. _pendingBashMessages 只能在 run 开始前或结束后 flush。
  7. _startRun 的 finally 必须结算 ,否则 isIdle 永远为 false,waitForIdle() 会挂起。
  8. 扩展 runner 失效后不能继续使用旧 ctx ;dispose / reload 都会 invalidate。
  9. 工具声明与可执行工具必须一致 :_hiddenDeclarations 要同步到系统提示补丁和请求投影。
  10. 溢出恢复最多一次,且省略必须持久化,不能只改内存。

18. 关键代码索引

位置 内容
agent-session.ts:166 ParsedSkillBlock
agent-session.ts:177 parseSkillBlock
agent-session.ts:196 AgentSessionEvent
agent-session.ts:252 AgentSessionConfig
agent-session.ts:302 ExtensionBindings
agent-session.ts:315 PromptOptions
agent-session.ts:343 SessionStats
agent-session.ts:379 AgentSession 类
agent-session.ts:486 构造函数
agent-session.ts:533 _getRequiredRequestAuth
agent-session.ts:573 _getSummarizationRequestAuth
agent-session.ts:616 _modelForMessage
agent-session.ts:629 _recordSelection
agent-session.ts:653 _installAgentToolHooks
agent-session.ts:659 _beforeToolCall
agent-session.ts:685 _afterToolCall
agent-session.ts:731 _executeNestedToolCall
agent-session.ts:768 _exceedsCompactionThreshold
agent-session.ts:777 _compactBeforeNextAssistantResponse
agent-session.ts:788 _installAgentRequestProjection
agent-session.ts:847 _dispatchTurnEndBoundary
agent-session.ts:887 _installAgentBoundaryHooks
agent-session.ts:899 _installAgentNextTurnRefresh
agent-session.ts:939 _refreshFinalizedContext
agent-session.ts:947 _applyBoundaryDrafts
agent-session.ts:988 _createBoundaryPreviewManager
agent-session.ts:1000 _buildBoundaryContext
agent-session.ts:1079 _emitAgentSettled
agent-session.ts:1104 _handleAgentEvent
agent-session.ts:1202 _willRetryAfterAgentEnd
agent-session.ts:1218 _findPersistedMessageEntryId
agent-session.ts:1241 _omitRecoveryAttempt
agent-session.ts:1271 _replaceMessageInPlace
agent-session.ts:1288 _emitExtensionEvent
agent-session.ts:1373 subscribe
agent-session.ts:1397 dispose
agent-session.ts:1425 refreshContext
agent-session.ts:1456 routedModel
agent-session.ts:1464 isStreaming
agent-session.ts:1469 isIdle
agent-session.ts:1523 setActiveToolsByName
agent-session.ts:1542 _isAllowedTool
agent-session.ts:1554 _isActivatable
agent-session.ts:1567 _getCallableTools
agent-session.ts:1580 _applyToolLoadout
agent-session.ts:1705 _rebuildSystemPrompt
agent-session.ts:1743 _preparePromptAndToolLoadout
agent-session.ts:1772 _installHiddenDeclarationsProjection
agent-session.ts:1792 _installAgentForcedPromptProjection
agent-session.ts:1815 _restoreToolsFromTranscript
agent-session.ts:1837 _startRun
agent-session.ts:1890 _prepareRun
agent-session.ts:1943 _handlePostAgentRun
agent-session.ts:1983 _runBeforeSettleBoundary
agent-session.ts:2007 _runInputHandlers
agent-session.ts:2027 _normalizePromptImages
agent-session.ts:2058 prompt
agent-session.ts:2146 _tryExecuteExtensionCommand
agent-session.ts:2177 _expandSkillCommand
agent-session.ts:2203 _queueUserInput
agent-session.ts:2241 steer
agent-session.ts:2257 followUp
agent-session.ts:2323 sendCustomMessage
agent-session.ts:2361 _appendCustomMessage
agent-session.ts:2377 _flushPendingCustomMessages
agent-session.ts:2395 sendUserMessage
agent-session.ts:2432 clearQueue
agent-session.ts:2464 abort
agent-session.ts:2476 waitForIdle
agent-session.ts:2507 setModel
agent-session.ts:2549 cycleModel
agent-session.ts:2642 setThinkingLevel
agent-session.ts:2699 _getThinkingLevelForModelSwitch
agent-session.ts:2794 compact
agent-session.ts:2944 abortCompaction
agent-session.ts:2977 _checkCompaction
agent-session.ts:3127 _runAutoCompaction
agent-session.ts:3288 bindExtensions
agent-session.ts:3314 extendResourcesFromExtensions
agent-session.ts:3390 _bindExtensionCore
agent-session.ts:3525 _refreshToolRegistry
agent-session.ts:3636 _buildRuntime
agent-session.ts:3690 reload
agent-session.ts:3739 _isRetryableError
agent-session.ts:3751 _summarizationRetryCallbacks
agent-session.ts:3776 _finishCancelledRetry
agent-session.ts:3792 _prepareRetry
agent-session.ts:3871 executeBash
agent-session.ts:3909 recordBashResult
agent-session.ts:3935 abortBash
agent-session.ts:3994 navigateTree
agent-session.ts:4213 getSessionStats
agent-session.ts:4267 getContextUsage
agent-session.ts:4318 exportToHtml
agent-session.ts:4344 exportToJsonl
agent-session.ts:4352 summarizeForBugReport
agent-session.ts:4405 createReplacedSessionContext
sdk.ts:411 new Agent
sdk.ts:461 new AgentSession
session-manager.ts:543 buildSessionProjection
session-manager.ts:1204 appendMessage
session-manager.ts:1261 appendCompaction
session-manager.ts:1339 appendCustomMessageEntry
session-manager.ts:1360 appendContextEdit
compaction.ts:267 shouldCompact
compaction.ts:859 prepareCompaction
compaction.ts:952 compact
messages.ts:148 convertToLlm

19. 测试覆盖

与 AgentSession 直接相关的测试:

测试文件 覆盖内容
test/suite/agent-session-prompt.test.ts 普通 prompt、工具 turn、多工具、图片、skill/template 展开、扩展命令、流式校验、自定义消息启动的 run
test/suite/agent-session-queue.test.ts steering/followUp 顺序、模式、custom message 投递、nextTurn、队列计数、扩展命令拒绝
test/suite/agent-session-retry-events.test.ts 重试成功/耗尽/取消、事件顺序、流式增量、错误与中止的 agent_end
test/suite/agent-session-compaction.test.ts 手动/自动压缩、扩展摘要、排队 prompt、溢出恢复、length stop、中止
test/suite/agent-session-boundaries.test.ts turn_end / agent_before_settle 边界、drafts、恢复省略、length recovery、结算延迟
test/suite/agent-session-tool-orchestration.test.ts 嵌套工具调用、codemode/tool_search 激活
test/suite/agent-session-mcp.test.ts MCP 工具的 allowlist/exclude/exposure、resume/reload
test/suite/agent-session-model-extension.test.ts 模型/thinking 切换与持久化、扩展钩子、bindExtensions / reload 事件
test/suite/agent-session-bash-persistence.test.ts bash 记录、流式延迟、取消、消息持久化顺序
test/suite/agent-session-tool-result-images.test.ts 工具结果图片归一化
test/suite/agent-session-compaction-model-overrides.test.ts 压缩使用新选模型、模型身份捕获
test/suite/agent-session-runtime.test.ts message_end 替换持久化、替换前结算、运行时替换
test/suite/regressions/1717-2113-agent-session-event-settlement.test.ts 慢扩展 handler 下的持久化顺序、tool_call 在消息结算后执行
test/agent-session-concurrent.test.ts 并发 prompt 守卫、流式 steer/followUp、慢 handler 顺序
test/agent-session-auto-compaction-queue.test.ts 阈值压缩后的队列恢复、溢出只重试一次、陈旧 usage
test/agent-session-branching.test.ts fork/分支
test/agent-session-tree-navigation.test.ts 树导航与分支摘要
test/agent-session-stats.test.ts 统计与上下文使用量
test/agent-session-dynamic-tools.test.ts 动态工具注册与刷新
test/agent-session-dynamic-provider.test.ts 动态 provider 注册与当前模型刷新
test/agent-session-runtime-events.test.ts 运行时事件顺序、取消、rebind 顺序
相关推荐
for_ever_love__1 小时前
检索工具化封装:把 Elasticsearch、SQL、Confluence 包装成 Agent 的统一工具
agent·工具·封装·调用·rag·检索·做成
guslegend1 小时前
注意力稀释:当 113 个工具让模型降智时,工程师该怎么做?
agent
梦醒江南1 小时前
Agent 卡在网页上时,为什么不能换个真实入口继续?
人工智能·agent
用户460381291941 小时前
MCP 给了 Agent 一堆“手”,Skill 才教它怎么干活:两者到底什么关系?
agent·mcp
for_ever_love__2 小时前
Agentic RAG 实战:让 Agent 自己决定怎么检索、检索几次
人工智能·后端·agent·控制·自适应·rag·检索策略
大模型真好玩2 小时前
用TRAE、DeepSeek-Harness、DeepSeek-V4.1-Flash-1017再现特斯拉Roadster汽车飞行名场面
人工智能·agent·deepseek
遇码2 小时前
不用转场引擎做幻灯片转场:相机滑动、黑场淡入与真全屏的完整做法
人工智能·数码相机·ai·rust·大模型·agent
薛定谔的猫-菜鸟程序员3 小时前
22 分 10 秒 vs 2 小时 44 分:AtomCode 与 opencode 项目开发对比实测,国产agent Atomcode 这么猛吗?
agent·opencode·atomcode
Eloudy3 小时前
ADR-042: Gas Town 与 Beads 分析 —— 对 Claude Flow V3 的启示
agent