dsh-plugin-om 0.0.36 → 0.0.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
  ## 功能
8
8
 
9
9
  - **自动压缩**:仅主会话,在 agent/pre-step 阻塞串行执行。净压力达到 `observeThresholdTokens` 后再累计 `tailMessageCount` 条完整消息时,把触发点前的全部消息摘要为新 `<history>` 块并精确替换对应消息区间;全部 `<history>` 块 token 合计达到 `reflectThresholdTokens` 时把全部块内条目送入重新压缩,合并为一条更紧凑的摘要。待定标记以 log-only 会话事件持久化,重启后从日志恢复
10
- - **工具驱动压缩**:摘要生成走多轮工具会话,模型经 getHistory 查看区间条目、compressHistory 分批替换 assistant 条目、completeCompression 结束。首条消息仅含压缩指令与 index 区间,不含历史内容。用户消息与系统消息不可压缩且原样保留;未压缩条目原样保留,条目正文一律以 CDATA 包裹;toolcall 条目以 `<assistant type="toolcall" tool-name="…" callId="…" index="…">` 元素呈现,内含 `<tool-args>`(调用参数 JSON,仅一层转义)与 `<tool-result>` 两段 CDATA 子元素,与 recall 工具输出同构;skill 加载条目以 `<skill_content name="…" index="…">` 元素呈现,内含 `<skill_resources>` 与 `<skill_instructions>` 两段,首次压缩时要求模型再次确认相关性,压缩后变为常规 assistant 摘要条目。最终 `<history>` 块由插件构建,天然合法无需校验
10
+ - **工具驱动压缩**:摘要生成走多轮工具会话,模型经 getHistory 查看区间条目、compressHistory 分批替换 assistant 条目、completeCompression 结束。首条消息仅含压缩指令与 index 区间,不含历史内容。用户消息与系统消息不可压缩且原样保留;未压缩条目原样保留,条目正文一律以 CDATA 包裹;toolcall 条目以 `<assistant type="toolcall" tool-name="…" callId="…" index="…">` 元素呈现,内含 `<tool-args>`(调用参数 JSON,仅一层转义)与 `<tool-result>` 两段 CDATA 子元素,与 recall 工具输出同构;skill 加载条目以 `<skill_content name="…" index="…">` 元素呈现,内含 `<skill_resources>` 与 `<skill_instructions>` 两段;ask_user_question 提问条目以 `<ask-user-question index="…">` 元素呈现,CDATA 内为 q:(问题文本,一个问题一行)与 a:(用户回答原文)行,旧版 `<askuserquestion>` 条目原样保留;两类条目首次压缩时都要求模型再次确认相关性,压缩后变为常规 assistant 摘要条目。最终 `<history>` 块由插件构建,天然合法无需校验,块首格式说明注释中的 `<user_message>`、`<sys>`、`<skill_content>`、`<ask-user-question>` 条目说明仅在块内存在对应条目时包含
11
11
  - **压缩会话记录**:每次压缩的工具循环完整对话与压缩统计(起止时间、总耗时、逐轮请求耗时与 token usage 及合计)落盘为 one-shot 子会话,成功为会话记录、失败为失败日志,便于查看模型实际的查看与压缩行为及其 token 成本。主会话日志只保留汇总:`compaction/summary` 携带 usage 与起止时间、总耗时,失败路径 `compaction/end` 携带总耗时
12
12
  - **降级容错**:systemPrompt 或 tokenMeter 服务异常时按 0 计继续压缩,问题通过 console 输出与 log-only `om/warning` 会话事件上报,同会话同一问题至多一条
13
13
  - **recall 工具**:按完整消息 index 区间回看原始会话,含被压缩内容;输出为 XML 条目序列(`<user_message>`、`<sys>`、`<assistant type="text"|"toolcall">`),正文一律以 CDATA 包裹逐字原样,toolcall 条目内嵌 `<tool-args>`(合法 JSON,仅一层转义)与 `<tool-result>` CDATA 子元素,图片附件随结果保留
@@ -62,6 +62,9 @@ preset-agent 自带 compaction-basic 压缩,阈值为上下文窗口的 80%,
62
62
  | `observeThresholdTokens` | `35000` | 净压力达到该值时触发观察压缩 |
63
63
  | `reflectThresholdTokens` | `40000` | 全部 `<history>` 块 token 合计达到该值时触发反思合并 |
64
64
  | `compressMaxTokens` | 不设置 | 压缩循环单轮生成上限,不设置时由模型适配器默认值决定 |
65
+ | `compressProvider` | 不设置 | 压缩请求的 provider,与 `compressModel` 成对配置才生效,只配置其一回落会话路由,成对配置后未路由会话也会执行压缩 |
66
+ | `compressModel` | 不设置 | 压缩请求的模型,与 `compressProvider` 成对配置才生效 |
67
+ | `compressReasoningEffort` | 不设置 | 压缩请求的思考等级,需为目标模型支持的等级,不设置时用模型默认;配置值不被目标模型支持时降级为模型默认并输出 `reasoning-effort-unavailable` 警告(每会话一次) |
65
68
  | `rateLimitWaitMs` | `60000` | 遇 429 限流后下一次压缩请求前的等待毫秒数,`0` 不限流 |
66
69
  | `tailMessageCount` | `20` | 观察触发后等待新增完整消息达到该条数才执行压缩,`0` 表示触发当轮立即执行 |
67
70
  | `compressSkipReasoning` | `true` | 工具循环 getHistory 输出是否携带 `<reasoning>` 参考条目,`true` 时不携带,压缩指令同步省略对应说明 |
@@ -133,5 +136,6 @@ tests/ # vitest 测试:服务端各模块、客户
133
136
  web/ # 机制说明与成本计算器站点:独立 Vite + React + Tailwind CSS + shadcn/ui 工程,发布到 GitHub Pages,不随插件包分发
134
137
  ├── src/model.ts # 成本模型纯函数:om 开关全会话模拟与三类 token 计价
135
138
  └── src/components/ # 机制简述、侧边栏参数面板、合并单元格成本表、shadcn/ui 原语
139
+ .agents/skills/agent-workflow/SKILL.md # agent-workflow skill:仓库内任何变更触发的完整开发工作流
136
140
  .github/workflows/web-deploy.yml # web/ 变更合入 main 时构建并部署 GitHub Pages
137
141
  ```
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":["memo","useState","DisclosureRow","IconBrowseOutline16","memo","useState","DisclosureRow","IconBrowseOutline16"],"sources":["../src/constants.ts","../src/om-event.ts","../src/client/definition.ts","../src/client/locales.ts","../src/client/format.ts","../src/client/OmCompactionCard.tsx","../src/client/OmWarningCard.tsx","../src/client/index.ts"],"sourcesContent":["/**\n * 共享常量:插件级魔法字符串,集中定义避免散落各模块。\n * 导出 PLUGIN_LABEL / HISTORY_TAG / HISTORY_TIP / COMPLETE_MESSAGE_DEFINITION /\n * HISTORY_FORMAT_NOTE / SKILL_TOOL_NAME / COMPACT_CHECKPOINT_PLUGIN /\n * COMPACTION_ABORTED_ERROR / isPluginOwnedSource。\n */\n\n/** 插件标识:压缩消息 source.plugin 取值与日志前缀。 */\nexport const PLUGIN_LABEL = 'dsh-plugin-om';\n\n/** 压缩日志标签名:<history>...</history> 包裹观察/反思日志块。 */\nexport const HISTORY_TAG = 'history';\n\n/** 压缩日志块开标签的 tip 属性(对 AI 的提醒:本块是历史压缩产物,不要复述)。 */\nexport const HISTORY_TIP = '当前块是历史消息的压缩产物,不要复述';\n\n/**\n * 「完整消息」定义(提示词 / 工具描述 / 块顶注释共用)。\n * 完整消息是摘要日志与 recall 共用的定位单位;首条 index 为 0,按会话顺序递增、全局稳定。\n */\nexport const COMPLETE_MESSAGE_DEFINITION =\n '`完整消息`指一条`用户消息`、`系统消息`、`模型输出文本`或`具有result的toolcall`;首条 index 为 0,按会话顺序递增。';\n\n/**\n * 最终 <history> 块内文块首的格式说明注释(XML 注释,完整消息定义 + 条目标签语义 + CDATA 约定)。\n */\nexport const HISTORY_FORMAT_NOTE = `<!-- ${COMPLETE_MESSAGE_DEFINITION} <TAG index=\"N\">表示单条完整消息,<TAG start=\"A\" end=\"B\"> 表示多条连续消息,start/end 是首尾完整消息的 index;消息块的内容是用CDATA包裹的纯文本;<assistant type=\"toolcall\" tool-name=\"T\" callId=\"C\" index=\"N\"> 表示工具调用,内含 <tool-args> 与 <tool-result> 两个CDATA子元素(调用参数与工具返回内容);<sys type=\"KIND\" index=\"N\"> 表示被压缩的系统消息,块中为空;<skill_content name=\"S\" index=\"N\"> 表示未压缩的原始 skill -->`;\n\n/** skill 工具名:toolcall 条目的工具名为该值时视为 skill 加载,<history> 块中以 <skill_content> 元素呈现。 */\nexport const SKILL_TOOL_NAME = 'skill';\n\n/** 旧日志压缩消息的宿主 checkpoint 标记 plugin 名(历史兼容识别用)。 */\nexport const COMPACT_CHECKPOINT_PLUGIN = 'compact';\n\n/**\n * 压缩因 signal 中止而放弃时 compaction/end 的 error 标识(服务端写入、客户端过滤):\n * 中止不是失败,客户端据此隐藏失败行(宿主不变量要求无 summary 的 end 必须带 error)。\n */\nexport const COMPACTION_ABORTED_ERROR = '压缩已中止(signal aborted)';\n\n/** 判定 user/message 的 source 是否为本插件自产(压缩日志消息;含旧宿主 checkpoint 标记兼容)。这类消息不占完整消息 index。 */\nexport function isPluginOwnedSource(\n source: { kind?: string; plugin?: string } | undefined,\n): boolean {\n if (source?.kind !== 'plugin') return false;\n return source.plugin === PLUGIN_LABEL || source.plugin === COMPACT_CHECKPOINT_PLUGIN;\n}\n","/**\n * om 事件借用通道:插件私有事件以宿主已知类型 feedback/record 持久化。\n * 导出 OM_EVENT_PREFIX / OmEventKind / OmEventPayloadMap / OmEvent /\n * appendOmEvent / readOmEvent / findOmEvents。\n *\n * 背景:持久化读取路径拒绝 KNOWN_SESSION_EVENT_TYPES 目录之外的未知类型\n * (dsh-session-persistence 的 assertEventsSupported),而 Session.append 不提供\n * ignorable 标记的写入途径,插件自定义事件类型会使含该事件的会话无法加载。\n * feedback/record(dsh-command-feedback 声明)是目录内 log-only 审计事件,所有者\n * invariant 声明其无跨事件关系、无运行时不变量、永不进入模型上下文,故选为承载\n * 类型:插件数据以 `om:1:` 前缀 + JSON 信封写入其 text 字段,解码失败按非 om\n * 记录处理(含用户自写的真实反馈记录)。\n */\nimport type { Session, SessionEvent } from './types.ts';\n\n/** om 信封 text 前缀:标识该 feedback/record 记录由本插件写入。 */\nexport const OM_EVENT_PREFIX = 'om:1:';\n\n/** om 私有事件类别(信封 kind 字段)。 */\nexport type OmEventKind =\n /** 功能降级警告(degrade.ts 报告,客户端渲染「功能降级」警告行)。 */\n | 'om/warning'\n /** 观察压缩待定标记(compress.ts 观察触发时追加)。 */\n | 'om/observe-pending'\n /** 观察压缩待定失效标记(压缩执行完成后追加,声明待定可重新触发)。 */\n | 'om/observe-invalidate';\n\n/** 各类别信封载荷(kind 之外的 JSON 字段)。 */\nexport type OmEventPayloadMap = {\n 'om/warning': {\n /** 降级问题标识(会话内去重键,取值见 degrade.ts)。 */\n problem: string;\n /** 面向用户的简短说明。 */\n message: string;\n };\n 'om/observe-pending': {\n /** 触发点:追加时的最后一条完整消息 index。 */\n triggerMessageIndex: number;\n };\n 'om/observe-invalidate': {\n /** 被失效的 om/observe-pending 事件 seq。 */\n pendingSeq: number;\n };\n};\n\n/** 一条解码后的 om 私有事件:类别、载荷与承载事件在日志中的 seq。 */\nexport type OmEvent = {\n [K in OmEventKind]: { kind: K; data: OmEventPayloadMap[K]; seq: number };\n}[OmEventKind];\n\n/** 校验载荷字段与类别匹配(运行时守卫,保证返回类型的诚实性)。 */\nfunction isValidPayload(kind: OmEventKind, data: Record<string, unknown>): boolean {\n switch (kind) {\n case 'om/warning':\n return typeof data.problem === 'string' && typeof data.message === 'string';\n case 'om/observe-pending':\n return (\n typeof data.triggerMessageIndex === 'number' &&\n Number.isSafeInteger(data.triggerMessageIndex)\n );\n case 'om/observe-invalidate':\n return typeof data.pendingSeq === 'number' && Number.isSafeInteger(data.pendingSeq);\n }\n}\n\n/**\n * 解码一条会话事件为 om 私有事件:仅识别 feedback/record 中带 om 信封前缀的\n * text;前缀缺失、JSON 非法、kind 未知或载荷字段缺失时返回 undefined。\n */\nexport function readOmEvent(event: SessionEvent | undefined | null): OmEvent | undefined {\n if (event === undefined || event === null || event.type !== 'feedback/record') return undefined;\n const text = (event.data as { text?: unknown } | undefined)?.text;\n if (typeof text !== 'string' || !text.startsWith(OM_EVENT_PREFIX)) return undefined;\n let envelope: unknown;\n try {\n envelope = JSON.parse(text.slice(OM_EVENT_PREFIX.length));\n } catch {\n return undefined;\n }\n if (envelope === null || typeof envelope !== 'object' || Array.isArray(envelope))\n return undefined;\n const { kind, ...rest } = envelope as Record<string, unknown>;\n if (typeof kind !== 'string') return undefined;\n const kinds: OmEventKind[] = ['om/warning', 'om/observe-pending', 'om/observe-invalidate'];\n if (!kinds.includes(kind as OmEventKind)) return undefined;\n const omKind = kind as OmEventKind;\n if (!isValidPayload(omKind, rest)) return undefined;\n // 载荷已由 isValidPayload 运行时校验;seq 为宿主品牌类型,经 unknown 中转收窄为 OmEvent\n return { kind: omKind, data: rest, seq: event.seq } as unknown as OmEvent;\n}\n\n/** 编码一条 om 私有事件为 feedback/record 的 text 信封。 */\nfunction encodeOmEvent<K extends OmEventKind>(kind: K, data: OmEventPayloadMap[K]): string {\n return `${OM_EVENT_PREFIX}${JSON.stringify({ kind, ...data })}`;\n}\n\n/** 追加一条 om 私有事件(借用 feedback/record,log-only,不进 surface),返回事件 seq。 */\nexport function appendOmEvent<K extends OmEventKind>(\n session: Session,\n kind: K,\n data: OmEventPayloadMap[K],\n): number {\n return session.append('feedback/record', { text: encodeOmEvent(kind, data) }).seq;\n}\n\n/** 读取日志中全部 om 私有事件(按日志顺序)。 */\nexport function findOmEvents(session: Session): OmEvent[];\n/** 读取日志中指定类别的 om 私有事件(按日志顺序,载荷类型按类别收窄)。 */\nexport function findOmEvents<K extends OmEventKind>(\n session: Session,\n kind: K,\n): Array<{ kind: K; data: OmEventPayloadMap[K]; seq: number }>;\nexport function findOmEvents(session: Session, kind?: OmEventKind): OmEvent[] {\n const result: OmEvent[] = [];\n for (const event of session.snapshotEvents()) {\n const om = readOmEvent(event);\n if (om !== undefined && (kind === undefined || om.kind === kind)) result.push(om);\n }\n return result;\n}\n","/**\n * 压缩卡片业务定义:认领插件自产的压缩生命周期事件(compaction/start|summary|end)\n * 与替换检查点(source.plugin = 'dsh-plugin-om'),聚合出可渲染的摘要卡片节点;\n * 并认领 om 警告信封事件(借用 feedback/record,kind 为 om/warning,见 om-event.ts)\n * 渲染为警告行。\n * 导出 COMPACTION_CARD_KIND / OmCompactionChatData / checkpointCompactionId /\n * omCompactionDefinition / OM_WARNING_CARD_KIND / OmWarningChatData / omWarningDefinition。\n * 宿主的 'compact' 检查点由宿主自己渲染,本定义不认领\n * (双方共存无视觉冲突:宿主无检查点证据时不产出节点)。\n */\n\nimport type { ChatNode, ChatNodeDataMap } from '@deepseek-ai/dsh-client-ui-chat/client';\nimport type {\n ConversationMatch,\n ConversationNodeContext,\n ConversationNodeDefinition,\n} from '@deepseek-ai/dsh-client-ui-conversation/client';\nimport type {} from '@deepseek-ai/dsh-compaction/types';\nimport type { SessionEvent } from '@deepseek-ai/dsh-session/types';\nimport { COMPACTION_ABORTED_ERROR, PLUGIN_LABEL } from '../constants.ts';\nimport { readOmEvent } from '../om-event.ts';\nimport type { CompactionSummaryPayload } from '../types.ts';\n\n/** 压缩卡片渲染器分发键(合并进 ChatNodeDataMap)。 */\nexport const COMPACTION_CARD_KIND = 'om-compaction';\n\n/** 功能降级警告行渲染器分发键(合并进 ChatNodeDataMap)。 */\nexport const OM_WARNING_CARD_KIND = 'om-warning';\n\ndeclare module '@deepseek-ai/dsh-client-ui-chat/client' {\n interface ChatNodeDataMap {\n /** dsh-plugin-om 压缩替换检查点渲染的摘要卡片数据。 */\n 'om-compaction': OmCompactionChatData;\n /** dsh-plugin-om 功能降级警告行数据。 */\n 'om-warning': OmWarningChatData;\n }\n}\n\n/** 压缩卡片载荷:摘要文本与遮蔽统计。 */\nexport interface OmCompactionChatData {\n /** 压缩进行中(start 已到、checkpoint/end 未到):渲染为「正在压缩上下文…」提示行。 */\n readonly running: boolean;\n /** 压缩 pass(观察/反思;来自 start 事件载荷扩展,缺失或非运行态为 null)。 */\n readonly phase: 'observe' | 'reflect' | null;\n /** compaction/summary 的文本摘要;窗口裁剪把该事件留在窗外时为 null(卡片不可展开)。 */\n readonly summary: string | null;\n /** 已载入的 compaction/summary 事件 seq,窗外时为 null。 */\n readonly summaryEventSeq: number | null;\n /** 被遮蔽的表层节点数,summary 事件缺失或载荷非法时为 null。 */\n readonly shadowedItemCount: number | null;\n /** 遮蔽的 token 数,summary 事件缺失或载荷非法时为 null。 */\n readonly shadowedTokenCount: number | null;\n /** 压缩前的字符数,载荷缺失或非法时为 null。 */\n readonly shadowedCharCount: number | null;\n /** 压缩后的字符数(摘要文本长度),summary 不可用或非法时为 null。 */\n readonly summaryCharCount: number | null;\n /** 压缩后的估算 token 数(4 字符 ≈ 1 token),summary 不可用或非法时为 null。 */\n readonly summaryTokenCount: number | null;\n /** 压缩失败的错误文案(来自 compaction/end 载荷 error);非失败节点为 null。 */\n readonly error: string | null;\n}\n\n/** 压缩生命周期关联状态:summary / checkpoint / end 事件证据。 */\ninterface OmCompactionState {\n readonly summary?: ConversationMatch;\n readonly checkpoint?: ConversationMatch;\n /** compaction/end(成功与失败都会到达;无 checkpoint 的 end 表示压缩失败或中止)。 */\n readonly end?: ConversationMatch;\n}\n\n/**\n * replace-surface 判定:surfaceOp 为 { op: 'replace' } 对象(与宿主 runtime 的\n * isReplacementSurfaceEvent 同义;宿主该助手位于浏览器 bundle,node 端测试无法求值,\n * 故本地实现同一形状检查)。\n */\nfunction isReplacementSurface(event: SessionEvent): boolean {\n const surfaceOp = (event as { surfaceOp?: unknown }).surfaceOp;\n return (\n typeof surfaceOp === 'object' &&\n surfaceOp !== null &&\n (surfaceOp as { op?: unknown }).op === 'replace'\n );\n}\n\n/**\n * 从压缩替换检查点(user/message + replace surface + source.plugin 为本插件)读取\n * 关联 compactionId;其余事件返回 undefined。\n */\nexport function checkpointCompactionId(event: SessionEvent): string | undefined {\n if (event.type !== 'user/message' || !isReplacementSurface(event)) return undefined;\n const data = event.data as unknown as {\n source?: { kind?: unknown; plugin?: unknown; compactionId?: unknown };\n };\n const source = data.source;\n if (\n source === undefined ||\n source.kind !== 'plugin' ||\n source.plugin !== PLUGIN_LABEL ||\n typeof source.compactionId !== 'string'\n ) {\n return undefined;\n }\n return source.compactionId;\n}\n\n/** 从 compaction/summary 载荷提取摘要文本与遮蔽统计(载荷非法时各字段回落 null)。 */\nfunction compactSummaryData(summaryMatch: ConversationMatch | undefined): OmCompactionChatData {\n let summary: string | null = null;\n let shadowedItemCount: number | null = null;\n let shadowedTokenCount: number | null = null;\n let shadowedCharCount: number | null = null;\n if (summaryMatch?.event.type === 'compaction/summary') {\n // 宿主载荷类型是 union 且不含插件扩展字段,读取处收窄为插件扩展类型\n const data = summaryMatch.event.data as CompactionSummaryPayload;\n if (Array.isArray(data.summary)) {\n const text = data.summary.map((block) => (block.type === 'text' ? block.text : '')).join('');\n summary = text.trim() === '' ? null : text;\n }\n shadowedItemCount =\n Array.isArray(data.shadowedSeqs) &&\n data.shadowedSeqs.every((seq) => Number.isSafeInteger(seq) && seq >= 0)\n ? data.shadowedSeqs.length\n : null;\n shadowedTokenCount =\n Number.isSafeInteger(data.shadowedTokenCount) && data.shadowedTokenCount >= 0\n ? data.shadowedTokenCount\n : null;\n shadowedCharCount =\n data.shadowedCharCount !== undefined &&\n Number.isSafeInteger(data.shadowedCharCount) &&\n data.shadowedCharCount >= 0\n ? data.shadowedCharCount\n : null;\n }\n return {\n running: false,\n phase: null,\n error: null,\n summary,\n summaryEventSeq: summaryMatch?.event.seq ?? null,\n shadowedItemCount,\n shadowedTokenCount,\n shadowedCharCount,\n summaryCharCount: summary === null ? null : summary.length,\n summaryTokenCount: summary === null ? null : Math.ceil(summary.length / 4),\n };\n}\n\n/** 从 compaction/start 载荷读取压缩 pass(observe/reflect;缺失或非法时回落 null)。 */\nfunction startPhase(start: ConversationMatch | undefined): 'observe' | 'reflect' | null {\n const data = start?.event.data as { phase?: unknown } | undefined;\n return data?.phase === 'observe' || data?.phase === 'reflect' ? data.phase : null;\n}\n\n/** 压缩进行中提示行的载荷(统计未就绪,全部为 null)。 */\nfunction runningData(start: ConversationMatch | undefined): OmCompactionChatData {\n return {\n running: true,\n phase: startPhase(start),\n error: null,\n summary: null,\n summaryEventSeq: null,\n shadowedItemCount: null,\n shadowedTokenCount: null,\n shadowedCharCount: null,\n summaryCharCount: null,\n summaryTokenCount: null,\n };\n}\n\n/**\n * 压缩失败节点的载荷:end 已到且带非中止 error、无检查点时使用。\n * error 取 compaction/end 载荷中的实际报错文案(非字符串或为空时回落 null);\n * 摘要与统计字段全部为 null。\n */\nfunction failureData(\n start: ConversationMatch | undefined,\n end: ConversationMatch,\n): OmCompactionChatData {\n const data = end.event.data as { error?: unknown } | undefined;\n return {\n running: false,\n phase: startPhase(start),\n error: typeof data?.error === 'string' && data.error !== '' ? data.error : null,\n summary: null,\n summaryEventSeq: null,\n shadowedItemCount: null,\n shadowedTokenCount: null,\n shadowedCharCount: null,\n summaryCharCount: null,\n summaryTokenCount: null,\n };\n}\n\n/** 窗口只载入部分事件时的回落证据扫描(summary / 检查点 / end 各自独立)。 */\nfunction fallbackState(context: ConversationNodeContext<OmCompactionState>): OmCompactionState {\n const summary = context.matches.find((match) => match.event.type === 'compaction/summary');\n const checkpoint = context.matches.find(\n (match) => checkpointCompactionId(match.event) !== undefined,\n );\n const end = context.matches.find((match) => match.event.type === 'compaction/end');\n return {\n ...(summary === undefined ? {} : { summary }),\n ...(checkpoint === undefined ? {} : { checkpoint }),\n ...(end === undefined ? {} : { end }),\n };\n}\n\n/** 构建最终 Chat 目标节点(与 ui-conversation 的 chatNode 助手同构)。 */\nfunction chatNode<Kind extends keyof ChatNodeDataMap & string>(\n context: ConversationNodeContext,\n kind: Kind,\n anchorSeq: number,\n data: ChatNode<Kind>['data'],\n visibility: 'visible' | 'hidden' = 'visible',\n): ChatNode<Kind> {\n return {\n key: context.key,\n kind,\n id: context.id,\n target: 'chat',\n anchorSeq,\n location: context.start?.location ?? context.matches[0]?.location ?? { kind: 'unresolved' },\n visibility,\n data,\n };\n}\n\n/**\n * 插件压缩生命周期定义:compaction/start 开启上下文,summary / 替换检查点 / end\n * 作为 update 折叠证据。有检查点时产出摘要卡片;end 已到且无检查点时,error 为\n * 非中止报错则产出可见失败行,error 为中止标识或缺失则以 hidden 撤回进行中提示行\n * (已物化节点以 hidden visibility 保留同一 key);仅 start 时渲染「正在压缩上下文…」\n * 提示行。\n */\nexport const omCompactionDefinition: ConversationNodeDefinition<OmCompactionState> = {\n kind: COMPACTION_CARD_KIND,\n target: 'chat',\n match: (event) => {\n const compactionId = checkpointCompactionId(event);\n if (compactionId !== undefined) return { id: compactionId, role: 'update' };\n if (\n event.type === 'compaction/start' ||\n event.type === 'compaction/summary' ||\n event.type === 'compaction/end'\n ) {\n const id: unknown = event.data.compactionId;\n if (typeof id !== 'string' || id === '') return null;\n return { id, role: event.type === 'compaction/start' ? 'start' : 'update' };\n }\n return null;\n },\n start: () => ({}),\n update: (context, match) => {\n if (match.event.type === 'compaction/summary') return { ...context.state, summary: match };\n if (match.event.type === 'compaction/end') return { ...context.state, end: match };\n if (checkpointCompactionId(match.event) !== undefined)\n return { ...context.state, checkpoint: match };\n return context.state;\n },\n buildViewNode: (context) => {\n const state = context.state ?? fallbackState(context);\n // 替换检查点已到达 → 压缩完成,渲染摘要卡片\n if (state.checkpoint !== undefined) {\n const data = compactSummaryData(state.summary);\n return chatNode(context, COMPACTION_CARD_KIND, state.checkpoint.event.seq, data);\n }\n // end 已到达但无检查点:error 为非中止的实际报错时渲染可见失败行;\n // 无 error 或 error 以 COMPACTION_ABORTED_ERROR 开头(用户中止)时,\n // 以 hidden visibility 撤回进行中提示行\n if (state.end !== undefined) {\n const anchorSeq = context.start?.event.seq ?? state.end.event.seq;\n const endData = state.end.event.data as { error?: unknown } | undefined;\n const isFailure =\n typeof endData?.error === 'string' &&\n endData.error !== '' &&\n !endData.error.startsWith(COMPACTION_ABORTED_ERROR);\n if (isFailure) {\n return chatNode(\n context,\n COMPACTION_CARD_KIND,\n anchorSeq,\n failureData(context.start, state.end),\n );\n }\n return chatNode(\n context,\n COMPACTION_CARD_KIND,\n anchorSeq,\n runningData(context.start),\n 'hidden',\n );\n }\n // start 已到、checkpoint/end 未到 → 压缩进行中,渲染「正在压缩上下文…」提示行\n if (context.start !== undefined) {\n return chatNode(\n context,\n COMPACTION_CARD_KIND,\n context.start.event.seq,\n runningData(context.start),\n );\n }\n return null;\n },\n};\n\n/** 功能降级警告行载荷:降级问题标识与面向用户的说明(信封载荷非法时为 null)。 */\nexport interface OmWarningChatData {\n /** 降级问题标识(om/warning 信封载荷 problem)。 */\n readonly problem: string | null;\n /** 面向用户的降级说明(om/warning 信封载荷 message)。 */\n readonly message: string | null;\n}\n\n/**\n * 插件功能降级警告定义:每条 om/warning 信封事件独立成节点(id 含 seq),渲染为可\n * 展开的「功能降级」警告行。服务端按会话同问题去重后追加,每会话同一问题至多一行;\n * 不带 om 信封的 feedback/record 记录(用户自写反馈)不认领。\n */\nexport const omWarningDefinition: ConversationNodeDefinition = {\n kind: OM_WARNING_CARD_KIND,\n target: 'chat',\n match: (event) => {\n if (readOmEvent(event)?.kind !== 'om/warning') return null;\n return { id: `om-warning:${event.seq}`, role: 'start' };\n },\n start: () => ({}),\n update: (context) => context.state,\n buildViewNode: (context) => {\n const start = context.start;\n if (start === undefined) return null;\n const om = readOmEvent(start.event);\n if (om?.kind !== 'om/warning') return null;\n const problem = om.data.problem !== '' ? om.data.problem : null;\n const message = om.data.message !== '' ? om.data.message : null;\n if (problem === null && message === null) return null;\n return chatNode(context, OM_WARNING_CARD_KIND, start.event.seq, { problem, message });\n },\n};\n","/**\n * `om-compaction` namespace 字典:插件压缩卡片的界面文案(zh/en)。\n * 导出 NS / zh / en;zh 为键集事实源,en 键集与 zh 一致。\n */\n\n/** Dictionary namespace owned by this plugin. */\nexport const NS = 'om-compaction';\n\n/** Simplified Chinese dictionary (the key-set source of truth). */\nexport const zh = {\n compaction: '上下文已压缩',\n 'compaction.completed': '已压缩 {items} 条历史记录(约 {tokens} tokens)',\n 'compaction.stats':\n '{items} 条 · {beforeChars} 字符({beforeTokens} tokens)→ {afterChars} 字符({afterTokens} tokens)',\n 'compaction.expand': '点击查看压缩摘要',\n 'compaction.unavailable': '压缩摘要不可用',\n 'compaction.running': '正在压缩上下文…',\n 'compaction.running.observe': '正在压缩上下文(观察)…',\n 'compaction.running.reflect': '正在压缩上下文(反思)…',\n 'compaction.failed': '上下文压缩失败',\n 'compaction.failed.observe': '上下文压缩失败(观察)',\n 'compaction.failed.reflect': '上下文压缩失败(反思)',\n warning: '上下文压缩功能降级',\n} as const;\n\n/** English dictionary(键集与 zh 一致)。 */\nexport const en: Record<keyof typeof zh, string> = {\n compaction: 'Context compacted',\n 'compaction.completed': 'Compacted {items} messages (~{tokens} tokens)',\n 'compaction.stats':\n '{items} msgs · {beforeChars} chars ({beforeTokens} tokens) → {afterChars} chars ({afterTokens} tokens)',\n 'compaction.expand': 'Click to view summary',\n 'compaction.unavailable': 'Summary unavailable',\n 'compaction.running': 'Compressing context…',\n 'compaction.running.observe': 'Compressing context (observation)…',\n 'compaction.running.reflect': 'Compressing context (reflection)…',\n 'compaction.failed': 'Context compaction failed',\n 'compaction.failed.observe': 'Context compaction failed (observation)',\n 'compaction.failed.reflect': 'Context compaction failed (reflection)',\n warning: 'Context compaction degraded',\n};\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n /** Compaction card copy owned by dsh-plugin-om. */\n 'om-compaction': keyof typeof zh;\n }\n}\n","/**\n * 压缩卡片统计行的紧凑数字格式化。导出 formatCompactCount。\n * <1k 原样;≥1k 用 k;≥1w(万)用 w;≥1M 用 M;保留 1 位小数并去掉末尾 .0。\n */\nexport function formatCompactCount(value: number): string {\n const trim = (n: number): string => {\n const text = String(Math.round(n * 10) / 10);\n return text.endsWith('.0') ? text.slice(0, -2) : text;\n };\n if (value >= 1_000_000) return `${trim(value / 1_000_000)}M`;\n if (value >= 10_000) return `${trim(value / 10_000)}w`;\n if (value >= 1_000) return `${trim(value / 1_000)}k`;\n return String(value);\n}\n","/**\n * 压缩卡片渲染器:与宿主「上下文注入」卡片同款的折叠行。\n * 复用平台原语 DisclosureRow;行内统计与展开体样式按宿主 ContextInjectionRow 的规则\n * 注入 <style>(宿主该卡片样式是编译期哈希的 CSS Module,插件 bundle 无法引用其类名)。\n * 卡片报告模型从何处起不再看到那段历史;summary 留在加载窗口外时行不可展开。\n * 压缩失败节点渲染为可展开的错误行:折叠行显示错误摘要,展开体显示完整报错。\n */\n\nimport type { ChatNode } from '@deepseek-ai/dsh-client-ui-chat/client';\nimport { DisclosureRow, IconBrowseOutline16 } from '@deepseek-ai/dsh-client-ui-primitives';\nimport type { TranslateNS } from '@deepseek-ai/dsh-client-ui-slots';\nimport type { CSSProperties } from 'react';\nimport { memo, useState } from 'react';\nimport { formatCompactCount } from './format.ts';\n\n/** Keyed renderer props: 装配好的卡片节点 + 绑定 `om-compaction` 命名空间的 locale 座。 */\nexport interface OmCompactionCardProps {\n readonly node: ChatNode<'om-compaction'>;\n readonly t: TranslateNS<'om-compaction'>;\n}\n\n/** 卡片样式类名(与宿主 ContextInjectionRow.module.css 同款规则,见下方注册)。 */\nconst css = {\n root: 'om-compaction-root',\n chevron: 'om-compaction-chevron',\n sep: 'om-compaction-sep',\n summary: 'om-compaction-summary',\n body: 'om-compaction-body',\n} as const;\n\n/** 宿主 ContextInjectionRow.module.css 的规则(逐字一致,仅类名按插件前缀)。 */\nconst cardCss = `\n.${css.root}{min-width:0}\n.${css.root}[data-open]{padding-bottom:4px}\n.${css.chevron}{color:var(--dsw-alias-label-secondary)}\n.${css.sep}{background:var(--dsw-alias-label-caption);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}\n.${css.summary}{min-width:0;color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;flex:auto;font-size:14px;line-height:24px;overflow:hidden}\n.${css.body}{box-sizing:border-box;background:var(--dsw-alias-markdown-code-block);width:calc(100% - 22px);max-height:141px;color:var(--dsw-alias-label-tertiary);font:400 11px/16px var(--ds-font-family-code);border:none;border-radius:8px;margin:4px 0 0 22px;padding:10px 16px 12px 12px;overflow:auto}\n`;\n\n/** 注册卡片样式(无 document 的环境如 node 测试直接跳过)。 */\nif (\n typeof document !== 'undefined' &&\n document.querySelector('style[data-dsh-plugin-om-card]') === null\n) {\n const tag = document.createElement('style');\n tag.dataset.dshPluginOmCard = 'true';\n tag.textContent = cardCss;\n document.head.appendChild(tag);\n}\n\n/** 折叠式压缩卡片(统计标题行 + 代码块样式 summary 展开)。 */\nexport const OmCompactionCard = memo(function OmCompactionCard({ node, t }: OmCompactionCardProps) {\n const [expanded, setExpanded] = useState(false);\n const { data } = node;\n // 压缩进行中:不可展开的「正在压缩上下文…」提示行(按 phase 区分文案)\n if (data.running) {\n const runningLabel =\n data.phase === 'observe'\n ? t('compaction.running.observe')\n : data.phase === 'reflect'\n ? t('compaction.running.reflect')\n : t('compaction.running');\n return (\n <div style={styles.row}>\n <DisclosureRow\n className={css.root}\n icon={<IconBrowseOutline16 size={14} />}\n title={runningLabel}\n open={false}\n expandable={false}\n onToggle={() => {\n /* 进行中提示行不可展开 */\n }}\n />\n </div>\n );\n }\n // 压缩失败:可展开的错误行(按 phase 区分文案),折叠行为错误摘要、展开体为完整报错\n if (data.error !== null) {\n const failedLabel =\n data.phase === 'observe'\n ? t('compaction.failed.observe')\n : data.phase === 'reflect'\n ? t('compaction.failed.reflect')\n : t('compaction.failed');\n const errorSummary = data.error.length > 80 ? `${data.error.slice(0, 80)}…` : data.error;\n return (\n <div style={styles.row}>\n <DisclosureRow\n className={css.root}\n icon={<IconBrowseOutline16 size={14} />}\n chevronClassName={css.chevron}\n title={failedLabel}\n collapsedContent={\n <>\n <span className={css.sep} aria-hidden />\n <span className={css.summary}>{errorSummary}</span>\n </>\n }\n keepContentWhenOpen\n expandable\n expandOnRowClick\n open={expanded}\n onToggle={() => {\n setExpanded((value) => !value);\n }}\n >\n <div className={css.body} style={styles.body}>\n {data.error}\n </div>\n </DisclosureRow>\n </div>\n );\n }\n const expandable = data.summary !== null;\n const open = expandable && expanded;\n // 统计行:优先完整压缩前后统计,载荷字段不全时逐级回落\n const stats =\n data.shadowedItemCount !== null &&\n data.shadowedCharCount !== null &&\n data.shadowedTokenCount !== null &&\n data.summaryCharCount !== null &&\n data.summaryTokenCount !== null\n ? t('compaction.stats', {\n items: formatCompactCount(data.shadowedItemCount),\n beforeChars: formatCompactCount(data.shadowedCharCount),\n beforeTokens: formatCompactCount(data.shadowedTokenCount),\n afterChars: formatCompactCount(data.summaryCharCount),\n afterTokens: formatCompactCount(data.summaryTokenCount),\n })\n : data.shadowedItemCount !== null && data.shadowedTokenCount !== null\n ? t('compaction.completed', {\n items: formatCompactCount(data.shadowedItemCount),\n tokens: formatCompactCount(data.shadowedTokenCount),\n })\n : expandable\n ? t('compaction.expand')\n : t('compaction.unavailable');\n return (\n <div style={styles.row}>\n <DisclosureRow\n className={css.root}\n icon={<IconBrowseOutline16 size={14} />}\n chevronClassName={css.chevron}\n title={t('compaction')}\n collapsedContent={\n <>\n <span className={css.sep} aria-hidden />\n <span className={css.summary} data-om-compaction-summary>\n {stats}\n </span>\n </>\n }\n keepContentWhenOpen\n expandable={expandable}\n expandOnRowClick\n open={open}\n onToggle={() => {\n setExpanded((value) => !value);\n }}\n >\n {data.summary !== null && (\n <div className={css.body} style={styles.body}>\n {data.summary}\n </div>\n )}\n </DisclosureRow>\n </div>\n );\n});\n\nconst styles: Record<string, CSSProperties> = {\n row: {},\n /** 摘要与失败报错为多行文本,保留换行。 */\n body: { whiteSpace: 'pre-wrap' },\n};\n","/**\n * 功能降级警告行渲染器:与压缩卡片同款的折叠行。\n * 折叠行显示降级说明摘要,展开体显示完整说明;数据来自 om/warning 信封载荷\n * (借用 feedback/record),服务端按会话同问题去重后追加(每会话同一问题至多一行)。\n */\n\nimport type { ChatNode } from '@deepseek-ai/dsh-client-ui-chat/client';\nimport { DisclosureRow, IconBrowseOutline16 } from '@deepseek-ai/dsh-client-ui-primitives';\nimport type { TranslateNS } from '@deepseek-ai/dsh-client-ui-slots';\nimport type { CSSProperties } from 'react';\nimport { memo, useState } from 'react';\n\n/** Keyed renderer props: 装配好的警告行节点 + 绑定 `om-compaction` 命名空间的 locale 座。 */\nexport interface OmWarningCardProps {\n readonly node: ChatNode<'om-warning'>;\n readonly t: TranslateNS<'om-compaction'>;\n}\n\n/** 折叠式功能降级警告行(降级说明摘要行 + 完整说明展开)。 */\nexport const OmWarningCard = memo(function OmWarningCard({ node, t }: OmWarningCardProps) {\n const [expanded, setExpanded] = useState(false);\n const { data } = node;\n const message = data.message ?? (data.problem !== null ? data.problem : '');\n const expandable = message !== '';\n const messageSummary = message.length > 80 ? `${message.slice(0, 80)}…` : message;\n return (\n <div>\n <DisclosureRow\n className=\"om-compaction-root\"\n icon={<IconBrowseOutline16 size={14} />}\n chevronClassName=\"om-compaction-chevron\"\n title={t('warning')}\n collapsedContent={\n expandable ? (\n <>\n <span className=\"om-compaction-sep\" aria-hidden />\n <span className=\"om-compaction-summary\">{messageSummary}</span>\n </>\n ) : undefined\n }\n keepContentWhenOpen\n expandable={expandable}\n expandOnRowClick\n open={expandable && expanded}\n onToggle={() => {\n if (expandable) setExpanded((value) => !value);\n }}\n >\n {expandable && (\n <div className=\"om-compaction-body\" style={bodyStyle}>\n {message}\n </div>\n )}\n </DisclosureRow>\n </div>\n );\n});\n\nconst bodyStyle: CSSProperties = { whiteSpace: 'pre-wrap' };\n","/**\n * 浏览器客户端入口(exports[\"./client\"] → dist/client.js):注册压缩卡片与功能降级\n * 警告行的 locale 字典、conversation 业务定义与 keyed 渲染器。宿主 conversation UI 只\n * 识别内置 'compact' 检查点,插件自产的压缩检查点(source.plugin = 'dsh-plugin-om')\n * 由本 bundle 认领并在消息列表渲染「已压缩」卡片;om 警告信封事件(借用\n * feedback/record)渲染为「功能降级」警告行。\n */\nimport type { Context } from '@deepseek-ai/cordis';\n// Type-only: 拉取 locale 插件的 Context 合并(ctx.locale)。\nimport type {} from '@deepseek-ai/dsh-client-locale/client';\n// Type-only: 拉取 uiConversation 服务与 ChatNodeDataMap 的类型合并。\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client';\n// Type-only: 拉取 slots 服务的 Context 合并(ctx.slots)。\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client';\nimport { omCompactionDefinition, omWarningDefinition } from './definition.ts';\nimport { en, NS, zh } from './locales.ts';\nimport { OmCompactionCard } from './OmCompactionCard.tsx';\nimport { OmWarningCard } from './OmWarningCard.tsx';\n\n/** Required services: 聊天节点槽、uiConversation 会话定义注册表与 locale 服务。 */\nexport const inject = ['slots', 'uiConversation', 'locale'];\n\n/** Client plugin body: 注册压缩卡片的业务定义与 keyed 渲染器(随插件卸载移除)。 */\nexport function apply(ctx: Context): void {\n ctx.effect(\n () => ctx.locale.register(NS, { zh, en }),\n 'dsh-plugin-om: compaction card dictionaries',\n );\n ctx.effect(\n () => ctx.uiConversation.events.register(omCompactionDefinition),\n 'dsh-plugin-om: compaction definition',\n );\n ctx.effect(\n () => ctx.uiConversation.events.register(omWarningDefinition),\n 'dsh-plugin-om: om warning definition',\n );\n ctx.slots.inject('conversation.chat.node', () =>\n ctx.slots.register(\n { name: 'conversation.chat.node', key: 'om-compaction', locale: NS },\n OmCompactionCard,\n ),\n );\n ctx.slots.inject('conversation.chat.node', () =>\n ctx.slots.register(\n { name: 'conversation.chat.node', key: 'om-warning', locale: NS },\n OmWarningCard,\n ),\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"client.js","names":["memo","useState","DisclosureRow","IconBrowseOutline16","memo","useState","DisclosureRow","IconBrowseOutline16"],"sources":["../src/constants.ts","../src/om-event.ts","../src/client/definition.ts","../src/client/locales.ts","../src/client/format.ts","../src/client/OmCompactionCard.tsx","../src/client/OmWarningCard.tsx","../src/client/index.ts"],"sourcesContent":["/**\n * 共享常量:插件级魔法字符串,集中定义避免散落各模块。\n * 导出 PLUGIN_LABEL / HISTORY_TAG / HISTORY_TIP / COMPLETE_MESSAGE_DEFINITION /\n * historyFormatNote / SKILL_TOOL_NAME / ASK_USER_QUESTION_TOOL_NAME /\n * COMPACT_CHECKPOINT_PLUGIN / COMPACTION_ABORTED_ERROR / isPluginOwnedSource。\n */\n\n/** 插件标识:压缩消息 source.plugin 取值与日志前缀。 */\nexport const PLUGIN_LABEL = 'dsh-plugin-om';\n\n/** 压缩日志标签名:<history>...</history> 包裹观察/反思日志块。 */\nexport const HISTORY_TAG = 'history';\n\n/** 压缩日志块开标签的 tip 属性(对 AI 的提醒:本块是历史压缩产物,不要复述)。 */\nexport const HISTORY_TIP = '当前块是历史消息的压缩产物,不要复述';\n\n/**\n * 「完整消息」定义(提示词 / 工具描述 / 块顶注释共用)。\n * 完整消息是摘要日志与 recall 共用的定位单位;首条 index 为 0,按会话顺序递增、全局稳定。\n */\nexport const COMPLETE_MESSAGE_DEFINITION =\n '`完整消息`指一条`用户消息`、`系统消息`、`模型输出文本`或`具有result的toolcall`;首条 index 为 0,按会话顺序递增。';\n\n/** 块顶格式说明注释中按块内条目动态追加的分段开关。 */\nexport type HistoryNoteSections = {\n /** 块内存在 user 条目时追加 <user_message> 说明。 */\n user?: boolean;\n /** 块内存在 sys 条目时追加 <sys> 说明。 */\n sys?: boolean;\n /** 块内存在未压缩 skill 条目时追加 <skill_content> 说明。 */\n skill?: boolean;\n /** 块内存在 ask_user_question 条目时追加 <ask-user-question> 说明。 */\n askUserQuestion?: boolean;\n};\n\n/**\n * 最终 <history> 块内文块首的格式说明注释(XML 注释)。通用部分(完整消息定义 +\n * 条目标签语义 + CDATA 约定 + toolcall 结构)始终保留;<user_message> / <sys> /\n * <skill_content> / <ask-user-question> 的条目说明仅在块内存在对应条目时追加。\n */\nexport function historyFormatNote(sections: HistoryNoteSections = {}): string {\n const parts = [\n COMPLETE_MESSAGE_DEFINITION,\n '<TAG index=\"N\">表示单条完整消息,<TAG start=\"A\" end=\"B\"> 表示多条连续消息,start/end 是首尾完整消息的 index;消息块的内容是用CDATA包裹的纯文本',\n '<assistant type=\"toolcall\" tool-name=\"T\" callId=\"C\" index=\"N\"> 表示工具调用,内含 <tool-args> 与 <tool-result> 两个CDATA子元素(调用参数与工具返回内容)',\n ];\n if (sections.user) parts.push('<user_message index=\"N\"> 表示用户消息原文');\n if (sections.sys) parts.push('<sys type=\"KIND\" index=\"N\"> 表示被压缩的系统消息,块中为空');\n if (sections.skill) parts.push('<skill_content name=\"S\" index=\"N\"> 表示未压缩的原始 skill');\n if (sections.askUserQuestion)\n parts.push(\n '<ask-user-question index=\"N\"> 表示向用户提问,CDATA 内为 q:(提问)与 a:(用户回答)行',\n );\n return `<!-- ${parts.join(';')} -->`;\n}\n\n/** skill 工具名:toolcall 条目的工具名为该值时视为 skill 加载,<history> 块中以 <skill_content> 元素呈现。 */\nexport const SKILL_TOOL_NAME = 'skill';\n\n/**\n * ask_user_question 工具名:toolcall 条目的工具名为该值时视为向用户的提问,\n * <history> 块中以 <ask-user-question> 元素呈现,压缩时与 skill 一样要求二次确认。\n */\nexport const ASK_USER_QUESTION_TOOL_NAME = 'ask_user_question';\n\n/** 旧日志压缩消息的宿主 checkpoint 标记 plugin 名(历史兼容识别用)。 */\nexport const COMPACT_CHECKPOINT_PLUGIN = 'compact';\n\n/**\n * 压缩因 signal 中止而放弃时 compaction/end 的 error 标识(服务端写入、客户端过滤):\n * 中止不是失败,客户端据此隐藏失败行(宿主不变量要求无 summary 的 end 必须带 error)。\n */\nexport const COMPACTION_ABORTED_ERROR = '压缩已中止(signal aborted)';\n\n/** 判定 user/message 的 source 是否为本插件自产(压缩日志消息;含旧宿主 checkpoint 标记兼容)。这类消息不占完整消息 index。 */\nexport function isPluginOwnedSource(\n source: { kind?: string; plugin?: string } | undefined,\n): boolean {\n if (source?.kind !== 'plugin') return false;\n return source.plugin === PLUGIN_LABEL || source.plugin === COMPACT_CHECKPOINT_PLUGIN;\n}\n","/**\n * om 事件借用通道:插件私有事件以宿主已知类型 feedback/record 持久化。\n * 导出 OM_EVENT_PREFIX / OmEventKind / OmEventPayloadMap / OmEvent /\n * appendOmEvent / readOmEvent / findOmEvents。\n *\n * 背景:持久化读取路径拒绝 KNOWN_SESSION_EVENT_TYPES 目录之外的未知类型\n * (dsh-session-persistence 的 assertEventsSupported),而 Session.append 不提供\n * ignorable 标记的写入途径,插件自定义事件类型会使含该事件的会话无法加载。\n * feedback/record(dsh-command-feedback 声明)是目录内 log-only 审计事件,所有者\n * invariant 声明其无跨事件关系、无运行时不变量、永不进入模型上下文,故选为承载\n * 类型:插件数据以 `om:1:` 前缀 + JSON 信封写入其 text 字段,解码失败按非 om\n * 记录处理(含用户自写的真实反馈记录)。\n */\nimport type { Session, SessionEvent } from './types.ts';\n\n/** om 信封 text 前缀:标识该 feedback/record 记录由本插件写入。 */\nexport const OM_EVENT_PREFIX = 'om:1:';\n\n/** om 私有事件类别(信封 kind 字段)。 */\nexport type OmEventKind =\n /** 功能降级警告(degrade.ts 报告,客户端渲染「功能降级」警告行)。 */\n | 'om/warning'\n /** 观察压缩待定标记(compress.ts 观察触发时追加)。 */\n | 'om/observe-pending'\n /** 观察压缩待定失效标记(压缩执行完成后追加,声明待定可重新触发)。 */\n | 'om/observe-invalidate';\n\n/** 各类别信封载荷(kind 之外的 JSON 字段)。 */\nexport type OmEventPayloadMap = {\n 'om/warning': {\n /** 降级问题标识(会话内去重键,取值见 degrade.ts)。 */\n problem: string;\n /** 面向用户的简短说明。 */\n message: string;\n };\n 'om/observe-pending': {\n /** 触发点:追加时的最后一条完整消息 index。 */\n triggerMessageIndex: number;\n };\n 'om/observe-invalidate': {\n /** 被失效的 om/observe-pending 事件 seq。 */\n pendingSeq: number;\n };\n};\n\n/** 一条解码后的 om 私有事件:类别、载荷与承载事件在日志中的 seq。 */\nexport type OmEvent = {\n [K in OmEventKind]: { kind: K; data: OmEventPayloadMap[K]; seq: number };\n}[OmEventKind];\n\n/** 校验载荷字段与类别匹配(运行时守卫,保证返回类型的诚实性)。 */\nfunction isValidPayload(kind: OmEventKind, data: Record<string, unknown>): boolean {\n switch (kind) {\n case 'om/warning':\n return typeof data.problem === 'string' && typeof data.message === 'string';\n case 'om/observe-pending':\n return (\n typeof data.triggerMessageIndex === 'number' &&\n Number.isSafeInteger(data.triggerMessageIndex)\n );\n case 'om/observe-invalidate':\n return typeof data.pendingSeq === 'number' && Number.isSafeInteger(data.pendingSeq);\n }\n}\n\n/**\n * 解码一条会话事件为 om 私有事件:仅识别 feedback/record 中带 om 信封前缀的\n * text;前缀缺失、JSON 非法、kind 未知或载荷字段缺失时返回 undefined。\n */\nexport function readOmEvent(event: SessionEvent | undefined | null): OmEvent | undefined {\n if (event === undefined || event === null || event.type !== 'feedback/record') return undefined;\n const text = (event.data as { text?: unknown } | undefined)?.text;\n if (typeof text !== 'string' || !text.startsWith(OM_EVENT_PREFIX)) return undefined;\n let envelope: unknown;\n try {\n envelope = JSON.parse(text.slice(OM_EVENT_PREFIX.length));\n } catch {\n return undefined;\n }\n if (envelope === null || typeof envelope !== 'object' || Array.isArray(envelope))\n return undefined;\n const { kind, ...rest } = envelope as Record<string, unknown>;\n if (typeof kind !== 'string') return undefined;\n const kinds: OmEventKind[] = ['om/warning', 'om/observe-pending', 'om/observe-invalidate'];\n if (!kinds.includes(kind as OmEventKind)) return undefined;\n const omKind = kind as OmEventKind;\n if (!isValidPayload(omKind, rest)) return undefined;\n // 载荷已由 isValidPayload 运行时校验;seq 为宿主品牌类型,经 unknown 中转收窄为 OmEvent\n return { kind: omKind, data: rest, seq: event.seq } as unknown as OmEvent;\n}\n\n/** 编码一条 om 私有事件为 feedback/record 的 text 信封。 */\nfunction encodeOmEvent<K extends OmEventKind>(kind: K, data: OmEventPayloadMap[K]): string {\n return `${OM_EVENT_PREFIX}${JSON.stringify({ kind, ...data })}`;\n}\n\n/** 追加一条 om 私有事件(借用 feedback/record,log-only,不进 surface),返回事件 seq。 */\nexport function appendOmEvent<K extends OmEventKind>(\n session: Session,\n kind: K,\n data: OmEventPayloadMap[K],\n): number {\n return session.append('feedback/record', { text: encodeOmEvent(kind, data) }).seq;\n}\n\n/** 读取日志中全部 om 私有事件(按日志顺序)。 */\nexport function findOmEvents(session: Session): OmEvent[];\n/** 读取日志中指定类别的 om 私有事件(按日志顺序,载荷类型按类别收窄)。 */\nexport function findOmEvents<K extends OmEventKind>(\n session: Session,\n kind: K,\n): Array<{ kind: K; data: OmEventPayloadMap[K]; seq: number }>;\nexport function findOmEvents(session: Session, kind?: OmEventKind): OmEvent[] {\n const result: OmEvent[] = [];\n for (const event of session.snapshotEvents()) {\n const om = readOmEvent(event);\n if (om !== undefined && (kind === undefined || om.kind === kind)) result.push(om);\n }\n return result;\n}\n","/**\n * 压缩卡片业务定义:认领插件自产的压缩生命周期事件(compaction/start|summary|end)\n * 与替换检查点(source.plugin = 'dsh-plugin-om'),聚合出可渲染的摘要卡片节点;\n * 并认领 om 警告信封事件(借用 feedback/record,kind 为 om/warning,见 om-event.ts)\n * 渲染为警告行。\n * 导出 COMPACTION_CARD_KIND / OmCompactionChatData / checkpointCompactionId /\n * omCompactionDefinition / OM_WARNING_CARD_KIND / OmWarningChatData / omWarningDefinition。\n * 宿主的 'compact' 检查点由宿主自己渲染,本定义不认领\n * (双方共存无视觉冲突:宿主无检查点证据时不产出节点)。\n */\n\nimport type { ChatNode, ChatNodeDataMap } from '@deepseek-ai/dsh-client-ui-chat/client';\nimport type {\n ConversationMatch,\n ConversationNodeContext,\n ConversationNodeDefinition,\n} from '@deepseek-ai/dsh-client-ui-conversation/client';\nimport type {} from '@deepseek-ai/dsh-compaction/types';\nimport type { SessionEvent } from '@deepseek-ai/dsh-session/types';\nimport { COMPACTION_ABORTED_ERROR, PLUGIN_LABEL } from '../constants.ts';\nimport { readOmEvent } from '../om-event.ts';\nimport type { CompactionSummaryPayload } from '../types.ts';\n\n/** 压缩卡片渲染器分发键(合并进 ChatNodeDataMap)。 */\nexport const COMPACTION_CARD_KIND = 'om-compaction';\n\n/** 功能降级警告行渲染器分发键(合并进 ChatNodeDataMap)。 */\nexport const OM_WARNING_CARD_KIND = 'om-warning';\n\ndeclare module '@deepseek-ai/dsh-client-ui-chat/client' {\n interface ChatNodeDataMap {\n /** dsh-plugin-om 压缩替换检查点渲染的摘要卡片数据。 */\n 'om-compaction': OmCompactionChatData;\n /** dsh-plugin-om 功能降级警告行数据。 */\n 'om-warning': OmWarningChatData;\n }\n}\n\n/** 压缩卡片载荷:摘要文本与遮蔽统计。 */\nexport interface OmCompactionChatData {\n /** 压缩进行中(start 已到、checkpoint/end 未到):渲染为「正在压缩上下文…」提示行。 */\n readonly running: boolean;\n /** 压缩 pass(观察/反思;来自 start 事件载荷扩展,缺失或非运行态为 null)。 */\n readonly phase: 'observe' | 'reflect' | null;\n /** compaction/summary 的文本摘要;窗口裁剪把该事件留在窗外时为 null(卡片不可展开)。 */\n readonly summary: string | null;\n /** 已载入的 compaction/summary 事件 seq,窗外时为 null。 */\n readonly summaryEventSeq: number | null;\n /** 被遮蔽的表层节点数,summary 事件缺失或载荷非法时为 null。 */\n readonly shadowedItemCount: number | null;\n /** 遮蔽的 token 数,summary 事件缺失或载荷非法时为 null。 */\n readonly shadowedTokenCount: number | null;\n /** 压缩前的字符数,载荷缺失或非法时为 null。 */\n readonly shadowedCharCount: number | null;\n /** 压缩后的字符数(摘要文本长度),summary 不可用或非法时为 null。 */\n readonly summaryCharCount: number | null;\n /** 压缩后的估算 token 数(4 字符 ≈ 1 token),summary 不可用或非法时为 null。 */\n readonly summaryTokenCount: number | null;\n /** 压缩失败的错误文案(来自 compaction/end 载荷 error);非失败节点为 null。 */\n readonly error: string | null;\n}\n\n/** 压缩生命周期关联状态:summary / checkpoint / end 事件证据。 */\ninterface OmCompactionState {\n readonly summary?: ConversationMatch;\n readonly checkpoint?: ConversationMatch;\n /** compaction/end(成功与失败都会到达;无 checkpoint 的 end 表示压缩失败或中止)。 */\n readonly end?: ConversationMatch;\n}\n\n/**\n * replace-surface 判定:surfaceOp 为 { op: 'replace' } 对象(与宿主 runtime 的\n * isReplacementSurfaceEvent 同义;宿主该助手位于浏览器 bundle,node 端测试无法求值,\n * 故本地实现同一形状检查)。\n */\nfunction isReplacementSurface(event: SessionEvent): boolean {\n const surfaceOp = (event as { surfaceOp?: unknown }).surfaceOp;\n return (\n typeof surfaceOp === 'object' &&\n surfaceOp !== null &&\n (surfaceOp as { op?: unknown }).op === 'replace'\n );\n}\n\n/**\n * 从压缩替换检查点(user/message + replace surface + source.plugin 为本插件)读取\n * 关联 compactionId;其余事件返回 undefined。\n */\nexport function checkpointCompactionId(event: SessionEvent): string | undefined {\n if (event.type !== 'user/message' || !isReplacementSurface(event)) return undefined;\n const data = event.data as unknown as {\n source?: { kind?: unknown; plugin?: unknown; compactionId?: unknown };\n };\n const source = data.source;\n if (\n source === undefined ||\n source.kind !== 'plugin' ||\n source.plugin !== PLUGIN_LABEL ||\n typeof source.compactionId !== 'string'\n ) {\n return undefined;\n }\n return source.compactionId;\n}\n\n/** 从 compaction/summary 载荷提取摘要文本与遮蔽统计(载荷非法时各字段回落 null)。 */\nfunction compactSummaryData(summaryMatch: ConversationMatch | undefined): OmCompactionChatData {\n let summary: string | null = null;\n let shadowedItemCount: number | null = null;\n let shadowedTokenCount: number | null = null;\n let shadowedCharCount: number | null = null;\n if (summaryMatch?.event.type === 'compaction/summary') {\n // 宿主载荷类型是 union 且不含插件扩展字段,读取处收窄为插件扩展类型\n const data = summaryMatch.event.data as CompactionSummaryPayload;\n if (Array.isArray(data.summary)) {\n const text = data.summary.map((block) => (block.type === 'text' ? block.text : '')).join('');\n summary = text.trim() === '' ? null : text;\n }\n shadowedItemCount =\n Array.isArray(data.shadowedSeqs) &&\n data.shadowedSeqs.every((seq) => Number.isSafeInteger(seq) && seq >= 0)\n ? data.shadowedSeqs.length\n : null;\n shadowedTokenCount =\n Number.isSafeInteger(data.shadowedTokenCount) && data.shadowedTokenCount >= 0\n ? data.shadowedTokenCount\n : null;\n shadowedCharCount =\n data.shadowedCharCount !== undefined &&\n Number.isSafeInteger(data.shadowedCharCount) &&\n data.shadowedCharCount >= 0\n ? data.shadowedCharCount\n : null;\n }\n return {\n running: false,\n phase: null,\n error: null,\n summary,\n summaryEventSeq: summaryMatch?.event.seq ?? null,\n shadowedItemCount,\n shadowedTokenCount,\n shadowedCharCount,\n summaryCharCount: summary === null ? null : summary.length,\n summaryTokenCount: summary === null ? null : Math.ceil(summary.length / 4),\n };\n}\n\n/** 从 compaction/start 载荷读取压缩 pass(observe/reflect;缺失或非法时回落 null)。 */\nfunction startPhase(start: ConversationMatch | undefined): 'observe' | 'reflect' | null {\n const data = start?.event.data as { phase?: unknown } | undefined;\n return data?.phase === 'observe' || data?.phase === 'reflect' ? data.phase : null;\n}\n\n/** 压缩进行中提示行的载荷(统计未就绪,全部为 null)。 */\nfunction runningData(start: ConversationMatch | undefined): OmCompactionChatData {\n return {\n running: true,\n phase: startPhase(start),\n error: null,\n summary: null,\n summaryEventSeq: null,\n shadowedItemCount: null,\n shadowedTokenCount: null,\n shadowedCharCount: null,\n summaryCharCount: null,\n summaryTokenCount: null,\n };\n}\n\n/**\n * 压缩失败节点的载荷:end 已到且带非中止 error、无检查点时使用。\n * error 取 compaction/end 载荷中的实际报错文案(非字符串或为空时回落 null);\n * 摘要与统计字段全部为 null。\n */\nfunction failureData(\n start: ConversationMatch | undefined,\n end: ConversationMatch,\n): OmCompactionChatData {\n const data = end.event.data as { error?: unknown } | undefined;\n return {\n running: false,\n phase: startPhase(start),\n error: typeof data?.error === 'string' && data.error !== '' ? data.error : null,\n summary: null,\n summaryEventSeq: null,\n shadowedItemCount: null,\n shadowedTokenCount: null,\n shadowedCharCount: null,\n summaryCharCount: null,\n summaryTokenCount: null,\n };\n}\n\n/** 窗口只载入部分事件时的回落证据扫描(summary / 检查点 / end 各自独立)。 */\nfunction fallbackState(context: ConversationNodeContext<OmCompactionState>): OmCompactionState {\n const summary = context.matches.find((match) => match.event.type === 'compaction/summary');\n const checkpoint = context.matches.find(\n (match) => checkpointCompactionId(match.event) !== undefined,\n );\n const end = context.matches.find((match) => match.event.type === 'compaction/end');\n return {\n ...(summary === undefined ? {} : { summary }),\n ...(checkpoint === undefined ? {} : { checkpoint }),\n ...(end === undefined ? {} : { end }),\n };\n}\n\n/** 构建最终 Chat 目标节点(与 ui-conversation 的 chatNode 助手同构)。 */\nfunction chatNode<Kind extends keyof ChatNodeDataMap & string>(\n context: ConversationNodeContext,\n kind: Kind,\n anchorSeq: number,\n data: ChatNode<Kind>['data'],\n visibility: 'visible' | 'hidden' = 'visible',\n): ChatNode<Kind> {\n return {\n key: context.key,\n kind,\n id: context.id,\n target: 'chat',\n anchorSeq,\n location: context.start?.location ?? context.matches[0]?.location ?? { kind: 'unresolved' },\n visibility,\n data,\n };\n}\n\n/**\n * 插件压缩生命周期定义:compaction/start 开启上下文,summary / 替换检查点 / end\n * 作为 update 折叠证据。有检查点时产出摘要卡片;end 已到且无检查点时,error 为\n * 非中止报错则产出可见失败行,error 为中止标识或缺失则以 hidden 撤回进行中提示行\n * (已物化节点以 hidden visibility 保留同一 key);仅 start 时渲染「正在压缩上下文…」\n * 提示行。\n */\nexport const omCompactionDefinition: ConversationNodeDefinition<OmCompactionState> = {\n kind: COMPACTION_CARD_KIND,\n target: 'chat',\n match: (event) => {\n const compactionId = checkpointCompactionId(event);\n if (compactionId !== undefined) return { id: compactionId, role: 'update' };\n if (\n event.type === 'compaction/start' ||\n event.type === 'compaction/summary' ||\n event.type === 'compaction/end'\n ) {\n const id: unknown = event.data.compactionId;\n if (typeof id !== 'string' || id === '') return null;\n return { id, role: event.type === 'compaction/start' ? 'start' : 'update' };\n }\n return null;\n },\n start: () => ({}),\n update: (context, match) => {\n if (match.event.type === 'compaction/summary') return { ...context.state, summary: match };\n if (match.event.type === 'compaction/end') return { ...context.state, end: match };\n if (checkpointCompactionId(match.event) !== undefined)\n return { ...context.state, checkpoint: match };\n return context.state;\n },\n buildViewNode: (context) => {\n const state = context.state ?? fallbackState(context);\n // 替换检查点已到达 → 压缩完成,渲染摘要卡片\n if (state.checkpoint !== undefined) {\n const data = compactSummaryData(state.summary);\n return chatNode(context, COMPACTION_CARD_KIND, state.checkpoint.event.seq, data);\n }\n // end 已到达但无检查点:error 为非中止的实际报错时渲染可见失败行;\n // 无 error 或 error 以 COMPACTION_ABORTED_ERROR 开头(用户中止)时,\n // 以 hidden visibility 撤回进行中提示行\n if (state.end !== undefined) {\n const anchorSeq = context.start?.event.seq ?? state.end.event.seq;\n const endData = state.end.event.data as { error?: unknown } | undefined;\n const isFailure =\n typeof endData?.error === 'string' &&\n endData.error !== '' &&\n !endData.error.startsWith(COMPACTION_ABORTED_ERROR);\n if (isFailure) {\n return chatNode(\n context,\n COMPACTION_CARD_KIND,\n anchorSeq,\n failureData(context.start, state.end),\n );\n }\n return chatNode(\n context,\n COMPACTION_CARD_KIND,\n anchorSeq,\n runningData(context.start),\n 'hidden',\n );\n }\n // start 已到、checkpoint/end 未到 → 压缩进行中,渲染「正在压缩上下文…」提示行\n if (context.start !== undefined) {\n return chatNode(\n context,\n COMPACTION_CARD_KIND,\n context.start.event.seq,\n runningData(context.start),\n );\n }\n return null;\n },\n};\n\n/** 功能降级警告行载荷:降级问题标识与面向用户的说明(信封载荷非法时为 null)。 */\nexport interface OmWarningChatData {\n /** 降级问题标识(om/warning 信封载荷 problem)。 */\n readonly problem: string | null;\n /** 面向用户的降级说明(om/warning 信封载荷 message)。 */\n readonly message: string | null;\n}\n\n/**\n * 插件功能降级警告定义:每条 om/warning 信封事件独立成节点(id 含 seq),渲染为可\n * 展开的「功能降级」警告行。服务端按会话同问题去重后追加,每会话同一问题至多一行;\n * 不带 om 信封的 feedback/record 记录(用户自写反馈)不认领。\n */\nexport const omWarningDefinition: ConversationNodeDefinition = {\n kind: OM_WARNING_CARD_KIND,\n target: 'chat',\n match: (event) => {\n if (readOmEvent(event)?.kind !== 'om/warning') return null;\n return { id: `om-warning:${event.seq}`, role: 'start' };\n },\n start: () => ({}),\n update: (context) => context.state,\n buildViewNode: (context) => {\n const start = context.start;\n if (start === undefined) return null;\n const om = readOmEvent(start.event);\n if (om?.kind !== 'om/warning') return null;\n const problem = om.data.problem !== '' ? om.data.problem : null;\n const message = om.data.message !== '' ? om.data.message : null;\n if (problem === null && message === null) return null;\n return chatNode(context, OM_WARNING_CARD_KIND, start.event.seq, { problem, message });\n },\n};\n","/**\n * `om-compaction` namespace 字典:插件压缩卡片的界面文案(zh/en)。\n * 导出 NS / zh / en;zh 为键集事实源,en 键集与 zh 一致。\n */\n\n/** Dictionary namespace owned by this plugin. */\nexport const NS = 'om-compaction';\n\n/** Simplified Chinese dictionary (the key-set source of truth). */\nexport const zh = {\n compaction: '上下文已压缩',\n 'compaction.completed': '已压缩 {items} 条历史记录(约 {tokens} tokens)',\n 'compaction.stats':\n '{items} 条 · {beforeChars} 字符({beforeTokens} tokens)→ {afterChars} 字符({afterTokens} tokens)',\n 'compaction.expand': '点击查看压缩摘要',\n 'compaction.unavailable': '压缩摘要不可用',\n 'compaction.running': '正在压缩上下文…',\n 'compaction.running.observe': '正在压缩上下文(观察)…',\n 'compaction.running.reflect': '正在压缩上下文(反思)…',\n 'compaction.failed': '上下文压缩失败',\n 'compaction.failed.observe': '上下文压缩失败(观察)',\n 'compaction.failed.reflect': '上下文压缩失败(反思)',\n warning: '上下文压缩功能降级',\n} as const;\n\n/** English dictionary(键集与 zh 一致)。 */\nexport const en: Record<keyof typeof zh, string> = {\n compaction: 'Context compacted',\n 'compaction.completed': 'Compacted {items} messages (~{tokens} tokens)',\n 'compaction.stats':\n '{items} msgs · {beforeChars} chars ({beforeTokens} tokens) → {afterChars} chars ({afterTokens} tokens)',\n 'compaction.expand': 'Click to view summary',\n 'compaction.unavailable': 'Summary unavailable',\n 'compaction.running': 'Compressing context…',\n 'compaction.running.observe': 'Compressing context (observation)…',\n 'compaction.running.reflect': 'Compressing context (reflection)…',\n 'compaction.failed': 'Context compaction failed',\n 'compaction.failed.observe': 'Context compaction failed (observation)',\n 'compaction.failed.reflect': 'Context compaction failed (reflection)',\n warning: 'Context compaction degraded',\n};\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n /** Compaction card copy owned by dsh-plugin-om. */\n 'om-compaction': keyof typeof zh;\n }\n}\n","/**\n * 压缩卡片统计行的紧凑数字格式化。导出 formatCompactCount。\n * <1k 原样;≥1k 用 k;≥1w(万)用 w;≥1M 用 M;保留 1 位小数并去掉末尾 .0。\n */\nexport function formatCompactCount(value: number): string {\n const trim = (n: number): string => {\n const text = String(Math.round(n * 10) / 10);\n return text.endsWith('.0') ? text.slice(0, -2) : text;\n };\n if (value >= 1_000_000) return `${trim(value / 1_000_000)}M`;\n if (value >= 10_000) return `${trim(value / 10_000)}w`;\n if (value >= 1_000) return `${trim(value / 1_000)}k`;\n return String(value);\n}\n","/**\n * 压缩卡片渲染器:与宿主「上下文注入」卡片同款的折叠行。\n * 复用平台原语 DisclosureRow;行内统计与展开体样式按宿主 ContextInjectionRow 的规则\n * 注入 <style>(宿主该卡片样式是编译期哈希的 CSS Module,插件 bundle 无法引用其类名)。\n * 卡片报告模型从何处起不再看到那段历史;summary 留在加载窗口外时行不可展开。\n * 压缩失败节点渲染为可展开的错误行:折叠行显示错误摘要,展开体显示完整报错。\n */\n\nimport type { ChatNode } from '@deepseek-ai/dsh-client-ui-chat/client';\nimport { DisclosureRow, IconBrowseOutline16 } from '@deepseek-ai/dsh-client-ui-primitives';\nimport type { TranslateNS } from '@deepseek-ai/dsh-client-ui-slots';\nimport type { CSSProperties } from 'react';\nimport { memo, useState } from 'react';\nimport { formatCompactCount } from './format.ts';\n\n/** Keyed renderer props: 装配好的卡片节点 + 绑定 `om-compaction` 命名空间的 locale 座。 */\nexport interface OmCompactionCardProps {\n readonly node: ChatNode<'om-compaction'>;\n readonly t: TranslateNS<'om-compaction'>;\n}\n\n/** 卡片样式类名(与宿主 ContextInjectionRow.module.css 同款规则,见下方注册)。 */\nconst css = {\n root: 'om-compaction-root',\n chevron: 'om-compaction-chevron',\n sep: 'om-compaction-sep',\n summary: 'om-compaction-summary',\n body: 'om-compaction-body',\n} as const;\n\n/** 宿主 ContextInjectionRow.module.css 的规则(逐字一致,仅类名按插件前缀)。 */\nconst cardCss = `\n.${css.root}{min-width:0}\n.${css.root}[data-open]{padding-bottom:4px}\n.${css.chevron}{color:var(--dsw-alias-label-secondary)}\n.${css.sep}{background:var(--dsw-alias-label-caption);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}\n.${css.summary}{min-width:0;color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;flex:auto;font-size:14px;line-height:24px;overflow:hidden}\n.${css.body}{box-sizing:border-box;background:var(--dsw-alias-markdown-code-block);width:calc(100% - 22px);max-height:141px;color:var(--dsw-alias-label-tertiary);font:400 11px/16px var(--ds-font-family-code);border:none;border-radius:8px;margin:4px 0 0 22px;padding:10px 16px 12px 12px;overflow:auto}\n`;\n\n/** 注册卡片样式(无 document 的环境如 node 测试直接跳过)。 */\nif (\n typeof document !== 'undefined' &&\n document.querySelector('style[data-dsh-plugin-om-card]') === null\n) {\n const tag = document.createElement('style');\n tag.dataset.dshPluginOmCard = 'true';\n tag.textContent = cardCss;\n document.head.appendChild(tag);\n}\n\n/** 折叠式压缩卡片(统计标题行 + 代码块样式 summary 展开)。 */\nexport const OmCompactionCard = memo(function OmCompactionCard({ node, t }: OmCompactionCardProps) {\n const [expanded, setExpanded] = useState(false);\n const { data } = node;\n // 压缩进行中:不可展开的「正在压缩上下文…」提示行(按 phase 区分文案)\n if (data.running) {\n const runningLabel =\n data.phase === 'observe'\n ? t('compaction.running.observe')\n : data.phase === 'reflect'\n ? t('compaction.running.reflect')\n : t('compaction.running');\n return (\n <div style={styles.row}>\n <DisclosureRow\n className={css.root}\n icon={<IconBrowseOutline16 size={14} />}\n title={runningLabel}\n open={false}\n expandable={false}\n onToggle={() => {\n /* 进行中提示行不可展开 */\n }}\n />\n </div>\n );\n }\n // 压缩失败:可展开的错误行(按 phase 区分文案),折叠行为错误摘要、展开体为完整报错\n if (data.error !== null) {\n const failedLabel =\n data.phase === 'observe'\n ? t('compaction.failed.observe')\n : data.phase === 'reflect'\n ? t('compaction.failed.reflect')\n : t('compaction.failed');\n const errorSummary = data.error.length > 80 ? `${data.error.slice(0, 80)}…` : data.error;\n return (\n <div style={styles.row}>\n <DisclosureRow\n className={css.root}\n icon={<IconBrowseOutline16 size={14} />}\n chevronClassName={css.chevron}\n title={failedLabel}\n collapsedContent={\n <>\n <span className={css.sep} aria-hidden />\n <span className={css.summary}>{errorSummary}</span>\n </>\n }\n keepContentWhenOpen\n expandable\n expandOnRowClick\n open={expanded}\n onToggle={() => {\n setExpanded((value) => !value);\n }}\n >\n <div className={css.body} style={styles.body}>\n {data.error}\n </div>\n </DisclosureRow>\n </div>\n );\n }\n const expandable = data.summary !== null;\n const open = expandable && expanded;\n // 统计行:优先完整压缩前后统计,载荷字段不全时逐级回落\n const stats =\n data.shadowedItemCount !== null &&\n data.shadowedCharCount !== null &&\n data.shadowedTokenCount !== null &&\n data.summaryCharCount !== null &&\n data.summaryTokenCount !== null\n ? t('compaction.stats', {\n items: formatCompactCount(data.shadowedItemCount),\n beforeChars: formatCompactCount(data.shadowedCharCount),\n beforeTokens: formatCompactCount(data.shadowedTokenCount),\n afterChars: formatCompactCount(data.summaryCharCount),\n afterTokens: formatCompactCount(data.summaryTokenCount),\n })\n : data.shadowedItemCount !== null && data.shadowedTokenCount !== null\n ? t('compaction.completed', {\n items: formatCompactCount(data.shadowedItemCount),\n tokens: formatCompactCount(data.shadowedTokenCount),\n })\n : expandable\n ? t('compaction.expand')\n : t('compaction.unavailable');\n return (\n <div style={styles.row}>\n <DisclosureRow\n className={css.root}\n icon={<IconBrowseOutline16 size={14} />}\n chevronClassName={css.chevron}\n title={t('compaction')}\n collapsedContent={\n <>\n <span className={css.sep} aria-hidden />\n <span className={css.summary} data-om-compaction-summary>\n {stats}\n </span>\n </>\n }\n keepContentWhenOpen\n expandable={expandable}\n expandOnRowClick\n open={open}\n onToggle={() => {\n setExpanded((value) => !value);\n }}\n >\n {data.summary !== null && (\n <div className={css.body} style={styles.body}>\n {data.summary}\n </div>\n )}\n </DisclosureRow>\n </div>\n );\n});\n\nconst styles: Record<string, CSSProperties> = {\n row: {},\n /** 摘要与失败报错为多行文本,保留换行。 */\n body: { whiteSpace: 'pre-wrap' },\n};\n","/**\n * 功能降级警告行渲染器:与压缩卡片同款的折叠行。\n * 折叠行显示降级说明摘要,展开体显示完整说明;数据来自 om/warning 信封载荷\n * (借用 feedback/record),服务端按会话同问题去重后追加(每会话同一问题至多一行)。\n */\n\nimport type { ChatNode } from '@deepseek-ai/dsh-client-ui-chat/client';\nimport { DisclosureRow, IconBrowseOutline16 } from '@deepseek-ai/dsh-client-ui-primitives';\nimport type { TranslateNS } from '@deepseek-ai/dsh-client-ui-slots';\nimport type { CSSProperties } from 'react';\nimport { memo, useState } from 'react';\n\n/** Keyed renderer props: 装配好的警告行节点 + 绑定 `om-compaction` 命名空间的 locale 座。 */\nexport interface OmWarningCardProps {\n readonly node: ChatNode<'om-warning'>;\n readonly t: TranslateNS<'om-compaction'>;\n}\n\n/** 折叠式功能降级警告行(降级说明摘要行 + 完整说明展开)。 */\nexport const OmWarningCard = memo(function OmWarningCard({ node, t }: OmWarningCardProps) {\n const [expanded, setExpanded] = useState(false);\n const { data } = node;\n const message = data.message ?? (data.problem !== null ? data.problem : '');\n const expandable = message !== '';\n const messageSummary = message.length > 80 ? `${message.slice(0, 80)}…` : message;\n return (\n <div>\n <DisclosureRow\n className=\"om-compaction-root\"\n icon={<IconBrowseOutline16 size={14} />}\n chevronClassName=\"om-compaction-chevron\"\n title={t('warning')}\n collapsedContent={\n expandable ? (\n <>\n <span className=\"om-compaction-sep\" aria-hidden />\n <span className=\"om-compaction-summary\">{messageSummary}</span>\n </>\n ) : undefined\n }\n keepContentWhenOpen\n expandable={expandable}\n expandOnRowClick\n open={expandable && expanded}\n onToggle={() => {\n if (expandable) setExpanded((value) => !value);\n }}\n >\n {expandable && (\n <div className=\"om-compaction-body\" style={bodyStyle}>\n {message}\n </div>\n )}\n </DisclosureRow>\n </div>\n );\n});\n\nconst bodyStyle: CSSProperties = { whiteSpace: 'pre-wrap' };\n","/**\n * 浏览器客户端入口(exports[\"./client\"] → dist/client.js):注册压缩卡片与功能降级\n * 警告行的 locale 字典、conversation 业务定义与 keyed 渲染器。宿主 conversation UI 只\n * 识别内置 'compact' 检查点,插件自产的压缩检查点(source.plugin = 'dsh-plugin-om')\n * 由本 bundle 认领并在消息列表渲染「已压缩」卡片;om 警告信封事件(借用\n * feedback/record)渲染为「功能降级」警告行。\n */\nimport type { Context } from '@deepseek-ai/cordis';\n// Type-only: 拉取 locale 插件的 Context 合并(ctx.locale)。\nimport type {} from '@deepseek-ai/dsh-client-locale/client';\n// Type-only: 拉取 uiConversation 服务与 ChatNodeDataMap 的类型合并。\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client';\n// Type-only: 拉取 slots 服务的 Context 合并(ctx.slots)。\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client';\nimport { omCompactionDefinition, omWarningDefinition } from './definition.ts';\nimport { en, NS, zh } from './locales.ts';\nimport { OmCompactionCard } from './OmCompactionCard.tsx';\nimport { OmWarningCard } from './OmWarningCard.tsx';\n\n/** Required services: 聊天节点槽、uiConversation 会话定义注册表与 locale 服务。 */\nexport const inject = ['slots', 'uiConversation', 'locale'];\n\n/** Client plugin body: 注册压缩卡片的业务定义与 keyed 渲染器(随插件卸载移除)。 */\nexport function apply(ctx: Context): void {\n ctx.effect(\n () => ctx.locale.register(NS, { zh, en }),\n 'dsh-plugin-om: compaction card dictionaries',\n );\n ctx.effect(\n () => ctx.uiConversation.events.register(omCompactionDefinition),\n 'dsh-plugin-om: compaction definition',\n );\n ctx.effect(\n () => ctx.uiConversation.events.register(omWarningDefinition),\n 'dsh-plugin-om: om warning definition',\n );\n ctx.slots.inject('conversation.chat.node', () =>\n ctx.slots.register(\n { name: 'conversation.chat.node', key: 'om-compaction', locale: NS },\n OmCompactionCard,\n ),\n );\n ctx.slots.inject('conversation.chat.node', () =>\n ctx.slots.register(\n { name: 'conversation.chat.node', key: 'om-warning', locale: NS },\n OmWarningCard,\n ),\n );\n}\n"],"mappings":"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"}
@@ -18,13 +18,14 @@
18
18
  * - 成功与失败均把循环消息组原样落盘为子会话(recordCompressionSession),成功记
19
19
  * 录 sessionId 于日志,失败记录作为诊断子会话 id 向上传播
20
20
  */
21
- import { type TokenUsage } from '@deepseek-ai/dsh-llm';
21
+ import { type ReasoningEffortId, type TokenUsage } from '@deepseek-ai/dsh-llm';
22
22
  import type { CompressionView } from './compress-view.ts';
23
23
  import type { Context, Session } from './types.ts';
24
24
  import { type RoutedTarget } from './utils.ts';
25
25
  /**
26
- * 共享压缩提示词(观察/反思同一套):完整消息定义、工具语义、压缩要求、skill 规则
27
- * 与提交方式。作为压缩会话的 system;skipReasoning=true 时省略 <reasoning> 说明行。
26
+ * 共享压缩提示词(观察/反思同一套):完整消息定义、工具语义、压缩要求、skill 与
27
+ * ask_user_question 规则、提交方式。作为压缩会话的 system;skipReasoning=true 时
28
+ * 省略 <reasoning> 说明行。
28
29
  */
29
30
  export declare function buildCompressionPrompt(skipReasoning: boolean): string;
30
31
  /**
@@ -73,6 +74,8 @@ export type CompressionLoopOptions = {
73
74
  skipReasoning: boolean;
74
75
  /** 步骤级日志开关。 */
75
76
  debug: boolean;
77
+ /** 压缩请求的思考等级(已按目标模型校验);undefined 用模型默认。 */
78
+ reasoningEffort?: ReasoningEffortId;
76
79
  /** 取消信号。 */
77
80
  signal?: AbortSignal;
78
81
  };
@@ -1 +1 @@
1
- {"version":3,"file":"compress-loop.d.ts","sourceRoot":"","sources":["../src/compress-loop.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"compress-loop.d.ts","sourceRoot":"","sources":["../src/compress-loop.ts"],"names":[],"mappings":"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"}
@@ -9,14 +9,17 @@
9
9
  * content 摘要(纯文本,构建最终块时以 CDATA 包裹嵌入;含 CDATA 包裹时拒绝)。参数非法 / 越界 / 覆盖用户或
10
10
  * 系统消息 / 与条目或已有替换区间部分重叠 → 返回错误结果(模型可修正重试);
11
11
  * 重复覆盖同一区间:新区间完全包含旧区间时覆盖,部分重叠时报错
12
- * - skill 规则:区间覆盖工具名为 skill 的 toolcall 条目时,该 skill 块首次被覆盖
13
- * 不执行、返回要求重新思考的提示;之后再次覆盖它的调用直接执行
12
+ * - skill / ask_user_question 规则:区间覆盖工具名为 skill(skill 加载)或
13
+ * ask_user_question(向用户的提问)的条目时,该条目首次被覆盖不执行、返回要求
14
+ * 重新思考的提示;之后再次覆盖它的调用直接执行
14
15
  * - completeCompression:标记完成(调用后压缩会话立即停止);空提交(0 次成功
15
16
  * 压缩)允许
16
17
  * - 最终 <history> 块由插件从视图与替换记录构建:user / sys 条目原样、被替换区间
17
18
  * 生成新摘要条目、未替换 assistant 条目原样保留(toolcall 条目以
18
19
  * <assistant type="toolcall"> 结构呈现,内含 <tool-args> / <tool-result> 两个
19
- * CDATA 子元素)、reasoning 不进产物;产物天然合法 XML,无需校验
20
+ * CDATA 子元素;skill 条目以 <skill_content> 元素呈现,ask_user_question 条目以
21
+ * <ask-user-question> 元素呈现,旧格式 <askuserquestion> 条目原样保留)、reasoning
22
+ * 不进产物;块首为按产物内实际条目动态生成的格式说明注释。产物天然合法 XML,无需校验
20
23
  */
21
24
  import type { ToolSchema } from '@deepseek-ai/dsh-llm';
22
25
  import { type CompressionView } from './compress-view.ts';
@@ -29,7 +32,7 @@ export type ToolCallResult = {
29
32
  /** 是否为错误结果(未执行 / 参数非法)。 */
30
33
  isError: boolean;
31
34
  };
32
- /** 压缩会话的工具状态:视图 + 替换记录 + skill 二次确认标记 + 完成标记。 */
35
+ /** 压缩会话的工具状态:视图 + 替换记录 + 二次确认标记(skill / ask_user_question)+ 完成标记。 */
33
36
  export declare class CompressionState {
34
37
  private readonly view;
35
38
  private readonly replacements;
@@ -60,9 +63,9 @@ export declare class CompressionState {
60
63
  private static spanLabel;
61
64
  /**
62
65
  * compressHistory:把 index 单条或 start..end 连续区间的 assistant 条目替换为
63
- * content 摘要。校验失败返回错误结果(不应用);skill 块首次被覆盖返回要求
64
- * 重新思考的错误结果(不应用,标记已挑战);通过后记录替换并覆盖被完全包含
65
- * 的旧替换。
66
+ * content 摘要。校验失败返回错误结果(不应用);skill / ask_user_question 条目
67
+ * 首次被覆盖返回要求重新思考的错误结果(不应用,标记已挑战);通过后记录替换并
68
+ * 覆盖被完全包含的旧替换。
66
69
  */
67
70
  compressHistory(args: Record<string, unknown>): ToolCallResult;
68
71
  /** completeCompression:标记压缩完成(调用后压缩会话立即停止)。 */
@@ -70,8 +73,9 @@ export declare class CompressionState {
70
73
  /**
71
74
  * 构建最终 <history> 块:按 index 顺序合并视图条目与替换记录——user / sys 条目
72
75
  * 原样、被替换区间生成 <assistant index|start end> 摘要条目(content 以 CDATA 包裹嵌入)、
73
- * 未替换 assistant 条目原样保留、reasoning 不进产物;块首为格式说明注释,开标签
74
- * 携带 tip 属性。产物为合法 XML,无需校验。
76
+ * 未替换 assistant 条目原样保留、reasoning 不进产物;块首为按产物内实际条目动态
77
+ * 生成的格式说明注释(user_message / sys / skill_content / ask-user-question 条目说明
78
+ * 仅在对应条目存在时包含),开标签携带 tip 属性。产物为合法 XML,无需校验。
75
79
  */
76
80
  buildFinalBlock(): string;
77
81
  }
@@ -1 +1 @@
1
- {"version":3,"file":"compress-tools.d.ts","sourceRoot":"","sources":["../src/compress-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,EAEL,KAAK,eAAe,EAIrB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAiD,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEhG,OAAO,EAAE,eAAe,EAAE,CAAC;AAE3B,0CAA0C;AAC1C,MAAM,MAAM,cAAc,GAAG;IAC3B,gBAAgB;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,2BAA2B;IAC3B,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAYF,iDAAiD;AACjD,qBAAa,gBAAgB;IAQf,OAAO,CAAC,QAAQ,CAAC,IAAI;IAPjC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAqB;IAClD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAqB;IACtD,OAAO,CAAC,UAAU,CAAS;IAE3B;;OAEG;gBAC0B,IAAI,EAAE,eAAe;IAElD,2BAA2B;IAC3B,IAAI,gBAAgB,IAAI,MAAM,CAE7B;IAED,iCAAiC;IACjC,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED;;;OAGG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,cAAc;IAuB1D,yCAAyC;IACzC,OAAO,CAAC,cAAc;IAMtB;;;;OAIG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,cAAc;IA8CzD,yCAAyC;IACzC,OAAO,CAAC,MAAM,CAAC,SAAS;IAIxB;;;;;OAKG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,cAAc;IA+H9D,+CAA+C;IAC/C,QAAQ,IAAI,cAAc;IAK1B;;;;;OAKG;IACH,eAAe,IAAI,MAAM;CAmD1B;AAED,8CAA8C;AAC9C,eAAO,MAAM,wBAAwB,EAAE,UAAU,EAqChD,CAAC"}
1
+ {"version":3,"file":"compress-tools.d.ts","sourceRoot":"","sources":["../src/compress-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,EAEL,KAAK,eAAe,EAIrB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAKL,eAAe,EAChB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,eAAe,EAAE,CAAC;AAE3B,0CAA0C;AAC1C,MAAM,MAAM,cAAc,GAAG;IAC3B,gBAAgB;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,2BAA2B;IAC3B,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAYF,qEAAqE;AACrE,qBAAa,gBAAgB;IAQf,OAAO,CAAC,QAAQ,CAAC,IAAI;IAPjC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAqB;IAClD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAqB;IACtD,OAAO,CAAC,UAAU,CAAS;IAE3B;;OAEG;gBAC0B,IAAI,EAAE,eAAe;IAElD,2BAA2B;IAC3B,IAAI,gBAAgB,IAAI,MAAM,CAE7B;IAED,iCAAiC;IACjC,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED;;;OAGG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,cAAc;IAuB1D,yCAAyC;IACzC,OAAO,CAAC,cAAc;IAMtB;;;;OAIG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,cAAc;IA8CzD,yCAAyC;IACzC,OAAO,CAAC,MAAM,CAAC,SAAS;IAIxB;;;;;OAKG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,cAAc;IA2I9D,+CAA+C;IAC/C,QAAQ,IAAI,cAAc;IAK1B;;;;;;OAMG;IACH,eAAe,IAAI,MAAM;CAgE1B;AAED,8CAA8C;AAC9C,eAAO,MAAM,wBAAwB,EAAE,UAAU,EAqChD,CAAC"}
@@ -28,7 +28,7 @@ export type ViewEntry = {
28
28
  notes?: string[];
29
29
  /** sys 条目的 source.kind。 */
30
30
  sysKind?: string;
31
- /** 观察视图 toolcall 条目的工具名(skill 判定用;结构化渲染为 tool-name 属性)。 */
31
+ /** 观察视图 toolcall 条目的工具名(skill / ask_user_question 判定用;结构化渲染为 tool-name 属性)。 */
32
32
  toolName?: string;
33
33
  /** skill 条目的 skill 名(toolName 为 skill 时存在;反思视图取自 name 属性,缺失为空串)。 */
34
34
  skillName?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"compress-view.d.ts","sourceRoot":"","sources":["../src/compress-view.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAUxD,OAAO,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAG3D;;;;;;GAMG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB,YAAY;IACZ,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,WAAW,GAAG,WAAW,CAAC;IACjD,6CAA6C;IAC7C,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,0CAA0C;IAC1C,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,2CAA2C;IAC3C,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,2BAA2B;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uDAAuD;IACvD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iCAAiC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,mEAAmE;AACnE,MAAM,MAAM,eAAe,GAAG;IAC5B,uDAAuD;IACvD,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAyCF;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,eAAe,GAAG,MAAM,GAAG,SAAS,CAaxF;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,eAAe,GAAG,MAAM,GAAG,SAAS,CAmBrF;AAED,sDAAsD;AACtD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,+BAA+B;IAC/B,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,GAAE,gBAAqB,GAC7B,eAAe,CAiFjB;AAiBD,0CAA0C;AAC1C,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASjD;AAyCD;;GAEG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAyG7C;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,EAC5C,OAAO,GAAE,gBAAqB,GAC7B,eAAe,CAUjB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,GAAG,OAAO,CA+EvE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,MAAM,CAO7D"}
1
+ {"version":3,"file":"compress-view.d.ts","sourceRoot":"","sources":["../src/compress-view.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAUxD,OAAO,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAG3D;;;;;;GAMG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB,YAAY;IACZ,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,WAAW,GAAG,WAAW,CAAC;IACjD,6CAA6C;IAC7C,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,0CAA0C;IAC1C,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,2CAA2C;IAC3C,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,2BAA2B;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uDAAuD;IACvD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iCAAiC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,mEAAmE;AACnE,MAAM,MAAM,eAAe,GAAG;IAC5B,uDAAuD;IACvD,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAyCF;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,eAAe,GAAG,MAAM,GAAG,SAAS,CAaxF;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,eAAe,GAAG,MAAM,GAAG,SAAS,CAmBrF;AA+CD,sDAAsD;AACtD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,+BAA+B;IAC/B,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,GAAE,gBAAqB,GAC7B,eAAe,CAyFjB;AAiBD,0CAA0C;AAC1C,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASjD;AAoFD;;GAEG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAgJ7C;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,EAC5C,OAAO,GAAE,gBAAqB,GAC7B,eAAe,CAUjB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,GAAG,OAAO,CAwHvE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,MAAM,CAO7D"}
@@ -1,3 +1,43 @@
1
+ /**
2
+ * 两级自动压缩(观察/反思)与 compaction 生命周期提交。
3
+ * 导出 estimateTextTokens / isPairBalancedAfter / computeCompressRange / historySection /
4
+ * findObservePending / reflectPass / observePass / maybeCompress。
5
+ *
6
+ * - 摘要生成走工具驱动的压缩循环(compress-loop.ts runCompressionLoop):首条 user
7
+ * 消息仅含压缩指令与 start/end 区间,模型经 getHistory / compressHistory /
8
+ * completeCompression 工具完成压缩;最终 <history> 块由插件从视图与替换记录构建,
9
+ * 全程无需整块校验
10
+ * - 反思:全部 <history> 块 token 合计 ≥ reflectThresholdTokens 时,把全部块条目作为
11
+ * 压缩视图重新压缩合并(视图无条目时跳过,如全部为不可解析的历史遗留块)
12
+ * - 观察(触发 → 待定 → 延迟执行):净压力(上下文压力 − 已压缩块 token 合计 − 系统提示词
13
+ * token 估算 − 工具定义 token 估算)首次 ≥ observeThresholdTokens 时记录待定标记
14
+ * (触发点 = 当时的最后一条完整消息 index),本次不压缩;待定后新增完整消息数 ≥
15
+ * tailMessageCount 时,把压缩边界至触发点的全部消息作为压缩视图替换为新 <history>
16
+ * 块(旧块保留),等待期间的新消息成为下一轮未压缩尾部(延迟窗口内压力允许
17
+ * 短暂超阈值);tailMessageCount=0 时触发当轮直接执行(不落待定标记)
18
+ * - 待定标记以 log-only om 信封事件(借用 feedback/record,kind 为 om/observe-pending /
19
+ * om/observe-invalidate,见 om-event.ts)持久化在会话日志中(重启后从日志恢复);
20
+ * 压缩失败保留待定,下个 pre-step 直接重试执行
21
+ * - 两级在 pre-step 阻塞串行执行(先反思后观察);仅主会话生效;omEnabled=false 关闭
22
+ * - 压缩目标默认跟随会话路由;compressProvider + compressModel 成对配置时覆盖路由
23
+ * (成对配置下未路由会话也执行压缩);compressReasoningEffort 配置时压缩前经
24
+ * ctx.llm.resolveModelInfo 校验目标模型 reasoning.efforts(按 provider+model 缓存),
25
+ * 未命中 / 无元数据 / 查询失败降级为模型默认并报告 reasoning-effort-unavailable 降级
26
+ * - 压缩边界:最后一个合法 <history> 块之后的消息视为未压缩,其前不重复压缩
27
+ * - 压缩循环最终失败(连续无工具调用 / 请求级错误)时 pass 返回失败结果(携带最后一次
28
+ * 错误),压缩流程向上传播,pre-step 据此拒绝本 step 中断当前 turn;signal 中止标记
29
+ * aborted(不中断);成功与失败均落盘压缩会话记录子会话(失败时其 id 随结果传播为
30
+ * 诊断子会话 id)
31
+ * - 提交走宿主 compaction/* 生命周期事件(start 带 phase → summary → 替换消息 → end),
32
+ * 失败补 end(error,实际报错 + 诊断子会话 sessionId);替换消息 source 标记插件标识供 UI 认领
33
+ * - 挂载失败类问题(systemPrompt/tokenMeter 服务异常)始终 console 到外部进程,并追加
34
+ * log-only om 警告事件(借用 feedback/record,客户端渲染功能降级警告行,每会话同一
35
+ * 问题至多一次);
36
+ * 辅助估算的普通运行时报错仅记日志。降级与报错都不阻塞压缩(tokenMeter 压力数据
37
+ * 缺失时本轮跳过观察)
38
+ */
39
+ import type { ReasoningEffortId } from '@deepseek-ai/dsh-llm';
40
+ import type { PluginLogger } from './logger.ts';
1
41
  import type { Agent, Context, PluginConfig, Session } from './types.ts';
2
42
  import { type RoutedTarget } from './utils.ts';
3
43
  /**
@@ -15,6 +55,22 @@ export type CompressPassResult = {
15
55
  };
16
56
  /** 历史文本 token 估算:4 字符 ≈ 1 token(与宿主 dsh-token-meter 启发式一致)。 */
17
57
  export declare function estimateTextTokens(text: string): number;
58
+ /**
59
+ * 压缩目标解析:compressProvider + compressModel 成对配置时覆盖会话路由;仅配置单键或
60
+ * 未配置时回落 routedTarget(会话未路由返回 undefined,压缩跳过——成对覆盖配置下
61
+ * 未路由会话仍可压缩)。
62
+ */
63
+ export declare function compressionTarget(config: Readonly<PluginConfig>, session: Session): RoutedTarget | undefined;
64
+ /** 清空压缩思考等级校验缓存(按目标缓存 resolveModelInfo 查询结果;测试隔离用)。 */
65
+ export declare function clearCompressionModelInfoCache(): void;
66
+ /**
67
+ * 校验配置的 compressReasoningEffort 并解析为压缩请求的思考等级:未配置返回 undefined
68
+ * (用模型默认,不查询模型信息);命中目标模型 reasoning.efforts 返回等级 id;
69
+ * 不在可选等级 / 模型无 reasoning 元数据 / 查询抛错时返回 undefined 并报告
70
+ * reasoning-effort-unavailable 降级。结果按 provider+model 缓存(含降级结果),避免
71
+ * 每个 pre-step 重复查询。
72
+ */
73
+ export declare function resolveCompressionEffort(ctx: Context, session: Session, config: Readonly<PluginConfig>, target: RoutedTarget, logger: PluginLogger): Promise<ReasoningEffortId | undefined>;
18
74
  /**
19
75
  * 判定表层节点 seq 之后的切点是否 tool-call/result 配对平衡:按表层顺序折叠未闭合的
20
76
  * 工具调用数,处理到 seq 后计数为 0 即平衡(防止把 tool-call 与其结果切到两侧)。
@@ -60,7 +116,7 @@ export declare function findObservePending(session: Session): {
60
116
  * 为不可解析的历史遗留块)时跳过。失败不产生部分替换;最终失败返回失败结果
61
117
  * (error = 最后一次错误)。
62
118
  */
63
- export declare function reflectPass(ctx: Context, agent: Agent, config: Readonly<PluginConfig>, target: RoutedTarget, signal?: AbortSignal): Promise<CompressPassResult>;
119
+ export declare function reflectPass(ctx: Context, agent: Agent, config: Readonly<PluginConfig>, target: RoutedTarget, signal?: AbortSignal, reasoningEffort?: ReasoningEffortId): Promise<CompressPassResult>;
64
120
  /**
65
121
  * 观察(触发 → 待定 → 延迟执行):无活跃待定标记时测净压力 tokens(上下文压力 − 已压缩
66
122
  * <history> 块 token 合计 − 系统提示词 token 估算 − 工具定义 token 估算),首次 ≥
@@ -71,7 +127,7 @@ export declare function reflectPass(ctx: Context, agent: Agent, config: Readonly
71
127
  * 失败保留待定,下个 pre-step 直接重试执行。最终失败返回失败结果
72
128
  * (error = 最后一次错误)。
73
129
  */
74
- export declare function observePass(ctx: Context, agent: Agent, config: Readonly<PluginConfig>, waitCount: number, target: RoutedTarget, signal?: AbortSignal): Promise<CompressPassResult>;
130
+ export declare function observePass(ctx: Context, agent: Agent, config: Readonly<PluginConfig>, waitCount: number, target: RoutedTarget, signal?: AbortSignal, reasoningEffort?: ReasoningEffortId): Promise<CompressPassResult>;
75
131
  /**
76
132
  * 压力检查 + 两级压缩入口:先反思后观察,pre-step 阻塞串行执行;仅主会话生效。
77
133
  * 反思摘要耗尽失败时直接返回失败结果(观察无需继续,本轮将被拒绝);观察失败同样
@@ -1 +1 @@
1
- {"version":3,"file":"compress.d.ts","sourceRoot":"","sources":["../src/compress.ts"],"names":[],"mappings":"AAoDA,OAAO,KAAK,EACV,KAAK,EAKL,OAAO,EACP,YAAY,EACZ,OAAO,EAIR,MAAM,YAAY,CAAC;AACpB,OAAO,EAAgB,KAAK,YAAY,EAAqC,MAAM,YAAY,CAAC;AAEhG;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAC1B;IAAE,MAAM,EAAE,KAAK,CAAA;CAAE,GACjB;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpF,+DAA+D;AAC/D,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvD;AAmED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAY1E;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,OAAO,EAChB,eAAe,EAAE,MAAM,GACtB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,SAAS,CA+BpE;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG;IAChD,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC7C,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;CACjC,CAUA;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,OAAO,GACf;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,mBAAmB,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAoB1D;AA0ID;;;;;GAKG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,QAAQ,CAAC,YAAY,CAAC,EAC9B,MAAM,EAAE,YAAY,EACpB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,kBAAkB,CAAC,CAuH7B;AAwED;;;;;;;;;GASG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,QAAQ,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,YAAY,EACpB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,kBAAkB,CAAC,CAgO7B;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,QAAQ,CAAC,YAAY,CAAC,EAC9B,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,kBAAkB,CAAC,CAwB7B"}
1
+ {"version":3,"file":"compress.d.ts","sourceRoot":"","sources":["../src/compress.ts"],"names":[],"mappings":"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"}
package/dist/config.d.ts CHANGED
@@ -22,6 +22,12 @@ export type PluginConfig = {
22
22
  semanticRecallEnabled: boolean;
23
23
  /** 语义召回嵌入模型目录。 */
24
24
  modelDir: string;
25
+ /** 压缩请求覆盖的 provider(与 compressModel 成对生效,任一缺失回落会话路由)。 */
26
+ compressProvider: string | undefined;
27
+ /** 压缩请求覆盖的 model(与 compressProvider 成对生效,任一缺失回落会话路由)。 */
28
+ compressModel: string | undefined;
29
+ /** 压缩请求的思考等级(配置值不被目标模型支持时降级为模型默认并告警)。 */
30
+ compressReasoningEffort: string | undefined;
25
31
  };
26
32
  /** 默认配置(冻结对象,resolveConfig 合并的基底;debug 缺省值在解析时按 NODE_ENV 判定)。 */
27
33
  export declare const DEFAULT_CONFIG: Readonly<PluginConfig>;
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAQA,kCAAkC;AAClC,MAAM,MAAM,YAAY,GAAG;IACzB,oCAAoC;IACpC,sBAAsB,EAAE,MAAM,CAAC;IAC/B,wDAAwD;IACxD,sBAAsB,EAAE,MAAM,CAAC;IAC/B,2DAA2D;IAC3D,iBAAiB,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,sCAAsC;IACtC,eAAe,EAAE,MAAM,CAAC;IACxB,yDAAyD;IACzD,gBAAgB,EAAE,MAAM,CAAC;IACzB,oEAAoE;IACpE,qBAAqB,EAAE,OAAO,CAAC;IAC/B,uBAAuB;IACvB,SAAS,EAAE,OAAO,CAAC;IACnB,iDAAiD;IACjD,KAAK,EAAE,OAAO,CAAC;IACf,sBAAsB;IACtB,aAAa,EAAE,OAAO,CAAC;IACvB,+CAA+C;IAC/C,qBAAqB,EAAE,OAAO,CAAC;IAC/B,kBAAkB;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,iEAAiE;AACjE,eAAO,MAAM,cAAc,EAAE,QAAQ,CAAC,YAAY,CAYhD,CAAC;AAmCH,wCAAwC;AACxC,wBAAgB,aAAa,CAAC,GAAG,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC,YAAY,CAAC,CAqBnE"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAQA,kCAAkC;AAClC,MAAM,MAAM,YAAY,GAAG;IACzB,oCAAoC;IACpC,sBAAsB,EAAE,MAAM,CAAC;IAC/B,wDAAwD;IACxD,sBAAsB,EAAE,MAAM,CAAC;IAC/B,2DAA2D;IAC3D,iBAAiB,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,sCAAsC;IACtC,eAAe,EAAE,MAAM,CAAC;IACxB,yDAAyD;IACzD,gBAAgB,EAAE,MAAM,CAAC;IACzB,oEAAoE;IACpE,qBAAqB,EAAE,OAAO,CAAC;IAC/B,uBAAuB;IACvB,SAAS,EAAE,OAAO,CAAC;IACnB,iDAAiD;IACjD,KAAK,EAAE,OAAO,CAAC;IACf,sBAAsB;IACtB,aAAa,EAAE,OAAO,CAAC;IACvB,+CAA+C;IAC/C,qBAAqB,EAAE,OAAO,CAAC;IAC/B,kBAAkB;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,yDAAyD;IACzD,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,yCAAyC;IACzC,uBAAuB,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7C,CAAC;AAEF,iEAAiE;AACjE,eAAO,MAAM,cAAc,EAAE,QAAQ,CAAC,YAAY,CAehD,CAAC;AAyCH,wCAAwC;AACxC,wBAAgB,aAAa,CAAC,GAAG,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC,YAAY,CAAC,CAwBnE"}
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * 共享常量:插件级魔法字符串,集中定义避免散落各模块。
3
3
  * 导出 PLUGIN_LABEL / HISTORY_TAG / HISTORY_TIP / COMPLETE_MESSAGE_DEFINITION /
4
- * HISTORY_FORMAT_NOTE / SKILL_TOOL_NAME / COMPACT_CHECKPOINT_PLUGIN /
5
- * COMPACTION_ABORTED_ERROR / isPluginOwnedSource。
4
+ * historyFormatNote / SKILL_TOOL_NAME / ASK_USER_QUESTION_TOOL_NAME /
5
+ * COMPACT_CHECKPOINT_PLUGIN / COMPACTION_ABORTED_ERROR / isPluginOwnedSource。
6
6
  */
7
7
  /** 插件标识:压缩消息 source.plugin 取值与日志前缀。 */
8
8
  export declare const PLUGIN_LABEL = "dsh-plugin-om";
@@ -15,12 +15,30 @@ export declare const HISTORY_TIP = "\u5F53\u524D\u5757\u662F\u5386\u53F2\u6D88\u
15
15
  * 完整消息是摘要日志与 recall 共用的定位单位;首条 index 为 0,按会话顺序递增、全局稳定。
16
16
  */
17
17
  export declare const COMPLETE_MESSAGE_DEFINITION = "`\u5B8C\u6574\u6D88\u606F`\u6307\u4E00\u6761`\u7528\u6237\u6D88\u606F`\u3001`\u7CFB\u7EDF\u6D88\u606F`\u3001`\u6A21\u578B\u8F93\u51FA\u6587\u672C`\u6216`\u5177\u6709result\u7684toolcall`\uFF1B\u9996\u6761 index \u4E3A 0\uFF0C\u6309\u4F1A\u8BDD\u987A\u5E8F\u9012\u589E\u3002";
18
+ /** 块顶格式说明注释中按块内条目动态追加的分段开关。 */
19
+ export type HistoryNoteSections = {
20
+ /** 块内存在 user 条目时追加 <user_message> 说明。 */
21
+ user?: boolean;
22
+ /** 块内存在 sys 条目时追加 <sys> 说明。 */
23
+ sys?: boolean;
24
+ /** 块内存在未压缩 skill 条目时追加 <skill_content> 说明。 */
25
+ skill?: boolean;
26
+ /** 块内存在 ask_user_question 条目时追加 <ask-user-question> 说明。 */
27
+ askUserQuestion?: boolean;
28
+ };
18
29
  /**
19
- * 最终 <history> 块内文块首的格式说明注释(XML 注释,完整消息定义 + 条目标签语义 + CDATA 约定)。
30
+ * 最终 <history> 块内文块首的格式说明注释(XML 注释)。通用部分(完整消息定义 +
31
+ * 条目标签语义 + CDATA 约定 + toolcall 结构)始终保留;<user_message> / <sys> /
32
+ * <skill_content> / <ask-user-question> 的条目说明仅在块内存在对应条目时追加。
20
33
  */
21
- export declare const HISTORY_FORMAT_NOTE = "<!-- `\u5B8C\u6574\u6D88\u606F`\u6307\u4E00\u6761`\u7528\u6237\u6D88\u606F`\u3001`\u7CFB\u7EDF\u6D88\u606F`\u3001`\u6A21\u578B\u8F93\u51FA\u6587\u672C`\u6216`\u5177\u6709result\u7684toolcall`\uFF1B\u9996\u6761 index \u4E3A 0\uFF0C\u6309\u4F1A\u8BDD\u987A\u5E8F\u9012\u589E\u3002 <TAG index=\"N\">\u8868\u793A\u5355\u6761\u5B8C\u6574\u6D88\u606F\uFF0C<TAG start=\"A\" end=\"B\"> \u8868\u793A\u591A\u6761\u8FDE\u7EED\u6D88\u606F\uFF0Cstart/end \u662F\u9996\u5C3E\u5B8C\u6574\u6D88\u606F\u7684 index\uFF1B\u6D88\u606F\u5757\u7684\u5185\u5BB9\u662F\u7528CDATA\u5305\u88F9\u7684\u7EAF\u6587\u672C\uFF1B<assistant type=\"toolcall\" tool-name=\"T\" callId=\"C\" index=\"N\"> \u8868\u793A\u5DE5\u5177\u8C03\u7528\uFF0C\u5185\u542B <tool-args> \u4E0E <tool-result> \u4E24\u4E2ACDATA\u5B50\u5143\u7D20\uFF08\u8C03\u7528\u53C2\u6570\u4E0E\u5DE5\u5177\u8FD4\u56DE\u5185\u5BB9\uFF09\uFF1B<sys type=\"KIND\" index=\"N\"> \u8868\u793A\u88AB\u538B\u7F29\u7684\u7CFB\u7EDF\u6D88\u606F\uFF0C\u5757\u4E2D\u4E3A\u7A7A\uFF1B<skill_content name=\"S\" index=\"N\"> \u8868\u793A\u672A\u538B\u7F29\u7684\u539F\u59CB skill -->";
34
+ export declare function historyFormatNote(sections?: HistoryNoteSections): string;
22
35
  /** skill 工具名:toolcall 条目的工具名为该值时视为 skill 加载,<history> 块中以 <skill_content> 元素呈现。 */
23
36
  export declare const SKILL_TOOL_NAME = "skill";
37
+ /**
38
+ * ask_user_question 工具名:toolcall 条目的工具名为该值时视为向用户的提问,
39
+ * <history> 块中以 <ask-user-question> 元素呈现,压缩时与 skill 一样要求二次确认。
40
+ */
41
+ export declare const ASK_USER_QUESTION_TOOL_NAME = "ask_user_question";
24
42
  /** 旧日志压缩消息的宿主 checkpoint 标记 plugin 名(历史兼容识别用)。 */
25
43
  export declare const COMPACT_CHECKPOINT_PLUGIN = "compact";
26
44
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,uCAAuC;AACvC,eAAO,MAAM,YAAY,kBAAkB,CAAC;AAE5C,iDAAiD;AACjD,eAAO,MAAM,WAAW,YAAY,CAAC;AAErC,iDAAiD;AACjD,eAAO,MAAM,WAAW,iHAAuB,CAAC;AAEhD;;;GAGG;AACH,eAAO,MAAM,2BAA2B,sRACqC,CAAC;AAE9E;;GAEG;AACH,eAAO,MAAM,mBAAmB,ilCAA6W,CAAC;AAE9Y,mFAAmF;AACnF,eAAO,MAAM,eAAe,UAAU,CAAC;AAEvC,kDAAkD;AAClD,eAAO,MAAM,yBAAyB,YAAY,CAAC;AAEnD;;;GAGG;AACH,eAAO,MAAM,wBAAwB,6DAA0B,CAAC;AAEhE,uFAAuF;AACvF,wBAAgB,mBAAmB,CACjC,MAAM,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,GACrD,OAAO,CAGT"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,uCAAuC;AACvC,eAAO,MAAM,YAAY,kBAAkB,CAAC;AAE5C,iDAAiD;AACjD,eAAO,MAAM,WAAW,YAAY,CAAC;AAErC,iDAAiD;AACjD,eAAO,MAAM,WAAW,iHAAuB,CAAC;AAEhD;;;GAGG;AACH,eAAO,MAAM,2BAA2B,sRACqC,CAAC;AAE9E,+BAA+B;AAC/B,MAAM,MAAM,mBAAmB,GAAG;IAChC,yCAAyC;IACzC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,+BAA+B;IAC/B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,8CAA8C;IAC9C,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,2DAA2D;IAC3D,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,GAAE,mBAAwB,GAAG,MAAM,CAc5E;AAED,mFAAmF;AACnF,eAAO,MAAM,eAAe,UAAU,CAAC;AAEvC;;;GAGG;AACH,eAAO,MAAM,2BAA2B,sBAAsB,CAAC;AAE/D,kDAAkD;AAClD,eAAO,MAAM,yBAAyB,YAAY,CAAC;AAEnD;;;GAGG;AACH,eAAO,MAAM,wBAAwB,6DAA0B,CAAC;AAEhE,uFAAuF;AACvF,wBAAgB,mBAAmB,CACjC,MAAM,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,GACrD,OAAO,CAGT"}
package/dist/degrade.d.ts CHANGED
@@ -5,7 +5,9 @@ export type DegradedProblem =
5
5
  /** systemPrompt 服务未挂载(ctx.get 返回 undefined):上下文压力不扣系统提示词,观察偏早触发 */
6
6
  'systemPrompt-missing'
7
7
  /** tokenMeter 服务调用异常(measure/estimateMessage 抛错):压力估算降级,可能跳过观察压缩 */
8
- | 'tokenMeter-unavailable';
8
+ | 'tokenMeter-unavailable'
9
+ /** 配置的 compressReasoningEffort 不被压缩目标模型支持(含模型信息查询失败):本次压缩用模型默认思考等级 */
10
+ | 'reasoning-effort-unavailable';
9
11
  /** 各降级问题面向用户的简短说明(om/warning 信封载荷 message;客户端警告行直接展示)。 */
10
12
  export declare const DEGRADE_PROBLEMS: Record<DegradedProblem, string>;
11
13
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"degrade.d.ts","sourceRoot":"","sources":["../src/degrade.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,+CAA+C;AAC/C,MAAM,MAAM,eAAe;AACzB,mEAAmE;AACjE,sBAAsB;AACxB,oEAAoE;GAClE,wBAAwB,CAAC;AAE7B,0DAA0D;AAC1D,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,eAAe,EAAE,MAAM,CAI5D,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,eAAe,GACvB,IAAI,CAiBN"}
1
+ {"version":3,"file":"degrade.d.ts","sourceRoot":"","sources":["../src/degrade.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,+CAA+C;AAC/C,MAAM,MAAM,eAAe;AACzB,mEAAmE;AACjE,sBAAsB;AACxB,oEAAoE;GAClE,wBAAwB;AAC1B,sEAAsE;GACpE,8BAA8B,CAAC;AAEnC,0DAA0D;AAC1D,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,eAAe,EAAE,MAAM,CAM5D,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,eAAe,GACvB,IAAI,CAiBN"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAG1C,6BAA6B;AAC7B,eAAO,MAAM,IAAI,kBAAkB,CAAC;AAEpC,wDAAwD;AACxD,eAAO,MAAM,MAAM,UAA6C,CAAC;AAEjE,yCAAyC;AACzC,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,CAwD1D"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAG1C,6BAA6B;AAC7B,eAAO,MAAM,IAAI,kBAAkB,CAAC;AAEpC,wDAAwD;AACxD,eAAO,MAAM,MAAM,UAA6C,CAAC;AAEjE,yCAAyC;AACzC,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,CA4D1D"}
package/dist/index.mjs CHANGED
@@ -16,8 +16,8 @@ var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).expor
16
16
  /**
17
17
  * 共享常量:插件级魔法字符串,集中定义避免散落各模块。
18
18
  * 导出 PLUGIN_LABEL / HISTORY_TAG / HISTORY_TIP / COMPLETE_MESSAGE_DEFINITION /
19
- * HISTORY_FORMAT_NOTE / SKILL_TOOL_NAME / COMPACT_CHECKPOINT_PLUGIN /
20
- * COMPACTION_ABORTED_ERROR / isPluginOwnedSource。
19
+ * historyFormatNote / SKILL_TOOL_NAME / ASK_USER_QUESTION_TOOL_NAME /
20
+ * COMPACT_CHECKPOINT_PLUGIN / COMPACTION_ABORTED_ERROR / isPluginOwnedSource。
21
21
  */
22
22
  /** 插件标识:压缩消息 source.plugin 取值与日志前缀。 */
23
23
  const PLUGIN_LABEL = "dsh-plugin-om";
@@ -31,12 +31,30 @@ const HISTORY_TIP = "当前块是历史消息的压缩产物,不要复述";
31
31
  */
32
32
  const COMPLETE_MESSAGE_DEFINITION = "`完整消息`指一条`用户消息`、`系统消息`、`模型输出文本`或`具有result的toolcall`;首条 index 为 0,按会话顺序递增。";
33
33
  /**
34
- * 最终 <history> 块内文块首的格式说明注释(XML 注释,完整消息定义 + 条目标签语义 + CDATA 约定)。
34
+ * 最终 <history> 块内文块首的格式说明注释(XML 注释)。通用部分(完整消息定义 +
35
+ * 条目标签语义 + CDATA 约定 + toolcall 结构)始终保留;<user_message> / <sys> /
36
+ * <skill_content> / <ask-user-question> 的条目说明仅在块内存在对应条目时追加。
35
37
  */
36
- const HISTORY_FORMAT_NOTE = `<!-- ${COMPLETE_MESSAGE_DEFINITION} <TAG index="N">表示单条完整消息,<TAG start="A" end="B"> 表示多条连续消息,start/end 是首尾完整消息的 index;消息块的内容是用CDATA包裹的纯文本;<assistant type="toolcall" tool-name="T" callId="C" index="N"> 表示工具调用,内含 <tool-args> 与 <tool-result> 两个CDATA子元素(调用参数与工具返回内容);<sys type="KIND" index="N"> 表示被压缩的系统消息,块中为空;<skill_content name="S" index="N"> 表示未压缩的原始 skill -->`;
38
+ function historyFormatNote(sections = {}) {
39
+ const parts = [
40
+ COMPLETE_MESSAGE_DEFINITION,
41
+ "<TAG index=\"N\">表示单条完整消息,<TAG start=\"A\" end=\"B\"> 表示多条连续消息,start/end 是首尾完整消息的 index;消息块的内容是用CDATA包裹的纯文本",
42
+ "<assistant type=\"toolcall\" tool-name=\"T\" callId=\"C\" index=\"N\"> 表示工具调用,内含 <tool-args> 与 <tool-result> 两个CDATA子元素(调用参数与工具返回内容)"
43
+ ];
44
+ if (sections.user) parts.push("<user_message index=\"N\"> 表示用户消息原文");
45
+ if (sections.sys) parts.push("<sys type=\"KIND\" index=\"N\"> 表示被压缩的系统消息,块中为空");
46
+ if (sections.skill) parts.push("<skill_content name=\"S\" index=\"N\"> 表示未压缩的原始 skill");
47
+ if (sections.askUserQuestion) parts.push("<ask-user-question index=\"N\"> 表示向用户提问,CDATA 内为 q:(提问)与 a:(用户回答)行");
48
+ return `<!-- ${parts.join(";")} -->`;
49
+ }
37
50
  /** skill 工具名:toolcall 条目的工具名为该值时视为 skill 加载,<history> 块中以 <skill_content> 元素呈现。 */
38
51
  const SKILL_TOOL_NAME = "skill";
39
52
  /**
53
+ * ask_user_question 工具名:toolcall 条目的工具名为该值时视为向用户的提问,
54
+ * <history> 块中以 <ask-user-question> 元素呈现,压缩时与 skill 一样要求二次确认。
55
+ */
56
+ const ASK_USER_QUESTION_TOOL_NAME = "ask_user_question";
57
+ /**
40
58
  * 压缩因 signal 中止而放弃时 compaction/end 的 error 标识(服务端写入、客户端过滤):
41
59
  * 中止不是失败,客户端据此隐藏失败行(宿主不变量要求无 summary 的 end 必须带 error)。
42
60
  */
@@ -7662,6 +7680,40 @@ function skillNameOf(session, cm) {
7662
7680
  return "";
7663
7681
  }
7664
7682
  /**
7683
+ * 从 ask_user_question 调用参数 JSON 提取问题文本行:questions 数组逐项取
7684
+ * question 字段(字符串元素原样),一个问题一行。参数缺失、非法或解析不出
7685
+ * 问题文本时返回空数组。
7686
+ */
7687
+ function askQuestionLines(args) {
7688
+ if (args === void 0 || args.trim() === "") return [];
7689
+ let parsed;
7690
+ try {
7691
+ parsed = JSON.parse(args);
7692
+ } catch {
7693
+ return [];
7694
+ }
7695
+ if (!isRecord(parsed) || !Array.isArray(parsed.questions)) return [];
7696
+ const lines = [];
7697
+ for (const q of parsed.questions) if (typeof q === "string" && q.trim() !== "") lines.push(q);
7698
+ else if (isRecord(q) && typeof q.question === "string" && q.question.trim() !== "") lines.push(q.question);
7699
+ return lines;
7700
+ }
7701
+ /**
7702
+ * ask_user_question 条目正文:构造为原生 <ask-user-question> 包裹形态,
7703
+ * 内文为 q:(问题文本,一个问题一行)与 a:(用户回答原文)行,缺失段省略。
7704
+ * 问题与回答均缺失时返回 null(调用方回退为通用完整消息呈现)。
7705
+ */
7706
+ function askUserQuestionText(session, cm) {
7707
+ const call = toolCallBlockOf(session, cm);
7708
+ const args = call === void 0 ? void 0 : toolArgsJson(call.arguments);
7709
+ const resultMessage = toolResultMessageOf(session, cm);
7710
+ const result = resultMessage && Array.isArray(resultMessage.content) ? renderMessageText(resultMessage) : "";
7711
+ const qLines = askQuestionLines(args);
7712
+ const answers = result.trim() === "" ? "" : result;
7713
+ if (qLines.length === 0 && answers === "") return null;
7714
+ return `<ask-user-question>${[...qLines.map((q) => `q:${q}`), ...answers === "" ? [] : [`a:${answers}`]].join("\n")}</ask-user-question>`;
7715
+ }
7716
+ /**
7665
7717
  * 观察视图:被压缩区间(表层 seq 集合)内的完整消息投影为条目——
7666
7718
  * user → 原文(图片等非文本块为注释)、sys → 空条目、assistant/toolcall → 原文渲染,
7667
7719
  * reasoning 作为参考条目置于其所属 assistant 条目之前(每条 assistant 消息输出一次;
@@ -7721,12 +7773,14 @@ function buildObserveView(session, seqs, options = {}) {
7721
7773
  }
7722
7774
  const toolName = cm.type === "toolcall" ? toolCallNameOf(session, cm) : void 0;
7723
7775
  const isSkill = toolName === SKILL_TOOL_NAME;
7724
- const text = isSkill ? renderToolResultText(session, cm) : renderCompleteMessage(session, cm);
7776
+ const isAsk = toolName === ASK_USER_QUESTION_TOOL_NAME;
7777
+ const askText = isAsk ? askUserQuestionText(session, cm) : void 0;
7778
+ const text = isSkill ? renderToolResultText(session, cm) : isAsk ? askText ?? renderCompleteMessage(session, cm) : renderCompleteMessage(session, cm);
7725
7779
  if (text.trim() === "") continue;
7726
7780
  const skillName = isSkill ? skillNameOf(session, cm) : void 0;
7727
7781
  let toolArgs;
7728
7782
  let toolResult;
7729
- if (cm.type === "toolcall" && !isSkill) {
7783
+ if (cm.type === "toolcall" && !isSkill && !isAsk) {
7730
7784
  const call = toolCallBlockOf(session, cm);
7731
7785
  if (call !== void 0) toolArgs = toolArgsJson(call.arguments);
7732
7786
  const resultMessage = toolResultMessageOf(session, cm);
@@ -7809,8 +7863,45 @@ function skillContentSections(text) {
7809
7863
  };
7810
7864
  }
7811
7865
  /**
7866
+ * 提取新格式 ask_user_question 条目正文(原生 <ask-user-question> 包裹)的内文
7867
+ * (CDATA 内 q:/a: 行)。非该包裹形态时返回 undefined。
7868
+ */
7869
+ function askUserQuestionInner(text) {
7870
+ return /^[\s]*<ask-user-question\b[^>]*>([\s\S]*)<\/ask-user-question>[\s]*$/.exec(text)?.[1];
7871
+ }
7872
+ /**
7873
+ * 提取旧格式 ask_user_question 条目正文(原生 <askuserquestion> 包裹)的内文。
7874
+ * 非该包裹形态时返回 undefined。
7875
+ */
7876
+ function askUserQuestionLegacyInner(text) {
7877
+ return /^[\s]*<askuserquestion\b[^>]*>([\s\S]*)<\/askuserquestion>[\s]*$/.exec(text)?.[1];
7878
+ }
7879
+ /**
7880
+ * 提取旧格式 ask_user_question 条目正文(原生 <askuserquestion> 包裹)中
7881
+ * <questions> 与 <answers> 两段正文。<questions> 与 <answers> 均缺失、两段之间存在
7882
+ * 其他内容时返回 undefined(调用方按旧格式整体正文处理);<answers> 缺省为
7883
+ * undefined(渲染时省略该段)。
7884
+ */
7885
+ function askUserQuestionSections(text) {
7886
+ const body = askUserQuestionLegacyInner(text);
7887
+ if (body === void 0) return void 0;
7888
+ const qMatch = /<questions>([\s\S]*?)<\/questions>/.exec(body);
7889
+ const aMatch = /<answers>([\s\S]*?)<\/answers>/.exec(body);
7890
+ if (!qMatch && !aMatch) return void 0;
7891
+ if (qMatch && aMatch && aMatch.index < qMatch.index) return void 0;
7892
+ let rest = body;
7893
+ if (qMatch) rest = rest.replace(qMatch[0], "");
7894
+ if (aMatch) rest = rest.replace(aMatch[0], "");
7895
+ if (rest.trim() !== "") return void 0;
7896
+ return {
7897
+ questions: qMatch?.[1] ?? "",
7898
+ ...aMatch === null ? {} : { answers: aMatch[1] ?? "" }
7899
+ };
7900
+ }
7901
+ /**
7812
7902
  * 解析一个已有 <history> 块的内条目(反思视图):user_message / sys / assistant
7813
- * (index 单条或 start/end 区间)/ skill_content(name 属性 + index 定位)/ reasoning。
7903
+ * (index 单条或 start/end 区间)/ skill_content(name 属性 + index 定位)/
7904
+ * ask-user-question(index 定位)/ reasoning。
7814
7905
  * 整块无法解析或根非 <history> 时降级为单条不可定位的历史遗留条目(text 为块内文原文,
7815
7906
  * 构建最终块时原样保留)。
7816
7907
  */
@@ -7913,6 +8004,31 @@ function parseBlockEntries(blockText, blockSeq) {
7913
8004
  blockSeq
7914
8005
  });
7915
8006
  }
8007
+ } else if (el.nodeName === "ask-user-question") {
8008
+ const index = intAttr(el, "index");
8009
+ if (index !== void 0) entries.push({
8010
+ kind: "assistant",
8011
+ lo: index,
8012
+ hi: index,
8013
+ text: `<ask-user-question>${el.textContent ?? ""}</ask-user-question>`,
8014
+ toolName: ASK_USER_QUESTION_TOOL_NAME,
8015
+ blockSeq
8016
+ });
8017
+ } else if (el.nodeName === "askuserquestion") {
8018
+ const index = intAttr(el, "index");
8019
+ if (index !== void 0) {
8020
+ const questions = childText(el, "questions");
8021
+ const answers = childText(el, "answers");
8022
+ const text = questions !== void 0 || answers !== void 0 ? "<askuserquestion>" + (questions === void 0 ? "" : `<questions>${questions}</questions>`) + (answers === void 0 ? "" : `<answers>${answers}</answers>`) + "</askuserquestion>" : `<askuserquestion>${el.textContent ?? ""}</askuserquestion>`;
8023
+ entries.push({
8024
+ kind: "assistant",
8025
+ lo: index,
8026
+ hi: index,
8027
+ text,
8028
+ toolName: ASK_USER_QUESTION_TOOL_NAME,
8029
+ blockSeq
8030
+ });
8031
+ }
7916
8032
  } else if (el.nodeName === "reasoning") entries.push({
7917
8033
  kind: "reasoning",
7918
8034
  text,
@@ -7976,6 +8092,36 @@ function entryToElement(doc, entry) {
7976
8092
  }
7977
8093
  return el;
7978
8094
  }
8095
+ if (entry.kind === "assistant" && entry.toolName === "ask_user_question") {
8096
+ const inner = askUserQuestionInner(entry.text);
8097
+ if (inner !== void 0) {
8098
+ const el = doc.createElement("ask-user-question");
8099
+ if (entry.lo !== void 0 && entry.lo === entry.hi) el.setAttribute("index", String(entry.lo));
8100
+ appendCdataText(doc, el, inner);
8101
+ return el;
8102
+ }
8103
+ const legacyInner = askUserQuestionLegacyInner(entry.text);
8104
+ if (legacyInner !== void 0) {
8105
+ const el = doc.createElement("askuserquestion");
8106
+ if (entry.lo !== void 0 && entry.lo === entry.hi) el.setAttribute("index", String(entry.lo));
8107
+ const sections = askUserQuestionSections(entry.text);
8108
+ if (sections) {
8109
+ const questions = doc.createElement("questions");
8110
+ appendCdataText(doc, questions, sections.questions);
8111
+ el.appendChild(questions);
8112
+ if (sections.answers !== void 0) {
8113
+ const answers = doc.createElement("answers");
8114
+ appendCdataText(doc, answers, sections.answers);
8115
+ el.appendChild(answers);
8116
+ }
8117
+ } else appendCdataText(doc, el, legacyInner);
8118
+ return el;
8119
+ }
8120
+ const el = doc.createElement("ask-user-question");
8121
+ if (entry.lo !== void 0 && entry.lo === entry.hi) el.setAttribute("index", String(entry.lo));
8122
+ appendCdataText(doc, el, entry.text);
8123
+ return el;
8124
+ }
7979
8125
  if (entry.kind === "assistant" && entry.toolName === "skill") {
7980
8126
  const el = doc.createElement("skill_content");
7981
8127
  el.setAttribute("name", entry.skillName ?? "");
@@ -8011,7 +8157,7 @@ function renderEntriesXml(entries) {
8011
8157
  }
8012
8158
  //#endregion
8013
8159
  //#region src/compress-tools.ts
8014
- /** 压缩会话的工具状态:视图 + 替换记录 + skill 二次确认标记 + 完成标记。 */
8160
+ /** 压缩会话的工具状态:视图 + 替换记录 + 二次确认标记(skill / ask_user_question)+ 完成标记。 */
8015
8161
  var CompressionState = class CompressionState {
8016
8162
  view;
8017
8163
  replacements = [];
@@ -8117,9 +8263,9 @@ var CompressionState = class CompressionState {
8117
8263
  }
8118
8264
  /**
8119
8265
  * compressHistory:把 index 单条或 start..end 连续区间的 assistant 条目替换为
8120
- * content 摘要。校验失败返回错误结果(不应用);skill 块首次被覆盖返回要求
8121
- * 重新思考的错误结果(不应用,标记已挑战);通过后记录替换并覆盖被完全包含
8122
- * 的旧替换。
8266
+ * content 摘要。校验失败返回错误结果(不应用);skill / ask_user_question 条目
8267
+ * 首次被覆盖返回要求重新思考的错误结果(不应用,标记已挑战);通过后记录替换并
8268
+ * 覆盖被完全包含的旧替换。
8123
8269
  */
8124
8270
  compressHistory(args) {
8125
8271
  const { minIndex, maxIndex } = this.view;
@@ -8205,13 +8351,22 @@ var CompressionState = class CompressionState {
8205
8351
  isError: true
8206
8352
  };
8207
8353
  const unchallenged = [];
8354
+ let challengedTool;
8208
8355
  for (const entry of this.view.entries) {
8209
- if (entry.kind !== "assistant" || entry.toolName !== "skill") continue;
8356
+ if (entry.kind !== "assistant") continue;
8357
+ if (entry.toolName !== "skill" && entry.toolName !== "ask_user_question") continue;
8210
8358
  if (entry.lo === void 0 || entry.lo < lo || entry.lo > hi) continue;
8211
- if (!this.challengedSkills.has(entry.lo)) unchallenged.push(entry.lo);
8359
+ if (!this.challengedSkills.has(entry.lo)) {
8360
+ unchallenged.push(entry.lo);
8361
+ challengedTool = entry.toolName;
8362
+ }
8212
8363
  }
8213
8364
  if (unchallenged.length > 0) {
8214
8365
  for (const index of unchallenged) this.challengedSkills.add(index);
8366
+ if (challengedTool === "ask_user_question") return {
8367
+ text: `${CompressionState.spanLabel(lo, hi)} 包含 ask_user_question 向用户的提问(完整消息 index ${unchallenged.join("、")})。请重新思考该提问是否确定与后续任务无关:确定不相关时再次调用 compressHistory 压缩该区间;不确定或相关时不要压缩该区间,保持原样即可`,
8368
+ isError: true
8369
+ };
8215
8370
  return {
8216
8371
  text: `${CompressionState.spanLabel(lo, hi)} 包含 skill 加载(完整消息 index ${unchallenged.join("、")})。请重新思考该 skill 是否确定与后续任务无关:确定不相关时再次调用 compressHistory 压缩该区间;不确定或相关时不要压缩该区间,保持原样即可`,
8217
8372
  isError: true
@@ -8243,8 +8398,9 @@ var CompressionState = class CompressionState {
8243
8398
  /**
8244
8399
  * 构建最终 <history> 块:按 index 顺序合并视图条目与替换记录——user / sys 条目
8245
8400
  * 原样、被替换区间生成 <assistant index|start end> 摘要条目(content 以 CDATA 包裹嵌入)、
8246
- * 未替换 assistant 条目原样保留、reasoning 不进产物;块首为格式说明注释,开标签
8247
- * 携带 tip 属性。产物为合法 XML,无需校验。
8401
+ * 未替换 assistant 条目原样保留、reasoning 不进产物;块首为按产物内实际条目动态
8402
+ * 生成的格式说明注释(user_message / sys / skill_content / ask-user-question 条目说明
8403
+ * 仅在对应条目存在时包含),开标签携带 tip 属性。产物为合法 XML,无需校验。
8248
8404
  */
8249
8405
  buildFinalBlock() {
8250
8406
  const doc = new import_lib.DOMParser({ onError: () => {} }).parseFromString(`<${HISTORY_TAG} />`, "text/xml");
@@ -8279,9 +8435,15 @@ var CompressionState = class CompressionState {
8279
8435
  root.appendChild(entryToElement(doc, entry));
8280
8436
  }
8281
8437
  flushReplacementsBefore(void 0);
8438
+ const note = historyFormatNote({
8439
+ user: this.view.entries.some((e) => e.kind === "user"),
8440
+ sys: this.view.entries.some((e) => e.kind === "sys"),
8441
+ skill: this.view.entries.some((e) => e.kind === "assistant" && e.toolName === "skill" && !coveredBy(e)),
8442
+ askUserQuestion: this.view.entries.some((e) => e.kind === "assistant" && e.toolName === "ask_user_question" && !coveredBy(e))
8443
+ });
8282
8444
  const serializer = new import_lib.XMLSerializer();
8283
8445
  const inner = Array.from(root.childNodes).map((node) => serializer.serializeToString(node)).join("\n");
8284
- return `<${HISTORY_TAG} tip="${HISTORY_TIP}">\n${HISTORY_FORMAT_NOTE}\n${inner}\n</${HISTORY_TAG}>`;
8446
+ return `<${HISTORY_TAG} tip="${HISTORY_TIP}">\n${note}\n${inner}\n</${HISTORY_TAG}>`;
8285
8447
  }
8286
8448
  };
8287
8449
  /** 压缩会话工具的 wire 定义(GenerateOptions.tools)。 */
@@ -8415,8 +8577,9 @@ async function gateRateLimit(waitMs, signal) {
8415
8577
  * 录 sessionId 于日志,失败记录作为诊断子会话 id 向上传播
8416
8578
  */
8417
8579
  /**
8418
- * 共享压缩提示词(观察/反思同一套):完整消息定义、工具语义、压缩要求、skill 规则
8419
- * 与提交方式。作为压缩会话的 system;skipReasoning=true 时省略 <reasoning> 说明行。
8580
+ * 共享压缩提示词(观察/反思同一套):完整消息定义、工具语义、压缩要求、skill 与
8581
+ * ask_user_question 规则、提交方式。作为压缩会话的 system;skipReasoning=true 时
8582
+ * 省略 <reasoning> 说明行。
8420
8583
  */
8421
8584
  function buildCompressionPrompt(skipReasoning) {
8422
8585
  return [
@@ -8439,6 +8602,7 @@ function buildCompressionPrompt(skipReasoning) {
8439
8602
  "- <history> 条目正文以 CDATA 包裹(空的 <sys> 条目为自闭合空元素,无正文),CDATA 内为逐字原样内容。",
8440
8603
  "- 工具调用条目为 <assistant index=\"N\" type=\"toolcall\" tool-name=\"…\" callId=\"…\">,内含 <tool-args>(调用参数 JSON)与 <tool-result>(工具返回内容)两个 CDATA 子元素。",
8441
8604
  "- 加载的 skill 以 <skill_content name=\"…\" index=\"N\"> 条目呈现,内含 <skill_resources> 与 <skill_instructions> 两段,内文为其工具返回内容,属于关键信息。仅在你明确判断该 skill 与后续任务无关时,压缩它;如果该 skill 与后续任务相关,或者你无法判断,不要压缩,**保持原文**。",
8605
+ "- ask_user_question 工具调用(向用户的提问)以 <ask-user-question index=\"N\"> 条目呈现,CDATA 内为 q:(问题文本,一个问题一行)与 a:(用户回答原文)行,属于关键信息。仅在你明确判断该提问与后续任务无关时,压缩它;如果该提问与后续任务相关,或者你无法判断,不要压缩,**保持原文**。",
8442
8606
  "- 未压缩的条目将原样保留;宁可保留也不要强行压缩不确定的内容。",
8443
8607
  "- 全部完成后调用 completeCompression 结束;不要输出与工具调用无关的文本。"
8444
8608
  ].join("\n");
@@ -8569,6 +8733,7 @@ async function runCompressionLoop(ctx, session, options) {
8569
8733
  provider: options.target.provider,
8570
8734
  model: options.target.model,
8571
8735
  ...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },
8736
+ ...options.reasoningEffort === void 0 ? {} : { reasoningEffort: options.reasoningEffort },
8572
8737
  sessionId: session.id,
8573
8738
  purpose: "compaction",
8574
8739
  ...options.signal === void 0 ? {} : { signal: options.signal },
@@ -8735,7 +8900,8 @@ function findOmEvents(session, kind) {
8735
8900
  /** 各降级问题面向用户的简短说明(om/warning 信封载荷 message;客户端警告行直接展示)。 */
8736
8901
  const DEGRADE_PROBLEMS = {
8737
8902
  "systemPrompt-missing": "系统提示词服务未挂载,上下文压力估算不扣除系统提示词 tokens(压缩触发会偏早)",
8738
- "tokenMeter-unavailable": "token 计量服务异常,上下文压力估算降级(可能跳过压缩或按 0 计)"
8903
+ "tokenMeter-unavailable": "token 计量服务异常,上下文压力估算降级(可能跳过压缩或按 0 计)",
8904
+ "reasoning-effort-unavailable": "配置的压缩思考等级不被压缩目标模型支持,压缩降级为模型默认思考等级"
8739
8905
  };
8740
8906
  /**
8741
8907
  * 报告一次挂载失败类降级:console.warn 始终输出到宿主进程外部;同会话同问题首次
@@ -8764,45 +8930,55 @@ function reportDegrade(session, logger, problem) {
8764
8930
  }
8765
8931
  //#endregion
8766
8932
  //#region src/compress.ts
8767
- /**
8768
- * 两级自动压缩(观察/反思)与 compaction 生命周期提交。
8769
- * 导出 estimateTextTokens / isPairBalancedAfter / computeCompressRange / historySection /
8770
- * findObservePending / reflectPass / observePass / maybeCompress。
8771
- *
8772
- * - 摘要生成走工具驱动的压缩循环(compress-loop.ts runCompressionLoop):首条 user
8773
- * 消息仅含压缩指令与 start/end 区间,模型经 getHistory / compressHistory /
8774
- * completeCompression 工具完成压缩;最终 <history> 块由插件从视图与替换记录构建,
8775
- * 全程无需整块校验
8776
- * - 反思:全部 <history> 块 token 合计 ≥ reflectThresholdTokens 时,把全部块条目作为
8777
- * 压缩视图重新压缩合并(视图无条目时跳过,如全部为不可解析的历史遗留块)
8778
- * - 观察(触发 → 待定 → 延迟执行):净压力(上下文压力 − 已压缩块 token 合计 − 系统提示词
8779
- * token 估算 − 工具定义 token 估算)首次 ≥ observeThresholdTokens 时记录待定标记
8780
- * (触发点 = 当时的最后一条完整消息 index),本次不压缩;待定后新增完整消息数 ≥
8781
- * tailMessageCount 时,把压缩边界至触发点的全部消息作为压缩视图替换为新 <history>
8782
- * 块(旧块保留),等待期间的新消息成为下一轮未压缩尾部(延迟窗口内压力允许
8783
- * 短暂超阈值);tailMessageCount=0 时触发当轮直接执行(不落待定标记)
8784
- * - 待定标记以 log-only om 信封事件(借用 feedback/record,kind 为 om/observe-pending /
8785
- * om/observe-invalidate,见 om-event.ts)持久化在会话日志中(重启后从日志恢复);
8786
- * 压缩失败保留待定,下个 pre-step 直接重试执行
8787
- * - 两级在 pre-step 阻塞串行执行(先反思后观察);仅主会话生效;omEnabled=false 关闭
8788
- * - 压缩边界:最后一个合法 <history> 块之后的消息视为未压缩,其前不重复压缩
8789
- * - 压缩循环最终失败(连续无工具调用 / 请求级错误)时 pass 返回失败结果(携带最后一次
8790
- * 错误),压缩流程向上传播,pre-step 据此拒绝本 step 中断当前 turn;signal 中止标记
8791
- * aborted(不中断);成功与失败均落盘压缩会话记录子会话(失败时其 id 随结果传播为
8792
- * 诊断子会话 id)
8793
- * - 提交走宿主 compaction/* 生命周期事件(start 带 phase → summary → 替换消息 → end),
8794
- * 失败补 end(error,实际报错 + 诊断子会话 sessionId);替换消息 source 标记插件标识供 UI 认领
8795
- * - 挂载失败类问题(systemPrompt/tokenMeter 服务异常)始终 console 到外部进程,并追加
8796
- * log-only om 警告事件(借用 feedback/record,客户端渲染功能降级警告行,每会话同一
8797
- * 问题至多一次);
8798
- * 辅助估算的普通运行时报错仅记日志。降级与报错都不阻塞压缩(tokenMeter 压力数据
8799
- * 缺失时本轮跳过观察)
8800
- */
8801
8933
  /** 历史文本 token 估算:4 字符 ≈ 1 token(与宿主 dsh-token-meter 启发式一致)。 */
8802
8934
  function estimateTextTokens(text) {
8803
8935
  return Math.ceil(text.length / 4);
8804
8936
  }
8805
8937
  /**
8938
+ * 压缩目标解析:compressProvider + compressModel 成对配置时覆盖会话路由;仅配置单键或
8939
+ * 未配置时回落 routedTarget(会话未路由返回 undefined,压缩跳过——成对覆盖配置下
8940
+ * 未路由会话仍可压缩)。
8941
+ */
8942
+ function compressionTarget(config, session) {
8943
+ if (config.compressProvider !== void 0 && config.compressModel !== void 0) return {
8944
+ provider: config.compressProvider,
8945
+ model: config.compressModel
8946
+ };
8947
+ return routedTarget(session);
8948
+ }
8949
+ /** 压缩思考等级校验缓存:provider+model → 命中的等级 id(undefined 表示降级为模型默认)。 */
8950
+ const compressionEffortCache = /* @__PURE__ */ new Map();
8951
+ /**
8952
+ * 校验配置的 compressReasoningEffort 并解析为压缩请求的思考等级:未配置返回 undefined
8953
+ * (用模型默认,不查询模型信息);命中目标模型 reasoning.efforts 返回等级 id;
8954
+ * 不在可选等级 / 模型无 reasoning 元数据 / 查询抛错时返回 undefined 并报告
8955
+ * reasoning-effort-unavailable 降级。结果按 provider+model 缓存(含降级结果),避免
8956
+ * 每个 pre-step 重复查询。
8957
+ */
8958
+ async function resolveCompressionEffort(ctx, session, config, target, logger) {
8959
+ const configured = config.compressReasoningEffort;
8960
+ if (configured === void 0) return void 0;
8961
+ const cacheKey = `${target.provider}\n${target.model}`;
8962
+ if (compressionEffortCache.has(cacheKey)) return compressionEffortCache.get(cacheKey);
8963
+ let resolved;
8964
+ try {
8965
+ const efforts = (await ctx.llm.resolveModelInfo(target.provider, target.model))?.reasoning?.efforts;
8966
+ if (Array.isArray(efforts) && efforts.some((effort) => effort?.id === configured)) {
8967
+ resolved = configured;
8968
+ logger.step(`压缩思考等级校验通过:${configured}`);
8969
+ } else {
8970
+ reportDegrade(session, logger, "reasoning-effort-unavailable");
8971
+ logger.warn(`compressReasoningEffort=${configured} 不在模型 ${target.provider}/${target.model} 的可选思考等级中,使用模型默认`);
8972
+ }
8973
+ } catch (error) {
8974
+ const message = error instanceof Error ? error.message : String(error);
8975
+ reportDegrade(session, logger, "reasoning-effort-unavailable");
8976
+ logger.warn(`压缩思考等级校验失败(${message}),使用模型默认`);
8977
+ }
8978
+ compressionEffortCache.set(cacheKey, resolved);
8979
+ return resolved;
8980
+ }
8981
+ /**
8806
8982
  * 运行压缩循环并归一化结果:失败统一追加 compaction/end(error)(携带诊断子会话 id),
8807
8983
  * 成功记会话记录日志;返回循环结果(成功时由调用方提交)。
8808
8984
  */
@@ -8995,7 +9171,8 @@ function appendCompactionSummary(session, data) {
8995
9171
  startedAt: data.stats.startedAt,
8996
9172
  completedAt: data.stats.completedAt,
8997
9173
  durationMs: data.stats.durationMs,
8998
- ...data.usage === void 0 ? {} : { usage: data.usage }
9174
+ ...data.usage === void 0 ? {} : { usage: data.usage },
9175
+ ...data.reasoningEffort === void 0 ? {} : { reasoningEffort: data.reasoningEffort }
8999
9176
  };
9000
9177
  return session.append("compaction/summary", payload).seq;
9001
9178
  }
@@ -9044,7 +9221,7 @@ function appendHistoryMessage(session, content, sourceEventSeqs, surfaceOp, comp
9044
9221
  * 为不可解析的历史遗留块)时跳过。失败不产生部分替换;最终失败返回失败结果
9045
9222
  * (error = 最后一次错误)。
9046
9223
  */
9047
- async function reflectPass(ctx, agent, config, target, signal) {
9224
+ async function reflectPass(ctx, agent, config, target, signal, reasoningEffort) {
9048
9225
  const session = agent.session;
9049
9226
  const logger = makeLogger(ctx, config.debug);
9050
9227
  logger.step(`反思检查(反思阈值 ${config.reflectThresholdTokens} tokens)`);
@@ -9094,6 +9271,7 @@ async function reflectPass(ctx, agent, config, target, signal) {
9094
9271
  rateLimitWaitMs: config.rateLimitWaitMs,
9095
9272
  skipReasoning: config.compressSkipReasoning,
9096
9273
  debug: config.debug,
9274
+ ...reasoningEffort === void 0 ? {} : { reasoningEffort },
9097
9275
  ...signal === void 0 ? {} : { signal }
9098
9276
  }, logger, "reflect");
9099
9277
  if (!summaryResult.ok) return {
@@ -9119,7 +9297,8 @@ async function reflectPass(ctx, agent, config, target, signal) {
9119
9297
  model: target.model,
9120
9298
  maxTokens: config.compressMaxTokens,
9121
9299
  stats: summaryResult.stats,
9122
- ...summaryResult.usage === void 0 ? {} : { usage: summaryResult.usage }
9300
+ ...summaryResult.usage === void 0 ? {} : { usage: summaryResult.usage },
9301
+ ...reasoningEffort === void 0 ? {} : { reasoningEffort }
9123
9302
  });
9124
9303
  logger.step("反思提交:替换整个 <history> 块区段为合并摘要");
9125
9304
  appendHistoryMessage(session, report, [summarySeq, ...blockSeqs], {
@@ -9207,7 +9386,7 @@ function measurePressureTokens(ctx, session, logger) {
9207
9386
  * 失败保留待定,下个 pre-step 直接重试执行。最终失败返回失败结果
9208
9387
  * (error = 最后一次错误)。
9209
9388
  */
9210
- async function observePass(ctx, agent, config, waitCount, target, signal) {
9389
+ async function observePass(ctx, agent, config, waitCount, target, signal, reasoningEffort) {
9211
9390
  const session = agent.session;
9212
9391
  const logger = makeLogger(ctx, config.debug);
9213
9392
  logger.step(`观察检查(观察阈值 ${config.observeThresholdTokens} tokens,延迟等待 ${waitCount} 条完整消息)`);
@@ -9315,6 +9494,7 @@ async function observePass(ctx, agent, config, waitCount, target, signal) {
9315
9494
  rateLimitWaitMs: config.rateLimitWaitMs,
9316
9495
  skipReasoning: config.compressSkipReasoning,
9317
9496
  debug: config.debug,
9497
+ ...reasoningEffort === void 0 ? {} : { reasoningEffort },
9318
9498
  ...signal === void 0 ? {} : { signal }
9319
9499
  }, logger, "observe");
9320
9500
  if (!summaryResult.ok) return {
@@ -9357,7 +9537,8 @@ async function observePass(ctx, agent, config, waitCount, target, signal) {
9357
9537
  model: target.model,
9358
9538
  maxTokens: config.compressMaxTokens,
9359
9539
  stats: summaryResult.stats,
9360
- ...usage === void 0 ? {} : { usage }
9540
+ ...usage === void 0 ? {} : { usage },
9541
+ ...reasoningEffort === void 0 ? {} : { reasoningEffort }
9361
9542
  });
9362
9543
  logger.step("观察提交:替换被压缩新消息区间为 <history>(旧块保留)");
9363
9544
  appendHistoryMessage(session, report, [summarySeq, ...replaceSeqs], {
@@ -9391,21 +9572,22 @@ async function maybeCompress(ctx, agent, config, signal) {
9391
9572
  logger.step("omEnabled=false,跳过压缩");
9392
9573
  return { failed: false };
9393
9574
  }
9394
- const target = routedTarget(session);
9575
+ const target = compressionTarget(config, session);
9395
9576
  if (target === void 0) {
9396
- logger.step("会话未路由(无 provider/model),跳过压缩");
9577
+ logger.step("会话未路由(无 provider/model)且未配置压缩目标覆盖,跳过压缩");
9397
9578
  return { failed: false };
9398
9579
  }
9399
- logger.step(`会话路由:provider ${target.provider},model ${target.model}`);
9580
+ logger.step(`压缩路由:provider ${target.provider},model ${target.model}`);
9581
+ const reasoningEffort = await resolveCompressionEffort(ctx, session, config, target, logger);
9400
9582
  const waitCount = config.tailMessageCount;
9401
9583
  logger.step("反思 pass 开始");
9402
- const reflect = await reflectPass(ctx, agent, config, target, signal);
9584
+ const reflect = await reflectPass(ctx, agent, config, target, signal, reasoningEffort);
9403
9585
  if (reflect.failed) {
9404
9586
  logger.step("反思 pass 失败(本轮将被拒绝),跳过观察 pass");
9405
9587
  return reflect;
9406
9588
  }
9407
9589
  logger.step("反思 pass 结束,观察 pass 开始");
9408
- const observe = await observePass(ctx, agent, config, waitCount, target, signal);
9590
+ const observe = await observePass(ctx, agent, config, waitCount, target, signal, reasoningEffort);
9409
9591
  logger.step("观察 pass 结束,压缩流程完成");
9410
9592
  return observe;
9411
9593
  }
@@ -9628,7 +9810,10 @@ const DEFAULT_CONFIG = Object.freeze({
9628
9810
  debug: false,
9629
9811
  recallEnabled: true,
9630
9812
  semanticRecallEnabled: true,
9631
- modelDir: sharedModelDir()
9813
+ modelDir: sharedModelDir(),
9814
+ compressProvider: void 0,
9815
+ compressModel: void 0,
9816
+ compressReasoningEffort: void 0
9632
9817
  });
9633
9818
  /** 数值键校验参数表:键名 + [是否必须为整数]。 */
9634
9819
  const NUMBER_KEYS = [
@@ -9652,6 +9837,10 @@ function resolveBoolean(raw, defaultValue) {
9652
9837
  if (typeof raw === "boolean") return raw;
9653
9838
  return defaultValue;
9654
9839
  }
9840
+ /** 解析字符串配置值:非空字符串才生效,缺省 / null / 空白串 / 非字符串回退 undefined。 */
9841
+ function resolveOptionalString(raw) {
9842
+ if (typeof raw === "string" && raw.trim() !== "") return raw;
9843
+ }
9655
9844
  /** 解析合并配置:未知键忽略、不合法值回退默认值,返回冻结的完整配置。 */
9656
9845
  function resolveConfig(raw) {
9657
9846
  const input = normalizeConfigInput(raw);
@@ -9671,6 +9860,9 @@ function resolveConfig(raw) {
9671
9860
  config.semanticRecallEnabled = resolveBoolean(input.semanticRecallEnabled, true);
9672
9861
  const modelDir = input.modelDir;
9673
9862
  if (typeof modelDir === "string" && modelDir.trim() !== "") config.modelDir = modelDir;
9863
+ config.compressProvider = resolveOptionalString(input.compressProvider);
9864
+ config.compressModel = resolveOptionalString(input.compressModel);
9865
+ config.compressReasoningEffort = resolveOptionalString(input.compressReasoningEffort);
9674
9866
  return Object.freeze(config);
9675
9867
  }
9676
9868
  //#endregion
@@ -10145,7 +10337,7 @@ const inject = [
10145
10337
  function apply(ctx, config) {
10146
10338
  const resolved = resolveConfig(config);
10147
10339
  const logger = makeLogger(ctx, resolved.debug);
10148
- logger.step(`apply 启动:observeThresholdTokens=${String(resolved.observeThresholdTokens)} reflectThresholdTokens=${String(resolved.reflectThresholdTokens)} compressMaxTokens=${resolved.compressMaxTokens === void 0 ? "未设置" : String(resolved.compressMaxTokens)} tailMessageCount=${String(resolved.tailMessageCount)} omEnabled=${String(resolved.omEnabled)} debug=${String(resolved.debug)}`);
10340
+ logger.step(`apply 启动:observeThresholdTokens=${String(resolved.observeThresholdTokens)} reflectThresholdTokens=${String(resolved.reflectThresholdTokens)} compressMaxTokens=${resolved.compressMaxTokens === void 0 ? "未设置" : String(resolved.compressMaxTokens)} tailMessageCount=${String(resolved.tailMessageCount)} omEnabled=${String(resolved.omEnabled)} debug=${String(resolved.debug)} compressProvider=${resolved.compressProvider ?? "跟随会话路由"} compressModel=${resolved.compressModel ?? "跟随会话路由"} compressReasoningEffort=${resolved.compressReasoningEffort ?? "模型默认"}`);
10149
10341
  if (resolved.recallEnabled) ctx.tools.register(buildRecallTool(() => ctx.get("toolResultPruner")));
10150
10342
  if (resolved.semanticRecallEnabled) {
10151
10343
  const warnModel = (message) => ctx.logger.warn(`dsh-plugin-om: ${message}`);
package/dist/types.d.ts CHANGED
@@ -81,6 +81,8 @@ export type CompactionSummaryPayload = SessionEventMap['compaction/summary'] & {
81
81
  completedAt?: number;
82
82
  /** 压缩循环总耗时(毫秒)。 */
83
83
  durationMs?: number;
84
+ /** 摘要请求实际使用的思考等级(未配置或降级为模型默认时缺失)。 */
85
+ reasoningEffort?: string;
84
86
  };
85
87
  /**
86
88
  * 插件扩展的 compaction/end 载荷:宿主类型 + diagnosticSessionId(最后一次摘要尝试
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-plugin-om",
3
- "version": "0.0.36",
3
+ "version": "0.0.38",
4
4
  "type": "module",
5
5
  "main": "./dist/index.mjs",
6
6
  "module": "./dist/index.mjs",