UNPKG

autosnippet

Version:

Extract code patterns into a knowledge base for AI coding assistants

176 lines (175 loc) 6.08 kB
/** * MessageAdapter — 统一消息操作接口 * * 消除 reactLoop 内的 useCtxWin 双模式分支: * - ContextWindowAdapter: 委托给 ContextWindow 实例 (bootstrap/system 场景) * - SimpleArrayAdapter: 裸数组模式 (对话场景) * * 两个实现对外暴露完全相同的 API, * 使得 reactLoop 及其提取方法无需关心底层消息存储方式。 * * @module core/MessageAdapter */ import { limitToolResult } from '../context/ContextWindow.js'; // ───────────────────────────────────────────── // Base class (接口定义 + JSDoc) // ───────────────────────────────────────────── /** @abstract */ export class MessageAdapter { /** 追加用户消息 */ appendUserMessage(_text) { throw new Error('not implemented'); } /** 追加助手纯文本回复 */ appendAssistantText(_text) { throw new Error('not implemented'); } /** * 追加助手带工具调用的回复 * @param _calls functionCalls 数组 */ appendAssistantWithToolCalls(_text, _calls) { throw new Error('not implemented'); } /** 追加工具执行结果 */ appendToolResult(_callId, _name, _content) { throw new Error('not implemented'); } /** 追加系统/用户 nudge 消息 */ appendUserNudge(_text) { throw new Error('not implemented'); } /** * 导出当前消息列表 (供 LLM 调用) * @returns >} */ toMessages() { throw new Error('not implemented'); } /** 重置到仅保留初始 prompt (错误恢复) */ resetToPromptOnly() { throw new Error('not implemented'); } /** * 获取工具结果限额 * @returns } */ getToolResultQuota() { throw new Error('not implemented'); } /** * 压缩检查 — 如果消息过多则自动压缩 * @returns } */ compactIfNeeded() { throw new Error('not implemented'); } /** * 格式化工具结果字符串 (统一 limitToolResult 调用) * @param rawResult 工具原始返回值 */ formatToolResult(toolName, rawResult) { const quota = this.getToolResultQuota(); return limitToolResult(toolName, rawResult, quota); } } // ───────────────────────────────────────────── // ContextWindowAdapter — 委托给 ContextWindow // ───────────────────────────────────────────── /** * 委托所有消息操作给 ContextWindow 实例。 * * 用于 bootstrap / system 场景, * ContextWindow 提供三级递进压缩 + 动态 token 预算。 */ export class ContextWindowAdapter extends MessageAdapter { #ctxWin; constructor(ctxWin) { super(); this.#ctxWin = ctxWin; } /** 获取底层 ContextWindow 实例 (供 forced-summary 等外部逻辑使用) */ get contextWindow() { return this.#ctxWin; } appendUserMessage(text) { this.#ctxWin.appendUserMessage(text); } appendAssistantText(text) { this.#ctxWin.appendAssistantText(text); } appendAssistantWithToolCalls(text, calls) { this.#ctxWin.appendAssistantWithToolCalls(text, calls); } appendToolResult(callId, name, content) { this.#ctxWin.appendToolResult(callId, name, content); } appendUserNudge(text) { this.#ctxWin.appendUserNudge(text); } toMessages() { return this.#ctxWin.toMessages(); } resetToPromptOnly() { this.#ctxWin.resetToPromptOnly(); } getToolResultQuota() { return this.#ctxWin.getToolResultQuota(); } compactIfNeeded() { return this.#ctxWin.compactIfNeeded(); } } // ───────────────────────────────────────────── // SimpleArrayAdapter — 裸数组模式 // ───────────────────────────────────────────── /** * 简单数组消息管理 — 对话场景。 * * 不做任何压缩,getToolResultQuota 返回固定 8000。 * compactIfNeeded 始终返回 no-op。 */ export class SimpleArrayAdapter extends MessageAdapter { #messages = []; appendUserMessage(text) { this.#messages.push({ role: 'user', content: text }); } appendAssistantText(text) { this.#messages.push({ role: 'assistant', content: text }); } appendAssistantWithToolCalls(text, calls) { this.#messages.push({ role: 'assistant', content: text, toolCalls: calls }); } appendToolResult(callId, name, content) { this.#messages.push({ role: 'tool', toolCallId: callId, name, content }); } appendUserNudge(text) { this.#messages.push({ role: 'user', content: text }); } toMessages() { return [...this.#messages]; } resetToPromptOnly() { const first = this.#messages[0]; this.#messages.length = 0; if (first) { this.#messages.push(first); } } getToolResultQuota() { return { maxChars: 8000, maxMatches: 20 }; } compactIfNeeded() { return { level: 0, removed: 0 }; } } // ───────────────────────────────────────────── // Factory helper // ───────────────────────────────────────────── /** 根据是否提供 contextWindow 创建对应适配器 */ export function createMessageAdapter(contextWindow) { if (contextWindow) { return new ContextWindowAdapter(contextWindow); } return new SimpleArrayAdapter(); }