OpenClaw 上下文窗口管理

OpenClaw 上下文窗口管理

OpenClaw 实现了多层上下文窗口管理系统,通过多种互补策略处理超出模型上下文限制的对话。

整体协作流程图

flowchart TB subgraph INIT["🚀 初始化阶段"] A0[runEmbeddedPiAgent 入口<br/>📄 run.ts:192-334] --> A1[执行钩子<br/>before_model_resolve<br/>before_agent_start] A1 --> A2[解析模型<br/>resolveModel<br/>📄 run.ts:294-306] A2 --> A3[解析上下文窗口<br/>resolveContextWindowInfo<br/>📄 context-window-guard.ts:21-50] A3 --> A4{窗口 < 16K?} A4 -->|是| A5[❌ 阻塞运行<br/>FailoverError] A4 -->|否| A6{窗口 < 32K?} A6 -->|是| A7[⚠️ 发出警告] A6 -->|否| A8[✅ 继续] A7 --> A8 A8 --> A9[解析认证配置<br/>resolveAuthProfileOrder] A9 --> A10[获取 API Key<br/>getApiKeyForModel] end subgraph RUNLOOP["🔄 运行循环"] B0[runLoopIterations++<br/>最大 32-160 次] --> B1[runEmbeddedAttempt<br/>📄 run/attempt.ts] B1 --> B2[历史轮次限制<br/>limitHistoryTurns<br/>📄 history.ts:15-36] B2 --> B3[安装工具结果保护<br/>installToolResultContextGuard<br/>📄 tool-result-context-guard.ts:297-336] B3 --> B4{上下文修剪<br/>已启用?} B4 -->|是| B5[上下文修剪<br/>pruneContextMessages<br/>📄 pruner.ts:220-341] B4 -->|否| B6[跳过修剪] B5 --> B5a{使用率 >= 30%?} B5a -->|是| B5b[软裁剪工具结果<br/>保留头尾各 1500 字符] B5a -->|否| B5c[跳过软裁剪] B5b --> B5d{使用率 >= 50%?} B5d -->|是| B5e[硬清除工具结果<br/>替换为占位符] B5d -->|否| B5f[跳过硬清除] B5e --> B6 B5f --> B6 B5c --> B6 B6 --> B7[Agent.transformContext<br/>工具结果截断保护<br/>📄 tool-result-context-guard.ts:269-295] B7 --> B8[发送到模型] end subgraph OVERFLOW["🔥 溢出处理"] C0{检测溢出错误<br/>isLikelyContextOverflowError<br/>📄 run.ts:671-687} --> C1{已有尝试压缩?} C1 -->|是| C2[overflowCompactionAttempts++] C1 -->|否| C3[继续] C2 --> C3 C3 --> C4{尝试次数 < 3?} C4 -->|是| C5{内存刷新<br/>已启用?} C4 -->|否| C6[跳过压缩<br/>尝试工具结果截断] C5 -->|是| C7{达到阈值?<br/>shouldRunMemoryFlush<br/>📄 memory-flush.ts:113-144} C5 -->|否| C8[跳过内存刷新] C7 -->|是| C9[执行内存刷新<br/>保存到 memory/*.md] C7 -->|否| C8 C8 --> C10 C9 --> C10[执行压缩<br/>compactEmbeddedPiSessionDirect<br/>📄 compact.ts:248-744] C10 --> C11[触发 before_compaction 钩子] C11 --> C12[Safeguard 扩展处理] end subgraph SAFEGUARD["🛡️ Safeguard 处理"] D1[验证模型和 API Key<br/>📄 compaction-safeguard.ts:206-226] --> D2{历史超出预算?<br/>newContentTokens > maxHistoryShare} D2 -->|是| D3[修剪历史<br/>pruneHistoryForContextShare<br/>📄 compaction.ts:339-401] D2 -->|否| D4[跳过历史修剪] D3 --> D5[摘要被丢弃消息<br/>summarizeInStages] D4 --> D6 D5 --> D6[计算自适应块比例<br/>computeAdaptiveChunkRatio<br/>📄 compaction.ts:129-148] D6 --> D7[渐进式摘要<br/>summarizeInStages<br/>📄 compaction.ts:276-337] D7 --> D8[收集工具失败信息<br/>collectToolFailures<br/>📄 compaction-safeguard.ts:74-117] D8 --> D9[收集文件操作信息<br/>computeFileLists<br/>📄 compaction-safeguard.ts:133-155] D9 --> D10[读取 AGENTS.md 关键内容<br/>readWorkspaceContextForSummary<br/>📄 compaction-safeguard.ts:162-189] D10 --> D11[拼接最终摘要<br/>+ 工具失败 + 文件操作 + AGENTS.md] end subgraph RESULT["📊 结果处理"] E1[返回压缩结果] --> E2{成功?} E2 -->|是| E3[触发 after_compaction 钩子] E3 --> E4[更新会话消息] E4 --> E5[重试原始请求] E2 -->|否| E6{有超大工具结果?} E6 -->|是| E7[截断超大工具结果<br/>truncateOversizedToolResultsInSession<br/>📄 tool-result-truncation.ts:155-280] E6 -->|否| E8[❌ 报告溢出错误] E7 --> E9{仍然溢出?} E9 -->|是| E8 E9 -->|否| E5 E5 --> E10{成功?} E10 -->|是| E11[✅ 完成] E10 -->|溢出| E12{运行循环次数<br/>超过限制?} E12 -->|是| E13[❌ 报告重试限制错误] E12 -->|否| B0 end INIT --> RUNLOOP RUNLOOP -->|溢出| OVERFLOW OVERFLOW --> SAFEGUARD SAFEGUARD --> RESULT style INIT fill:#e1f5fe style RUNLOOP fill:#e8f5e9 style OVERFLOW fill:#fff3e0 style SAFEGUARD fill:#fce4ec style RESULT fill:#f3e5f5

详细时序图

sequenceDiagram participant User as 用户消息 participant Runner as runEmbeddedPiAgent participant Hook as 钩子系统 participant Model as 模型解析 participant Auth as 认证配置 participant Attempt as runEmbeddedAttempt participant History as 历史限制 participant Pruning as 上下文修剪 participant Guard as 工具结果保护 participant API as 模型 API participant Flush as 内存刷新 participant Compact as 压缩引擎 participant Safeguard as Safeguard 扩展 User->>Runner: 发送消息 Note over Runner: 1. 初始化阶段 Runner->>Hook: before_model_resolve Hook-->>Runner: providerOverride/modelOverride (可选) Runner->>Model: resolveModel() Model-->>Runner: model 对象 Runner->>Runner: resolveContextWindowInfo()<br/>📄 context-window-guard.ts:21-50 alt 窗口 < 16K Runner-->>User: ❌ FailoverError (阻塞) end alt 窗口 < 32K Runner->>Runner: ⚠️ 发出警告 end Runner->>Auth: resolveAuthProfileOrder() Auth-->>Runner: 配置文件列表 Runner->>Auth: getApiKeyForModel() Auth-->>Runner: API Key loop 运行循环 (最大 32-160 次) Note over Runner,Attempt: 2. 尝试阶段 Runner->>Attempt: runEmbeddedAttempt() Note over Attempt: 3. 预处理阶段 Attempt->>History: limitHistoryTurns()<br/>📄 history.ts:15-36 History-->>Attempt: 限制后的消息 Attempt->>Guard: installToolResultContextGuard()<br/>📄 tool-result-context-guard.ts:297-336 opt 上下文修剪已启用 Attempt->>Pruning: pruneContextMessages()<br/>📄 pruner.ts:220-341 Pruning->>Pruning: 计算 contextUsageRatio alt ratio >= 30% Pruning->>Pruning: 软裁剪工具结果<br/>保留头尾各 1500 字符 end alt ratio >= 50% Pruning->>Pruning: 硬清除工具结果<br/>替换为占位符 end Pruning-->>Attempt: 修剪后的消息 end Note over Attempt: 4. 发送到模型 Attempt->>Guard: transformContext() Guard->>Guard: enforceToolResultContextBudgetInPlace()<br/>📄 tool-result-context-guard.ts:269-295 Guard->>API: 发送请求 alt 溢出错误 API-->>Attempt: ContextOverflowError Attempt-->>Runner: 溢出检测 Note over Runner: 5. 溢出处理 Runner->>Runner: isLikelyContextOverflowError()<br/>📄 run.ts:671-687 opt 尝试次数 < 3 opt 内存刷新已启用且达到阈值 Runner->>Flush: shouldRunMemoryFlush()<br/>📄 memory-flush.ts:113-144 Flush-->>Runner: true Runner->>Flush: 执行内存刷新 Flush->>Flush: 写入 memory/YYYY-MM-DD.md end Runner->>Compact: compactEmbeddedPiSessionDirect()<br/>📄 compact.ts:248-744 Compact->>Safeguard: session_before_compact 事件 Note over Safeguard: 6. Safeguard 处理 Safeguard->>Safeguard: 收集工具失败信息<br/>📄 compaction-safeguard.ts:74-117 Safeguard->>Safeguard: 收集文件操作信息<br/>📄 compaction-safeguard.ts:133-155 alt 历史超出预算 Safeguard->>Safeguard: pruneHistoryForContextShare()<br/>📄 compaction.ts:339-401 Safeguard->>Safeguard: summarizeInStages(被丢弃消息) end Safeguard->>Safeguard: computeAdaptiveChunkRatio()<br/>📄 compaction.ts:129-148 Safeguard->>Safeguard: summarizeInStages(保留消息)<br/>📄 compaction.ts:276-337 Safeguard->>Safeguard: readWorkspaceContextForSummary()<br/>📄 compaction-safeguard.ts:162-189 Safeguard-->>Compact: 返回摘要 Compact->>Compact: 替换旧消息为摘要 Compact-->>Runner: 压缩结果 Runner->>API: 重试请求 end alt 仍然溢出 API-->>Runner: ContextOverflowError Runner->>Guard: 截断超大工具结果<br/>📄 tool-result-truncation.ts:155-280 Runner->>API: 再次重试 end else 成功 API-->>Attempt: 模型响应 end end Runner-->>User: 返回结果

各层协作关系图

graph TB subgraph PROACTIVE["🟢 主动层 - 运行前预防"] P1[历史轮次限制<br/>limitHistoryTurns] P2[上下文修剪<br/>pruneContextMessages] P3[内存刷新<br/>memoryFlush] end subgraph REACTIVE["🔴 反应层 - 溢出响应"] R1[溢出检测<br/>isLikelyContextOverflowError] R2[压缩摘要<br/>compactEmbeddedPiSessionDirect] R3[工具结果截断<br/>enforceToolResultContextBudgetInPlace] end subgraph CORE["🔵 核心层 - 基础设施"] C1[上下文窗口解析<br/>resolveContextWindowInfo] C2[Token 估算<br/>estimateMessagesTokens] C3[消息分块<br/>chunkMessagesByMaxTokens] C4[渐进式摘要<br/>summarizeInStages] end subgraph SAFEGUARD["🛡️ 保护层 - 智能处理"] S1[Safeguard 扩展<br/>compactionSafeguardExtension] S2[历史预算修剪<br/>pruneHistoryForContextShare] S3[工具失败收集<br/>collectToolFailures] end C1 --> P1 C1 --> P2 C2 --> P3 C2 --> R2 C3 --> C4 C4 --> S1 P1 --> R1 P2 --> R1 P3 --> R2 R1 --> R2 R2 --> S1 S1 --> S2 S2 --> C4 S1 --> S3 R2 --> R3 style PROACTIVE fill:#e8f5e9 style REACTIVE fill:#ffebee style CORE fill:#e3f2fd style SAFEGUARD fill:#fce4ec

渐进式摘要

总览图

flowchart TB subgraph Stage1["阶段1: 判断处理方式"] A[输入消息] --> B{需要分块?} B -->|否| C[直接摘要] B -->|是| D[按token分割] end subgraph Stage2["阶段2: 分块处理 (如需要)"] D --> E[对每块独立摘要] E --> F[收集部分摘要] F --> G[转为消息] G --> H[合并摘要] end subgraph Stage3["阶段3: 摘要生成 (summarizeWithFallback)"] C --> I{尝试完整摘要} H --> I I -->|成功| J[返回摘要] I -->|失败| K[过滤超大消息] K --> L[只对小消息摘要] L --> M{成功?} M -->|是| N[返回部分摘要 + 备注] M -->|否| O[返回失败提示] end subgraph Stage4["阶段4: 分块摘要 (summarizeChunks)"] P[chunkMessagesByMaxTokens] --> Q[遍历chunks] Q --> R[generateSummary + 重试] R --> S[累积摘要] end I --> P L --> P J --> Z([输出最终摘要]) N --> Z O --> Z style Stage1 fill:#e3f2fd style Stage2 fill:#fff3e0 style Stage3 fill:#e8f5e9 style Stage4 fill:#f3e5f5

完整图

flowchart TB subgraph Input["📥 输入参数"] I1["messages: AgentMessage[]"] I2["model, apiKey, signal"] I3["contextWindow"] I4["maxChunkTokens"] I5["reserveTokens"] I6["parts? 默认=2"] I7["minMessagesForSplit? 默认=4"] I8["previousSummary?"] I9["customInstructions?"] end Start([开始 summarizeInStages]) --> CheckEmpty{"messages.length === 0?"} CheckEmpty -->|是| ReturnDefault["返回 previousSummary<br/>或 'No prior history.'"] CheckEmpty -->|否| CalcParams["计算参数:<br/>• minMessagesForSplit = max(2, minMessagesForSplit ?? 4)<br/>• parts = normalizeParts(parts ?? 2)<br/>• totalTokens = estimateMessagesTokens(messages)"] CalcParams --> CheckNeedSplit{"需要分块处理?<br/><br/>parts <= 1<br/>OR messages.length < minMessagesForSplit<br/>OR totalTokens <= maxChunkTokens"} %% 直接处理路径 CheckNeedSplit -->|否: 直接处理| DirectPath["调用 summarizeWithFallback(params)"] %% 分块处理路径 CheckNeedSplit -->|是: 分块处理| SplitMsgs["splitMessagesByTokenShare(messages, parts)<br/>按 token 比例分成 N 块"] SplitMsgs --> FilterEmpty1["过滤空 chunk"] FilterEmpty1 --> CheckSplitsCount{"splits.length <= 1?"} CheckSplitsCount -->|是| DirectPath CheckSplitsCount -->|否| LoopChunks["遍历每个 chunk"] %% 循环处理每个 chunk LoopChunks --> ChunkSummarize["summarizeWithFallback({<br/> messages: chunk,<br/> previousSummary: undefined<br/>})"] ChunkSummarize --> PushPartial["partialSummaries.push(result)"] PushPartial --> MoreChunks{"还有更多 chunk?"} MoreChunks -->|是| LoopChunks MoreChunks -->|否| CheckPartialCount{"partialSummaries.length === 1?"} CheckPartialCount -->|是| ReturnSingle["返回 partialSummaries[0]"] CheckPartialCount -->|否| ConvertToMsgs["将摘要转为消息:<br/>summaryMessages = partialSummaries.map(s => ({<br/> role: 'user',<br/> content: s,<br/> timestamp: Date.now()<br/>}))"] ConvertToMsgs --> BuildMergeInstr["构建合并指令:<br/>'Merge these partial summaries into<br/>a single cohesive summary.<br/>Preserve decisions, TODOs,<br/>open questions, and any constraints.'"] BuildMergeInstr --> MergeSummarize["summarizeWithFallback({<br/> messages: summaryMessages,<br/> customInstructions: mergeInstructions<br/>})"] %% summarizeWithFallback 详细流程 subgraph SummarizeWithFallback["summarizeWithFallback 详细流程"] direction TB SWF_Start([开始]) --> SWF_StripDetails["stripToolResultDetails(messages)<br/>移除工具结果中的敏感详情"] SWF_StripDetails --> SWF_TryFull["第一层: 尝试完整摘要<br/>summarizeChunks(全部消息)"] SWF_TryFull --> SWF_CheckFull{成功?} SWF_CheckFull -->|是| SWF_ReturnFull["返回完整摘要"] SWF_CheckFull -->|否| SWF_LogWarn["log.warn('Full summarization failed')"] SWF_LogWarn --> SWF_Separate["分离消息:<br/>遍历每条消息"] SWF_Separate --> SWF_CheckOversized{"isOversizedForSummary?<br/>(tokens > contextWindow * 0.5)"} SWF_CheckOversized -->|是: 超大消息| SWF_AddNote["oversizedNotes.push(<br/> '[Large role (~XK tokens)<br/> omitted from summary]'<br/>)"] SWF_CheckOversized -->|否: 正常消息| SWF_AddSmall["smallMessages.push(msg)"] SWF_AddNote --> SWF_NextMsg{"还有更多消息?"} SWF_AddSmall --> SWF_NextMsg SWF_NextMsg -->|是| SWF_Separate SWF_NextMsg -->|否| SWF_CheckSmall{"smallMessages.length > 0?"} SWF_CheckSmall -->|是| SWF_TryPartial["第二层: 尝试部分摘要<br/>summarizeChunks(smallMessages)"] SWF_TryPartial --> SWF_CheckPartial{成功?} SWF_CheckPartial -->|是| SWF_ReturnPartial["返回: 部分摘要 + oversizedNotes"] SWF_CheckPartial -->|否| SWF_FinalFallback SWF_CheckSmall -->|否| SWF_FinalFallback["第三层: 最终回退<br/>'Context contained X messages<br/>(Y oversized).<br/>Summary unavailable due to size limits.'"] SWF_FinalFallback --> SWF_ReturnFinal["返回失败提示"] end DirectPath --> SummarizeWithFallback MergeSummarize --> SummarizeWithFallback %% summarizeChunks 详细流程 subgraph SummarizeChunks["summarizeChunks 详细流程"] direction TB SC_Start([开始]) --> SC_Chunk["chunkMessagesByMaxTokens(messages, maxChunkTokens)<br/>按最大 token 分块"] SC_Chunk --> SC_LoopChunks["遍历每个 chunk"] SC_LoopChunks --> SC_Retry["retryAsync(<br/> generateSummary,<br/> { attempts: 3,<br/> minDelayMs: 500,<br/> maxDelayMs: 5000 }<br/>)"] SC_Retry --> SC_Accumulate["累积摘要:<br/>summary = 新摘要<br/>(传入之前的 summary)"] SC_Accumulate --> SC_MoreChunks{"还有更多 chunk?"} SC_MoreChunks -->|是| SC_LoopChunks SC_MoreChunks -->|否| SC_Return["返回最终累积摘要"] end SWF_TryFull --> SummarizeChunks SWF_TryPartial --> SummarizeChunks %% chunkMessagesByMaxTokens 详细流程 subgraph ChunkByMax["chunkMessagesByMaxTokens 详细流程"] direction TB CM_Start([开始]) --> CM_CalcMax["effectiveMax = maxTokens / SAFETY_MARGIN<br/>(SAFETY_MARGIN = 1.2)"] CM_CalcMax --> CM_LoopMsgs["遍历每条消息"] CM_LoopMsgs --> CM_Estimate["estimateCompactionMessageTokens(msg)"] CM_Estimate --> CM_CheckAdd{"currentTokens + msgTokens > effectiveMax<br/>且 currentChunk 不为空?"} CM_CheckAdd -->|是| CM_PushChunk["chunks.push(currentChunk)<br/>重置 currentChunk"] CM_CheckAdd -->|否| CM_AddMsg CM_PushChunk --> CM_AddMsg["currentChunk.push(msg)<br/>currentTokens += msgTokens"] CM_AddMsg --> CM_CheckOversized{"msgTokens > effectiveMax?<br/>(单条消息超大)"} CM_CheckOversized -->|是| CM_PushOversized["chunks.push(currentChunk)<br/>超大消息单独成块<br/>重置 currentChunk"] CM_CheckOversized -->|否| CM_NextMsg CM_PushOversized --> CM_NextMsg{"还有更多消息?"} CM_NextMsg -->|是| CM_LoopMsgs CM_NextMsg -->|否| CM_PushFinal["if (currentChunk.length > 0)<br/>chunks.push(currentChunk)"] CM_PushFinal --> CM_Return["返回 chunks"] end SC_Chunk --> ChunkByMax %% 输出 SWF_ReturnFull --> End([结束]) SWF_ReturnPartial --> End SWF_ReturnFinal --> End ReturnDefault --> End ReturnSingle --> End SC_Return --> End %% 样式 style Start fill:#e3f2fd style End fill:#ffebee style CheckNeedSplit fill:#fff3e0 style CheckEmpty fill:#fff3e0 style CheckSplitsCount fill:#fff3e0 style CheckPartialCount fill:#fff3e0 style MoreChunks fill:#fff3e0 style SummarizeWithFallback fill:#e8f5e9 style SummarizeChunks fill:#f3e5f5 style ChunkByMax fill:#fce4ec

历史消息和最新消息处理机制

flowchart TB subgraph Step1["步骤1: 计算预算"] A["maxContextTokens = 模型上下文窗口<br/>(如 128K)"] B["budgetTokens = maxContextTokens × maxHistoryShare<br/>= 128K × 0.5 = 64K"] end subgraph Step2["步骤2: 循环丢弃"] C{"当前消息 tokens > budgetTokens?"} C -->|是| D["splitMessagesByTokenShare(messages, 2)<br/>分成 2 部分"] D --> E["[最早的一半, 最新的一半]"] E --> F["摘要最早的一半"] F --> G["保留最新的一半"] G --> C C -->|否| H["保留剩余消息"] end A --> B --> C

决策树:上下文管理策略选择

flowchart TD Start[消息处理开始] --> Check1{上下文窗口<br/>解析完成?} Check1 -->|否| Resolve[resolveContextWindowInfo<br/>📄 context-window-guard.ts:21-50] Resolve --> Guard1{窗口 < 16K?} Guard1 -->|是| Block[❌ 阻塞运行] Guard1 -->|否| Guard2{窗口 < 32K?} Guard2 -->|是| Warn[⚠️ 警告但继续] Guard2 -->|否| Continue[✅ 继续] Warn --> Continue Check1 -->|是| History[limitHistoryTurns<br/>📄 history.ts:15-36] Continue --> History History --> PruneCheck{上下文修剪<br/>已启用?} PruneCheck -->|否| Transform[transformContext<br/>📄 tool-result-context-guard.ts:269-295] PruneCheck -->|是| Prune[pruneContextMessages<br/>📄 pruner.ts:220-341] Prune --> Ratio1{使用率 >= 30%?} Ratio1 -->|是| SoftTrim[软裁剪<br/>保留头尾各 1500 字符] Ratio1 -->|否| Ratio2 SoftTrim --> Ratio2{使用率 >= 50%?} Ratio2 -->|是| HardClear[硬清除<br/>替换为占位符] Ratio2 -->|否| Transform HardClear --> Transform Transform --> Send[发送到模型] Send --> Result{结果?} Result -->|成功| Done[✅ 完成] Result -->|溢出| OverflowCheck{尝试次数 < 3?} OverflowCheck -->|否| TruncateCheck{有超大工具结果?} OverflowCheck -->|是| FlushCheck{内存刷新<br/>已启用?} TruncateCheck -->|是| TruncateLarge[截断超大工具结果<br/>📄 tool-result-truncation.ts:155-280] TruncateCheck -->|否| Error[❌ 报告溢出错误] TruncateLarge --> FinalCheck1 FinalCheck1{仍然溢出?} FinalCheck1 -->|是| Error FinalCheck1 -->|否| Done FlushCheck -->|否| Compact FlushCheck -->|是| FlushThreshold{达到阈值?<br/>📄 memory-flush.ts:113-144} FlushThreshold -->|否| Compact FlushThreshold -->|是| FlushExec[执行内存刷新<br/>写入 memory/*.md] FlushExec --> Compact Compact[compactEmbeddedPiSessionDirect<br/>📄 compact.ts:248-744] --> BeforeHook[before_compaction 钩子] BeforeHook --> Safeguard[Safeguard 处理<br/>📄 compaction-safeguard.ts:191-371] Safeguard --> HistoryCheck{历史超出预算?<br/>maxHistoryShare} HistoryCheck -->|是| PruneHistory[pruneHistoryForContextShare<br/>📄 compaction.ts:339-401] PruneHistory --> SummarizeDropped[摘要被丢弃消息] HistoryCheck -->|否| AdaptiveRatio SummarizeDropped --> AdaptiveRatio[computeAdaptiveChunkRatio<br/>📄 compaction.ts:129-148] AdaptiveRatio --> Summarize[summarizeInStages<br/>📄 compaction.ts:276-337] Summarize --> AppendInfo[附加信息<br/>工具失败 + 文件操作 + AGENTS.md] AppendInfo --> AfterHook[after_compaction 钩子] AfterHook --> Retry[重试请求] Retry --> RetryResult{结果?} RetryResult -->|成功| Done RetryResult -->|溢出| LoopCheck{运行循环<br/>超过限制?} LoopCheck -->|是| LoopError[❌ 重试限制错误] LoopCheck -->|否| History style Start fill:#e3f2fd style Done fill:#e8f5e9 style Error fill:#ffebee style LoopError fill:#ffebee style Compact fill:#fff3e0 style Safeguard fill:#fce4ec

触发条件汇总

组件 触发条件 文件:行号
上下文窗口警告 tokens < 32,000 context-window-guard.ts:71
上下文窗口阻塞 tokens < 16,000 context-window-guard.ts:72
软裁剪 contextUsageRatio >= 0.3 pruner.ts:259
硬清除 contextUsageRatio >= 0.5 pruner.ts:298
内存刷新 totalTokens >= contextWindow - reserveTokensFloor - softThresholdTokens memory-flush.ts:129
历史修剪 newContentTokens > contextWindow * maxHistoryShare compaction-safeguard.ts:250
工具结果截断 currentChars > contextBudgetChars tool-result-context-guard.ts:286
溢出压缩重试 最多 3 次 run.ts:511
运行循环限制 32-160 次 (基于认证配置数量) run.ts:111-121
超大工具结果截断 textLength > contextWindowTokens * 0.3 * 4 tool-result-truncation.ts:71-76

关键常量

常量 说明 文件:行号
CONTEXT_WINDOW_HARD_MIN_TOKENS 16,000 最小上下文窗口 context-window-guard.ts:3
CONTEXT_WINDOW_WARN_BELOW_TOKENS 32,000 警告阈值 context-window-guard.ts:4
MAX_OVERFLOW_COMPACTION_ATTEMPTS 3 溢出压缩最大尝试次数 run.ts:511
BASE_RUN_RETRY_ITERATIONS 24 基础重试次数 run.ts:111
RUN_RETRY_ITERATIONS_PER_PROFILE 8 每个认证配置增加的重试次数 run.ts:112
MIN_RUN_RETRY_ITERATIONS 32 最小重试次数 run.ts:113
MAX_RUN_RETRY_ITERATIONS 160 最大重试次数 run.ts:114
BASE_CHUNK_RATIO 0.4 基础分块比例 compaction.ts:11
MIN_CHUNK_RATIO 0.15 最小分块比例 compaction.ts:12
SAFETY_MARGIN 1.2 安全边际 (20%) compaction.ts:13
SUMMARIZATION_OVERHEAD_TOKENS 4096 摘要开销 Token compaction.ts:81
MAX_TOOL_RESULT_CONTEXT_SHARE 0.3 单个工具结果最大上下文占比 tool-result-truncation.ts:11
HARD_MAX_TOOL_RESULT_CHARS 400,000 工具结果硬性字符限制 tool-result-truncation.ts:19
CONTEXT_INPUT_HEADROOM_RATIO 0.75 上下文输入保留比例 tool-result-context-guard.ts:5

数据流向图

flowchart LR subgraph Input["📥 输入"] M1[用户消息] M2[工具结果] M3[助手回复] end subgraph Pipeline["⚙️ 处理管道"] F1[历史限制] F2[上下文修剪] F3[工具结果保护] F4[压缩摘要] end subgraph Output["📤 输出"] O1[发送到模型] O2[摘要消息] O3[内存文件] end M1 --> F1 M2 --> F1 M3 --> F1 F1 --> F2 F2 --> F3 F3 --> O1 O1 -->|溢出| F4 F4 --> O2 F4 --> O3 O2 --> F3 O3 --> O1 style Input fill:#e3f2fd style Pipeline fill:#fff3e0 style Output fill:#e8f5e9

核心函数调用链

runEmbeddedPiAgent (run.ts:192)
├── resolveContextWindowInfo (context-window-guard.ts:21)
├── evaluateContextWindowGuard (context-window-guard.ts:57)
├── resolveAuthProfileOrder (model-auth.ts)
└── 运行循环 (run.ts:538)
    └── runEmbeddedAttempt (run/attempt.ts)
        ├── limitHistoryTurns (history.ts:15)
        ├── installToolResultContextGuard (tool-result-context-guard.ts:297)
        ├── pruneContextMessages (pruner.ts:220) [可选]
        └── Agent.transformContext
            └── enforceToolResultContextBudgetInPlace (tool-result-context-guard.ts:269)
    
    溢出时:
    └── compactEmbeddedPiSessionDirect (compact.ts:248)
        ├── shouldRunMemoryFlush (memory-flush.ts:113) [可选]
        └── session.compact
            └── compactionSafeguardExtension (compaction-safeguard.ts:191)
                ├── collectToolFailures (compaction-safeguard.ts:74)
                ├── computeFileLists (compaction-safeguard.ts:133)
                ├── pruneHistoryForContextShare (compaction.ts:339)
                ├── computeAdaptiveChunkRatio (compaction.ts:129)
                ├── summarizeInStages (compaction.ts:276)
                └── readWorkspaceContextForSummary (compaction-safeguard.ts:162)
posted @ 2026-03-17 08:43  枫叶流华  阅读(450)  评论(0)    收藏  举报