跳转至

52. System prompt 与 compaction:上下文怎样组装、缩短再回灌

这个模块干什么

system-prompt.ts 把 active tools、工具规则、项目 context files、skills、append prompt 和 cwd 拼成底层 Agent 的 system prompt。 【packages/coding-agent/src/core/system-prompt.ts:8-28】

prompt-templates.ts 处理的是用户输入 /name args 的模板展开,不是 system prompt 的一部分。 【packages/coding-agent/src/core/prompt-templates.ts:265-285】

compaction 在 context 接近窗口上限或已经 overflow 时,把较老的活动分支内容总结成一个 CompactionEntry,同时保留近期 entries。 【packages/coding-agent/src/core/compaction/compaction.ts:232-238】 【packages/coding-agent/src/core/compaction/compaction.ts:710-788】

摘要重新进入 context 时会变成 compactionSummary 自定义消息,再投影成带 <summary> 的 user message。 【packages/coding-agent/src/core/session-manager.ts:401-406】 【packages/coding-agent/src/core/messages.ts:176-183】

核心文件速查

文件 一句话职责 必读优先级
core/agent-session.ts 决定何时 build prompt、何时触发手动/自动 compaction,以及完成后如何更新 Agent state。 【packages/coding-agent/src/core/agent-session.ts:1021-1055】 【packages/coding-agent/src/core/agent-session.ts:1774-2215】 ⭐⭐⭐
core/system-prompt.ts 组装默认或 custom system prompt,并追加 context files、skills 和 cwd。 【packages/coding-agent/src/core/system-prompt.ts:27-71】 【packages/coding-agent/src/core/system-prompt.ts:74-162】 ⭐⭐⭐
core/prompt-templates.ts 加载 Markdown 模板,解析参数并在用户 prompt 阶段展开。 【packages/coding-agent/src/core/prompt-templates.ts:8-18】 【packages/coding-agent/src/core/prompt-templates.ts:188-285】 ⭐⭐
core/compaction/compaction.ts 计算 token、选择切点、准备摘要输入、调用模型并产出 CompactionResult。 【packages/coding-agent/src/core/compaction/compaction.ts:126-238】 【packages/coding-agent/src/core/compaction/compaction.ts:710-918】 ⭐⭐⭐
core/compaction/utils.ts 跟踪读写文件、序列化对话、限制 tool result,并定义 summarizer system prompt。 【packages/coding-agent/src/core/compaction/utils.ts:12-82】 【packages/coding-agent/src/core/compaction/utils.ts:88-158】 ⭐⭐⭐
core/compaction/branch-summarization.ts 在 tree navigation 时总结被离开的分支,复用同一 summarization choke point。 【packages/coding-agent/src/core/compaction/branch-summarization.ts:96-146】 【packages/coding-agent/src/core/compaction/branch-summarization.ts:287-375】 ⭐⭐
core/session-manager.ts 保存 compaction entry,并把最新摘要与 kept entries 投影回 active context。 【packages/coding-agent/src/core/session-manager.ts:69-80】 【packages/coding-agent/src/core/session-manager.ts:410-470】 ⭐⭐⭐
core/messages.ts 定义摘要消息的固定包装文本和 convertToLlm() 投影。 【packages/coding-agent/src/core/messages.ts:11-24】 【packages/coding-agent/src/core/messages.ts:170-183】 ⭐⭐⭐

精读

1. 先从 AgentSession._rebuildSystemPrompt() 看真实输入来源

简化签名:

private _rebuildSystemPrompt(toolNames: string[]): string

它先丢掉 registry 中不存在的名字,只为 active tools 收集 promptSnippetpromptGuidelines。 【packages/coding-agent/src/core/agent-session.ts:1021-1035】

tool snippet 被规范成单行,guideline 会 trim、去空和去重。 【packages/coding-agent/src/core/agent-session.ts:997-1019】

随后从 ResourceLoader 读取 system prompt override、append system prompts、skills 和 AGENTS/CLAUDE context files。 【packages/coding-agent/src/core/agent-session.ts:1037-1043】

最终保存的 BuildSystemPromptOptions 包含 cwd、skills、contextFiles、customPrompt、appendSystemPrompt、selectedTools、toolSnippets 和 promptGuidelines。 【packages/coding-agent/src/core/agent-session.ts:1044-1054】

这份 options 不只用于首次构造;extensions 还能通过 context 查询它,before_agent_start 也会拿到 base prompt 和 options。 【packages/coding-agent/src/core/agent-session.ts:1224-1230】 【packages/coding-agent/src/core/agent-session.ts:2422-2436】

active tools 改变时,setActiveToolsByName() 会立即重建 base system prompt。 【packages/coding-agent/src/core/agent-session.ts:920-941】

resources/extensions reload 后也会重建 prompt,使新增 skills、context files 和工具 metadata 生效。 【packages/coding-agent/src/core/agent-session.ts:2254-2277】

2. buildSystemPrompt() 的 custom 分支与 default 分支

简化签名:

function buildSystemPrompt(options: BuildSystemPromptOptions): string

所有路径都会先把 Windows cwd 的反斜杠换成 /。 【packages/coding-agent/src/core/system-prompt.ts:28-41】

customPrompt 时,默认 pi persona、工具列表和 guidelines 整段都不生成;custom text 成为主体。 【packages/coding-agent/src/core/system-prompt.ts:46-52】

但 custom prompt 之后仍会追加 append prompt、project context、可用 skills 和 current working directory。 【packages/coding-agent/src/core/system-prompt.ts:46-71】

skills 只有 active tools 中存在 read 时才写入;selectedTools 未提供时按默认有 read 处理。 【packages/coding-agent/src/core/system-prompt.ts:63-67】

default 分支先确定 tools,默认值是 readbasheditwrite。 【packages/coding-agent/src/core/system-prompt.ts:79-84】

“Available tools” 只展示同时存在 one-line snippet 的 active tool;没有 snippet 的工具仍可能在 Agent tools 数组里,但列表中不可见。 【packages/coding-agent/src/core/system-prompt.ts:79-84】

当有 bash、却没有独立 grep/find/ls 时,默认 guideline 才会加入 “Use bash for file operations like ls, rg, find”。 【packages/coding-agent/src/core/system-prompt.ts:97-106】

工具自带 guidelines 随后加入同一个有序去重集合。 【packages/coding-agent/src/core/system-prompt.ts:86-113】

最后无条件加入 concise 和清晰显示文件路径两条规则。 【packages/coding-agent/src/core/system-prompt.ts:115-119】

默认主体还包含 pi 文档、docs、examples 的绝对路径,以及遇到 pi 自身问题时的阅读规则。 【packages/coding-agent/src/core/system-prompt.ts:121-138】

append prompt 位于默认主体之后、project context 之前。 【packages/coding-agent/src/core/system-prompt.ts:140-152】

每个 context file 用 <project_instructions path="..."> 独立包装,外层是 <project_context>。 【packages/coding-agent/src/core/system-prompt.ts:144-152】

skills 块在 project context 后追加,cwd 永远位于末尾。 【packages/coding-agent/src/core/system-prompt.ts:154-161】

3. per-turn prompt override:base prompt 可以临时变,但不会永久污染

每次普通 prompt 在 before_agent_start 前已经得到 _baseSystemPrompt。 【packages/coding-agent/src/core/agent-session.ts:1224-1230】

扩展返回 systemPrompt 时,本轮写入 _systemPromptOverrideagent.state.systemPrompt。 【packages/coding-agent/src/core/agent-session.ts:1245-1253】

如果扩展未返回 override,则显式恢复 base prompt,避免上一轮临时值泄漏。 【packages/coding-agent/src/core/agent-session.ts:1245-1253】

同一轮出现多次 LLM 请求时,next-turn refresh 会继续使用 override;工具调用续轮不会突然退回 base prompt。 【packages/coding-agent/src/core/agent-session.ts:520-540】

整个 agent run 结束后,finally 清掉 _systemPromptOverride。 【packages/coding-agent/src/core/agent-session.ts:1061-1072】

4. prompt-templates.ts:这是 user prompt 宏,不是 system prompt loader

PromptTemplate 保存 name、description、argumentHint、body、sourceInfo 和绝对 filePath。 【packages/coding-agent/src/core/prompt-templates.ts:8-18】

模板参数解析支持单引号和双引号,但没有 shell escaping 语义;引号只负责把空格留在同一个 argument。 【packages/coding-agent/src/core/prompt-templates.ts:20-55】

替换语法包括 $1$@$ARGUMENTS${N:-default}${@:N}${@:N:L}。 【packages/coding-agent/src/core/prompt-templates.ts:57-101】

替换只扫描模板字符串一次;argument 或 default value 中出现 $1 不会递归展开。 【packages/coding-agent/src/core/prompt-templates.ts:67-70】

Markdown loader 从 frontmatter 读 description 和 argument-hint;没有 description 时取 body 第一条非空行并截到 60 字符。 【packages/coding-agent/src/core/prompt-templates.ts:104-132】

目录扫描不递归,只读取直接子项中的 .md;symlink 指向文件时允许,broken symlink 跳过。 【packages/coding-agent/src/core/prompt-templates.ts:135-175】

默认来源是 global agentDir/prompts/ 与 project .pi/prompts/,之后再加载显式 file/dir paths。 【packages/coding-agent/src/core/prompt-templates.ts:188-203】 【packages/coding-agent/src/core/prompt-templates.ts:235-262】

expandPromptTemplate() 只匹配以 / 开头、名字后可带任意剩余参数的整条输入;找不到模板时返回原文本。 【packages/coding-agent/src/core/prompt-templates.ts:265-285】

AgentSession.prompt() 中,input extension event 先运行,skill command 再展开,最后才展开 prompt template。 【packages/coding-agent/src/core/agent-session.ts:1131-1156】

5. compaction 触发条件:manual、threshold、overflow 三条入口

手动入口简化为:

async compact(customInstructions?: string): Promise<CompactionResult>

手动 compact 先断开 Agent event subscription,再 abort 当前 run,建立独立 AbortController,并发 compaction_start(reason="manual")。 【packages/coding-agent/src/core/agent-session.ts:1778-1788】

它要求当前有 model,并从活动 branch 读取 entries 与 compaction settings。 【packages/coding-agent/src/core/agent-session.ts:1789-1799】

prepareCompaction() 返回空时,会区分“刚压缩过”和“会话太小”。 【packages/coding-agent/src/core/agent-session.ts:1799-1807】

自动检查在两个时机发生:一次 agent run 的 post-run 阶段,以及提交新 prompt 前对最后 assistant 的预检查。 【packages/coding-agent/src/core/agent-session.ts:1075-1103】 【packages/coding-agent/src/core/agent-session.ts:1197-1202】

自动检查先尊重 settings.enabled;常规 post-run 会跳过用户主动 abort 的 assistant。 【packages/coding-agent/src/core/agent-session.ts:1953-1959】

它还跳过“来自旧 model 的 overflow”和“时间戳位于最新 compaction 之前的旧 assistant”,防止模型切换或 stale usage 误触发。 【packages/coding-agent/src/core/agent-session.ts:1960-1977】

overflow 分支用 isContextOverflow(message, contextWindow),既能处理明确错误,也能处理 provider 报告 usage 已超过配置窗口。 【packages/coding-agent/src/core/agent-session.ts:1979-1988】

如果 assistant 已成功 stop,可以压缩但不会 retry,因为不能从已完成 assistant message 继续。 【packages/coding-agent/src/core/agent-session.ts:1979-1988】

真正的 overflow error 会从 Agent state 去掉最后一条错误 assistant,保留它在 session history 中,然后 compact-and-retry。 【packages/coding-agent/src/core/agent-session.ts:1990-2010】

同一个用户输入最多做一次 overflow recovery;再次 overflow 会发明确失败事件。 【packages/coding-agent/src/core/agent-session.ts:1990-2003】

threshold 分支优先使用 assistant usage;error 或 all-zero usage 时,退回“最后一次有效 usage + 后续消息估算”。 【packages/coding-agent/src/core/agent-session.ts:2013-2037】

最终条件是:

contextTokens > contextWindow - reserveTokens

来源:packages/coding-agent/src/core/compaction/compaction.ts:232-238

默认 settings 是 enabled、reserve 16384、keep recent 20000。 【packages/coding-agent/src/core/compaction/compaction.ts:126-136】

6. token 估算:usage 是锚点,尾部才用 chars/4

calculateContextTokens() 优先使用 provider 的 usage.totalTokens,否则累加 input/output/cacheRead/cacheWrite。 【packages/coding-agent/src/core/compaction/compaction.ts:142-148】

aborted、error 和全零 usage 不作为有效锚点。 【packages/coding-agent/src/core/compaction/compaction.ts:150-167】

estimateContextTokens() 找到最后一条有效 assistant usage 后,只对它之后的 messages 做估算。 【packages/coding-agent/src/core/compaction/compaction.ts:190-229】

如果完全没有有效 usage,才对全部 messages 使用 estimateTokens()。 【packages/coding-agent/src/core/compaction/compaction.ts:202-215】

文本估算是字符数除以 4;每张 image 预估成 4800 字符。 【packages/coding-agent/src/core/compaction/compaction.ts:244-266】

assistant 会计算 text、thinking、tool name 和 JSON arguments;bashExecution 计算 command+output;摘要按 summary 长度计算。 【packages/coding-agent/src/core/compaction/compaction.ts:266-305】

7. cut point:保留近期 token,但不能把 toolResult 从 toolCall 切开

合法切点可以是 user、assistant、bashExecution、custom、branchSummary、compactionSummary,但不能是 toolResult。 【packages/coding-agent/src/core/compaction/compaction.ts:308-321】

turn start 则只包括 user-like 消息,不包括 assistant 和 toolResult。 【packages/coding-agent/src/core/compaction/compaction.ts:323-343】

findCutPoint() 从最新 entry 向前累加估算 token,达到 keepRecentTokens 后选择最近的合法切点。 【packages/coding-agent/src/core/compaction/compaction.ts:387-439】

切点之前相邻、但不参与 context 的 metadata entries 会一起保留,直到遇到 compaction boundary 或可见 entry。 【packages/coding-agent/src/core/compaction/compaction.ts:441-449】

如果切在 assistant 上,说明一个 turn 被拆开;实现会回找该 turn 的 user-like 起点。 【packages/coding-agent/src/core/compaction/compaction.ts:451-460】

这种 split-turn 设计允许保留巨大单轮中的近期工具工作,而不是被迫保留整轮。 【packages/coding-agent/src/core/compaction/compaction.ts:378-400】

8. prepareCompaction():精确决定总结什么、保留什么

如果活动 branch 最后一项已经是 compaction,准备直接返回 undefined。 【packages/coding-agent/src/core/compaction/compaction.ts:710-716】

它先找上一条 compaction;存在时取出 previous summary,并把 boundary start 放到上一轮 firstKeptEntryId。 【packages/coding-agent/src/core/compaction/compaction.ts:718-733】

tokensBefore 来自当前 branch 的 buildSessionContext(...).messages,已经尊重上一次 compaction。 【packages/coding-agent/src/core/compaction/compaction.ts:734-738】

普通切点下,messagesToSummarize 是 boundary start 到 first kept entry 之前的 context-visible messages。 【packages/coding-agent/src/core/compaction/compaction.ts:747-754】

split turn 下,历史 summary 截止到 turn start;turn start 到 first kept entry 另存为 turnPrefixMessages。 【packages/coding-agent/src/core/compaction/compaction.ts:747-763】

没有任何可总结消息时返回 undefined。 【packages/coding-agent/src/core/compaction/compaction.ts:765-767】

准备阶段还从 tool calls 和上一条 pi-generated compaction details 中累计 file operations。 【packages/coding-agent/src/core/compaction/compaction.ts:40-69】 【packages/coding-agent/src/core/compaction/compaction.ts:769-777】

返回值把 firstKeptEntryId、两组 messages、split 标记、tokensBefore、previousSummary、fileOps 和 settings 一次交给执行阶段。 【packages/coding-agent/src/core/compaction/compaction.ts:779-788】

9. 摘要请求:先序列化,再用独立 request 调模型

普通 summary prompt 要求固定输出 Goal、Constraints、Progress、Key Decisions、Next Steps、Critical Context。 【packages/coding-agent/src/core/compaction/compaction.ts:467-498】

存在 previous summary 时改用 update prompt,要求保留旧信息、加入新进展并更新状态。 【packages/coding-agent/src/core/compaction/compaction.ts:500-537】

custom instructions 被追加成 Additional focus,不是替换默认结构。 【packages/coding-agent/src/core/compaction/compaction.ts:642-646】

summary 输出上限是 min(0.8 * reserveTokens, model.maxTokens)。 【packages/coding-agent/src/core/compaction/compaction.ts:621-640】

输入先 convertToLlm(),再由 serializeConversation() 转成 [User][Assistant][Assistant thinking][Assistant tool calls][Tool result] 文本。 【packages/coding-agent/src/core/compaction/compaction.ts:648-658】 【packages/coding-agent/src/core/compaction/utils.ts:101-150】

每条 tool result 最多保留 2000 字符,超出部分用 marker 表示。 【packages/coding-agent/src/core/compaction/utils.ts:88-99】 【packages/coding-agent/src/core/compaction/utils.ts:141-145】

原对话被包在 <conversation>,旧摘要放进 <previous-summary>,整个请求只有一条 user message。 【packages/coding-agent/src/core/compaction/compaction.ts:653-666】

summarizer 的 system prompt 明确要求不要续写对话,只输出结构化摘要。 【packages/coding-agent/src/core/compaction/utils.ts:152-158】

completeSummarization() 是 compaction 与 branch summary 共用的调用点。 【packages/coding-agent/src/core/compaction/compaction.ts:555-580】

摘要请求使用新的 sessionId,并强制 cacheRetention: "none",因为这是不可复用的独立请求。 【packages/coding-agent/src/core/compaction/compaction.ts:570-580】

它优先使用当前 session 的 streamFn,否则回退 completeSimple(),外面统一套 retryAssistantCall()。 【packages/coding-agent/src/core/compaction/compaction.ts:576-580】

10. split-turn summary 与文件清单

不是 split turn 时,只生成一份 history summary。 【packages/coding-agent/src/core/compaction/compaction.ts:883-902】

split turn 时,先更新旧历史 summary,再用较小预算单独总结 turn prefix,最后用分隔线合并。 【packages/coding-agent/src/core/compaction/compaction.ts:841-882】

turn prefix 输出上限是 min(0.5 * reserveTokens, model.maxTokens)。 【packages/coding-agent/src/core/compaction/compaction.ts:924-940】

两次摘要调用的 usage 会逐字段相加,作为本次 compaction usage。 【packages/coding-agent/src/core/compaction/compaction.ts:99-120】 【packages/coding-agent/src/core/compaction/compaction.ts:880-882】

file operation 只识别 assistant toolCall 中 readwriteeditpath 参数。 【packages/coding-agent/src/core/compaction/utils.ts:26-55】

最终 readFiles 会排除已经 modified 的文件,modified 是 edited 与 written 的并集。 【packages/coding-agent/src/core/compaction/utils.ts:58-67】

这些路径以 <read-files><modified-files> 追加到 summary,也写入 CompactionDetails。 【packages/coding-agent/src/core/compaction/utils.ts:69-82】 【packages/coding-agent/src/core/compaction/compaction.ts:904-918】

11. 摘要怎样保存并重新进入 context

手动和自动路径都先 appendCompaction(summary, firstKeptEntryId, tokensBefore, details, fromHook, usage)。 【packages/coding-agent/src/core/agent-session.ts:1872-1876】 【packages/coding-agent/src/core/agent-session.ts:2153-2157】

SessionManager.appendCompaction() 把它作为普通 tree child 追加,不删除旧 entries。 【packages/coding-agent/src/core/session-manager.ts:1096-1119】

随后立刻 buildSessionContext(),并用返回 messages 整体替换 agent.state.messages。 【packages/coding-agent/src/core/agent-session.ts:1872-1876】 【packages/coding-agent/src/core/agent-session.ts:2153-2157】

buildContextEntries() 找最新 compaction,只输出该 compaction、它指定的 kept 区间以及之后新增 entries。 【packages/coding-agent/src/core/session-manager.ts:410-454】

compaction entry 经 sessionEntryToContextMessages() 变成 CompactionSummaryMessage。 【packages/coding-agent/src/core/session-manager.ts:379-407】

convertToLlm() 再把它变成 user message,文本格式是固定前缀、<summary>、摘要、</summary>。 【packages/coding-agent/src/core/messages.ts:11-17】 【packages/coding-agent/src/core/messages.ts:176-183】

因此模型看到的是“摘要 + 近期原消息”,而 session JSONL 仍保存完整旧树。 【packages/coding-agent/src/core/session-manager.ts:410-470】 【packages/coding-agent/src/core/session-manager.ts:1296-1303】

overflow 且 willRetry=true 时,compaction 完成后返回 true,_runAgentPrompt() 会调用 agent.continue()。 【packages/coding-agent/src/core/agent-session.ts:2182-2195】 【packages/coding-agent/src/core/agent-session.ts:1061-1067】

threshold compaction 不自动续写已完成回答,但如果此时有 queued messages,会继续一次以投递队列。 【packages/coding-agent/src/core/agent-session.ts:2182-2195】

12. branch summarization:同一 summarizer,不同保存边界

tree navigation 会从旧 leaf 回溯到与 target 的最近公共祖先,只总结离开的那段 branch。 【packages/coding-agent/src/core/compaction/branch-summarization.ts:96-146】

branch preparation 从新到旧装入 token budget,优先保留近期内容;已有 branch/compaction summary 可能在接近预算时仍被保留。 【packages/coding-agent/src/core/compaction/branch-summarization.ts:182-246】

toolResult 在 branch summary 中被跳过,因为 assistant 的 tool call 已保留操作意图。 【packages/coding-agent/src/core/compaction/branch-summarization.ts:152-180】

branch summary 同样先 convert、serialize,再走 completeSummarization()。 【packages/coding-agent/src/core/compaction/branch-summarization.ts:321-351】

成功后加上“用户探索了另一条分支”的 preamble 和文件清单。 【packages/coding-agent/src/core/compaction/branch-summarization.ts:253-256】 【packages/coding-agent/src/core/compaction/branch-summarization.ts:361-375】

它最终保存成 branch_summary entry;投影回 context 时使用另一套固定 summary wrapper。 【packages/coding-agent/src/core/session-manager.ts:82-92】 【packages/coding-agent/src/core/messages.ts:19-24】

数据流

下面追踪一次 threshold auto-compaction:

Agent finishes assistant message
  -> AgentSession._handlePostAgentRun()
  -> _checkCompaction(assistantMessage)
       -> calculateContextTokens(usage)
          or estimateContextTokens(agent.state.messages)
       -> shouldCompact(tokens, contextWindow, settings)
  -> _runAutoCompaction("threshold", false)
       -> sessionManager.getBranch()
       -> prepareCompaction(entries, settings)
            -> locate previous compaction
            -> findCutPoint(... keepRecentTokens)
            -> messagesToSummarize + optional turnPrefixMessages
            -> previousSummary + fileOps
       -> compact(preparation, model, ...)
            -> convertToLlm()
            -> serializeConversation()
            -> completeSummarization()
                 -> cacheRetention="none", fresh sessionId, retryAssistantCall()
            -> append read/modified file lists
       -> sessionManager.appendCompaction(...)
       -> sessionManager.buildSessionContext()
            -> CompactionSummaryMessage + kept recent messages
       -> agent.state.messages = compacted context
       -> compaction_end

post-run 触发点和是否继续由 _handlePostAgentRun() 决定。 【packages/coding-agent/src/core/agent-session.ts:1075-1103】

threshold 判断来自最后有效 usage 与 reserveTokens。 【packages/coding-agent/src/core/agent-session.ts:2013-2041】 【packages/coding-agent/src/core/compaction/compaction.ts:232-238】

切点、历史消息和 split-turn prefix 由 prepareCompaction() 一次算完。 【packages/coding-agent/src/core/compaction/compaction.ts:710-788】

摘要调用、重试隔离和无缓存策略集中在 completeSummarization()。 【packages/coding-agent/src/core/compaction/compaction.ts:555-580】

保存后通过 buildSessionContext() 立即重建 Agent transcript。 【packages/coding-agent/src/core/agent-session.ts:2153-2157】

下一轮模型请求中,compaction entry 已被投影成带 <summary> 的 user message。 【packages/coding-agent/src/core/session-manager.ts:401-406】 【packages/coding-agent/src/core/messages.ts:176-183】

自测

  1. custom system prompt 替换了哪些默认内容,又有哪些内容仍会继续追加? 【packages/coding-agent/src/core/system-prompt.ts:46-71】

  2. 为什么一个 active tool 可能已在 agent.state.tools 中,却不出现在 system prompt 的 “Available tools” 列表? 【packages/coding-agent/src/core/system-prompt.ts:79-84】

  3. threshold compaction 与 overflow compaction 在 retry 行为上有什么不同? 【packages/coding-agent/src/core/agent-session.ts:1979-2010】 【packages/coding-agent/src/core/agent-session.ts:2182-2195】

  4. findCutPoint() 为什么允许切在 assistant message,却绝不切在 toolResult? 【packages/coding-agent/src/core/compaction/compaction.ts:308-321】 【packages/coding-agent/src/core/compaction/compaction.ts:345-360】

  5. compaction 后,摘要经过哪两次类型转换才成为下一次模型请求中的 user message? 【packages/coding-agent/src/core/session-manager.ts:379-407】 【packages/coding-agent/src/core/messages.ts:176-183】