import type { Message } from '../types.js'; import type { ToolResultStore, HistoryPersistence } from './types.js'; /** 历史管理配置 */ export interface HistoryManagerConfig { /** 消息历史上限(滑动窗口),默认 50 */ maxMessages: number; /** 上下文压缩配置 */ contextBudget?: { maxToolOutput?: number; /** 数据获取类工具(web_fetch/http_request/browser_navigate 等)的即时截断阈值,默认 2000 字符 */ dataFetchToolOutputLimit?: number; compactThreshold?: number; maxContextTokens?: number; /** 工具输出截断时保留的头部字符数 */ toolOutputHeadLength?: number; /** 工具输出截断时保留的尾部字符数(结论通常在尾部) */ toolOutputTailLength?: number; /** 历史消息总字符预算,超过此值触发压缩 */ historyCharBudget?: number; }; /** 工具结果存储(可选) */ toolResultStore?: ToolResultStore; /** 会话历史持久化(可选,重启后恢复 Agent 上下文) */ persistence?: HistoryPersistence; } /** * 会话历史管理器 * * 职责: * - 维护 per-session 的消息历史(滑动窗口) * - 多级智能压缩(token 感知) * - Offload 大工具结果到外部存储 */ export declare class HistoryManager { private config; /** sessionId → Message[](会话历史,滑动窗口) */ private historyMap; /** sessionId → 当前 token 总数(增量维护,避免全量重算) */ private tokenCountMap; constructor(config: HistoryManagerConfig); /** 注入会话历史(从外部恢复,如持久化存储) */ setHistory(sessionId: string, messages: Message[]): void; /** 获取会话历史副本(用于持久化保存) */ getHistorySnapshot(sessionId: string): Message[]; /** 获取会话历史副本(用于构建 LLM 请求) */ getHistory(sessionId: string): Message[]; /** 追加消息到会话历史(含自动压缩) */ addHistory(sessionId: string, msg: Message): void; /** * 从持久化存储加载会话历史 * 加载后替换内存中的历史,并重建 token 计数 * 如果持久化未配置或文件不存在,返回 false */ loadHistory(sessionId: string): Promise; /** 清理指定会话的历史 */ clearHistory(sessionId: string): void; /** 清理所有会话历史 */ clearAll(): void; /** * 截断会话历史到指定位置(保留 [0, toIndex) 的消息) * * 用于消息编辑场景:用户编辑第 N 条消息后,截断历史到 N, * 然后重新追加编辑后的消息并重新生成。 * * @param sessionId 会话 ID * @param toIndex 保留的消息数量(0 = 清空历史) * @returns 被截断掉的消息数量 */ truncateHistory(sessionId: string, toIndex: number): number; /** * 从现有会话历史分叉创建新会话 * * 复制源会话 [0, fromIndex) 的消息到新会话, * 新会话可以独立追加消息而不影响源会话。 * * 用于对话分支场景:用户从第 N 条消息分叉,创建新对话线。 * * @param sourceSessionId 源会话 ID * @param targetSessionId 目标会话 ID * @param fromIndex 从源会话复制到哪个位置(不包含),默认全部 * @returns 新会话中的消息数量 */ forkHistory(sourceSessionId: string, targetSessionId: string, fromIndex?: number): number; /** * 获取会话历史的消息数量 */ getHistoryLength(sessionId: string): number; /** * 重写持久化文件(截断/分叉后历史已改变,需要全量重写) * 先删除旧文件,再逐条追加 */ private rewritePersistence; /** 不应被 offload 的读取类工具(避免 offload → read → offload 无限链) */ private static READ_THROUGH_TOOLS; /** 数据获取类工具:即时截断阈值更低,避免大量 HTML/API 响应累积导致上下文膨胀 */ private static DATA_FETCH_TOOLS; /** * 结果应始终持久化到 toolResultStore 的工具(无论结果大小)。 * 这些工具的重新执行成本极高(子 Agent 完整运行一轮), * 必须保证 read_tool_result(call_id) 在后续轮次中必定命中。 */ private static ALWAYS_PERSIST_TOOLS; /** * 处理工具输出: * - 数据获取类工具(web_fetch 等):超过 2000 字符即截断(head + tail),避免 13K HTML 累积 * - 小结果直接返回 * - 大结果写入 OffloadStore,返回摘要标签(保留 100% 可溯源) * - 无 OffloadStore 时回退到截断 */ /** * 直接将完整工具结果写入 toolResultStore(不经过 processToolOutput 的截断/offload 逻辑)。 * 用于 delegate_task 等工具:工具返回值是摘要,但完整内容需要单独持久化。 */ persistToolResult(callId: string, content: string): void; processToolOutput(output: string, callId: string, toolName?: string, sessionId?: string): string; /** * 压缩消息列表(公开接口,供 LLMCaller 在上下文过长时调用) * * 使用与 addHistory 相同的多级压缩策略,但直接作用于传入的 messages 数组。 * 返回压缩后的 token 估算值。 */ compressMessages(messages: Message[], targetTokens?: number): number; /** Level 1: 智能压缩(token 感知多级压缩管道) */ private compactHistorySmart; /** 压缩阶段 1: 卸载超长工具参数 */ private offloadToolArguments; /** 压缩阶段 2: 卸载 base64 数据块 */ private offloadBase64Content; /** 压缩阶段 3: 非破坏性卸载大工具结果 */ private offloadLargeToolResults; /** * 压缩阶段 3.5: 将旧轮次的工具结果替换为占位符。 * * 策略:找到最后一条 assistant 消息,其之前的 tool 消息属于"旧轮次", * LLM 已在前一轮看到过这些结果。将超过 200 字符的旧 tool 结果替换为: * `[tool_result: {toolName} - {N} chars - {preview}]` * * 保留最近一轮(最后 assistant 消息之后的 tool 消息)完整,因为 LLM 需要它们生成下一轮响应。 * 跳过已替换([placeholder:...)或已卸载([offload:...)的消息。 */ private replaceOldToolResults; /** 压缩阶段 4: 截断大工具结果(支持配置 head/tail 长度,结论通常在尾部) */ private truncateLargeToolResults; /** Level 2: 成对裁剪历史(移除最早的 assistant + 关联 tool 消息) */ private compactHistoryPairs; /** 截断工具输出(保留首尾,中间省略,支持配置 head/tail 长度) */ private truncateOutput; /** * 截断到指定长度限制(用于数据获取类工具的即时截断)。 * 保留头部 60% + 尾部 40%,中间省略。 */ private truncateToLimit; /** 根据 tool_call_id 从历史中查找工具名 */ static findToolNameForCallId(callId: string, history: Message[]): string; /** DJB2 哈希(用于生成短 nodeId) */ static simpleHash(str: string): number; /** * 获取非破坏性投影后的历史消息列表 * * 与 `compactHistorySmart()` 不同,此方法 **不修改原始历史**, * 而是返回一个投影副本: * - 保留最近的 N 条消息完整不变 * - 较早的消息对(assistant + tool)折叠为摘要标签 * - 原始历史可通过 `getHistory()` 完整获取 * * @param sessionId 会话 ID * @param tokenBudget token 预算(默认使用配置的 maxContextTokens) * @returns 投影后的消息列表(新数组,不影响原始历史) */ getProjectedHistory(sessionId: string, tokenBudget?: number): Message[]; /** * 为折叠的消息生成摘要标签 * * 将多条消息合并为一个 system 消息,包含: * - 消息数量统计 * - 关键工具调用列表 * - 用户消息摘要 */ private generateCollapseSummary; } //# sourceMappingURL=history-manager.d.ts.map