dsh-plugin-om 0.0.33 → 0.0.35

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
@@ -10,8 +10,8 @@
10
10
  - **工具驱动压缩**:摘要生成走多轮工具会话,模型经 getHistory 查看区间条目、compressHistory 分批替换 assistant 条目、completeCompression 结束。首条消息仅含压缩指令与 index 区间,不含历史内容。用户消息与系统消息不可压缩且原样保留;未压缩条目原样保留,条目正文一律以 CDATA 包裹;skill 加载条目以 `<skill_content name="…" index="…">` 元素呈现,内含 `<skill_resources>` 与 `<skill_instructions>` 两段,首次压缩时要求模型再次确认相关性,压缩后变为常规 assistant 摘要条目。最终 `<history>` 块由插件构建,天然合法无需校验
11
11
  - **压缩会话记录**:每次压缩的工具循环完整对话与压缩统计(起止时间、总耗时、逐轮请求耗时与 token usage 及合计)落盘为 one-shot 子会话,成功为会话记录、失败为失败日志,便于查看模型实际的查看与压缩行为及其 token 成本。主会话日志只保留汇总:`compaction/summary` 携带 usage 与起止时间、总耗时,失败路径 `compaction/end` 携带总耗时
12
12
  - **降级容错**:systemPrompt 或 tokenMeter 服务异常时按 0 计继续压缩,问题通过 console 输出与 log-only `om/warning` 会话事件上报,同会话同一问题至多一条
13
- - **recall 工具**:按完整消息 index 区间回看原始会话,含被压缩内容,图片附件随结果保留
14
- - **recall-semantic 工具**:本地嵌入模型 paraphrase-multilingual-MiniLM-L12-v2 按语义检索全部完整消息,只匹配文本,纯图片消息不进候选池
13
+ - **recall 工具**:按完整消息 index 区间回看原始会话,含被压缩内容;输出为 XML 条目序列(`<user_message>`、`<sys>`、`<assistant type="text"|"toolcall">`),正文一律以 CDATA 包裹逐字原样,toolcall 条目内嵌 `<tool-args>`(合法 JSON,仅一层转义)与 `<tool-result>` CDATA 子元素,图片附件随结果保留
14
+ - **recall-semantic 工具**:本地嵌入模型 paraphrase-multilingual-MiniLM-L12-v2 按语义检索全部完整消息,输出与 recall 相同的 XML 条目序列并以 XML 注释标注相似度与命中词;只匹配文本,纯图片消息不进候选池,本次调用自身的 toolcall 不参与检索
15
15
  - **压缩卡片**:浏览器客户端渲染折叠式已压缩卡片、压缩中提示行与可展开的失败错误行
16
16
  - **降级警告行**:浏览器客户端把 om 警告会话事件渲染为可展开的警告行
17
17
 
@@ -21,7 +21,7 @@
21
21
 
22
22
  ## 安装与启用
23
23
 
24
- `$DSH_HOME` 缺省为 `~/.dsh`,profile 描述 dsh 进程的启动模式。
24
+ 本插件适配 dsh 0.1.2-rc.1 及以上版本(客户端压缩卡片依赖宿主 `uiConversation` 服务)。`$DSH_HOME` 缺省为 `~/.dsh`,profile 描述 dsh 进程的启动模式。
25
25
 
26
26
  ```sh
27
27
  dsh plugin --profile <profile> add dsh-plugin-om
@@ -71,6 +71,8 @@ preset-agent 自带 compaction-basic 压缩,阈值为上下文窗口的 80%,
71
71
  | `recallEnabled` | `true` | 是否注册 `recall` 工具 |
72
72
  | `semanticRecallEnabled` | `true` | 是否注册 `recall-semantic` 工具,关闭时不触发模型下载 |
73
73
 
74
+ > 检测到未压缩消息到达观察阈值后,插件会等待至少 tailMessageCount 后再压缩之前的消息,因此这个配置可以影响首次压缩的时机,也可以保留更多的会话信息。
75
+
74
76
  合理设置 `observeThresholdTokens` 和 `compressSkipReasoning`:
75
77
  - 若模型 reasoning 输出质量差且会把关键结论以 text 形式输出(例如glm和deepseek),无需携带reasoning
76
78
  - 若使用 openai/responses 或 anthropic/messages API,reasoning 内容包含大量决策信息,建议携带reasoning
@@ -108,6 +110,7 @@ src/
108
110
  ├── rate-limit.ts # 全局 429 限流冷却门,进程级共享状态
109
111
  ├── log-index.ts # 完整消息索引与渲染,recall 与压缩共用同一套编号
110
112
  ├── recall.ts # recall 工具:按完整消息 index 区间回看
113
+ ├── recall-xml.ts # 完整消息到 CDATA 包裹 XML 条目的渲染(recall 系工具共用)
111
114
  ├── recall-output.ts # recall 输出契约:{ text, images } 与 render 投影
112
115
  ├── semantic-recall.ts # recall-semantic 工具:本地嵌入语义检索
113
116
  ├── embedding.ts # 本地 ONNX 嵌入:懒加载、批量、运行时按需下载编排
@@ -5,7 +5,7 @@
5
5
  * 卡片报告模型从何处起不再看到那段历史;summary 留在加载窗口外时行不可展开。
6
6
  * 压缩失败节点渲染为可展开的错误行:折叠行显示错误摘要,展开体显示完整报错。
7
7
  */
8
- import type { ChatNode } from '@deepseek-ai/dsh-client-ui-conversation/client';
8
+ import type { ChatNode } from '@deepseek-ai/dsh-client-ui-chat/client';
9
9
  import type { TranslateNS } from '@deepseek-ai/dsh-client-ui-slots';
10
10
  /** Keyed renderer props: 装配好的卡片节点 + 绑定 `om-compaction` 命名空间的 locale 座。 */
11
11
  export interface OmCompactionCardProps {
@@ -1 +1 @@
1
- {"version":3,"file":"OmCompactionCard.d.ts","sourceRoot":"","sources":["../../src/client/OmCompactionCard.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gDAAgD,CAAC;AAE/E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAKpE,0EAA0E;AAC1E,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAC;IACzC,QAAQ,CAAC,CAAC,EAAE,WAAW,CAAC,eAAe,CAAC,CAAC;CAC1C;AAgCD,yCAAyC;AACzC,eAAO,MAAM,gBAAgB,oDAA+C,qBAAqB,iCAsH/F,CAAC"}
1
+ {"version":3,"file":"OmCompactionCard.d.ts","sourceRoot":"","sources":["../../src/client/OmCompactionCard.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wCAAwC,CAAC;AAEvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAKpE,0EAA0E;AAC1E,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAC;IACzC,QAAQ,CAAC,CAAC,EAAE,WAAW,CAAC,eAAe,CAAC,CAAC;CAC1C;AAgCD,yCAAyC;AACzC,eAAO,MAAM,gBAAgB,oDAA+C,qBAAqB,iCAsH/F,CAAC"}
@@ -3,7 +3,7 @@
3
3
  * 折叠行显示降级说明摘要,展开体显示完整说明;数据来自 om/warning 信封载荷
4
4
  * (借用 feedback/record),服务端按会话同问题去重后追加(每会话同一问题至多一行)。
5
5
  */
6
- import type { ChatNode } from '@deepseek-ai/dsh-client-ui-conversation/client';
6
+ import type { ChatNode } from '@deepseek-ai/dsh-client-ui-chat/client';
7
7
  import type { TranslateNS } from '@deepseek-ai/dsh-client-ui-slots';
8
8
  /** Keyed renderer props: 装配好的警告行节点 + 绑定 `om-compaction` 命名空间的 locale 座。 */
9
9
  export interface OmWarningCardProps {
@@ -1 +1 @@
1
- {"version":3,"file":"OmWarningCard.d.ts","sourceRoot":"","sources":["../../src/client/OmWarningCard.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gDAAgD,CAAC;AAE/E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAIpE,2EAA2E;AAC3E,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC;IACtC,QAAQ,CAAC,CAAC,EAAE,WAAW,CAAC,eAAe,CAAC,CAAC;CAC1C;AAED,oCAAoC;AACpC,eAAO,MAAM,aAAa,oDAA4C,kBAAkB,iCAqCtF,CAAC"}
1
+ {"version":3,"file":"OmWarningCard.d.ts","sourceRoot":"","sources":["../../src/client/OmWarningCard.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wCAAwC,CAAC;AAEvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAIpE,2EAA2E;AAC3E,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC;IACtC,QAAQ,CAAC,CAAC,EAAE,WAAW,CAAC,eAAe,CAAC,CAAC;CAC1C;AAED,oCAAoC;AACpC,eAAO,MAAM,aAAa,oDAA4C,kBAAkB,iCAqCtF,CAAC"}
@@ -8,13 +8,13 @@
8
8
  * 宿主的 'compact' 检查点由宿主自己渲染,本定义不认领
9
9
  * (双方共存无视觉冲突:宿主无检查点证据时不产出节点)。
10
10
  */
11
- import type { ConversationMatch, ConversationNodeDefinition } from '@deepseek-ai/dsh-client-runtime/client';
11
+ import type { ConversationMatch, ConversationNodeDefinition } from '@deepseek-ai/dsh-client-ui-conversation/client';
12
12
  import type { SessionEvent } from '@deepseek-ai/dsh-session/types';
13
13
  /** 压缩卡片渲染器分发键(合并进 ChatNodeDataMap)。 */
14
14
  export declare const COMPACTION_CARD_KIND = "om-compaction";
15
15
  /** 功能降级警告行渲染器分发键(合并进 ChatNodeDataMap)。 */
16
16
  export declare const OM_WARNING_CARD_KIND = "om-warning";
17
- declare module '@deepseek-ai/dsh-client-ui-conversation/client' {
17
+ declare module '@deepseek-ai/dsh-client-ui-chat/client' {
18
18
  interface ChatNodeDataMap {
19
19
  /** dsh-plugin-om 压缩替换检查点渲染的摘要卡片数据。 */
20
20
  'om-compaction': OmCompactionChatData;
@@ -1 +1 @@
1
- {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/client/definition.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EACV,iBAAiB,EAEjB,0BAA0B,EAC3B,MAAM,wCAAwC,CAAC;AAGhD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAKnE,uCAAuC;AACvC,eAAO,MAAM,oBAAoB,kBAAkB,CAAC;AAEpD,0CAA0C;AAC1C,eAAO,MAAM,oBAAoB,eAAe,CAAC;AAEjD,OAAO,QAAQ,gDAAgD,CAAC;IAC9D,UAAU,eAAe;QACvB,sCAAsC;QACtC,eAAe,EAAE,oBAAoB,CAAC;QACtC,+BAA+B;QAC/B,YAAY,EAAE,iBAAiB,CAAC;KACjC;CACF;AAED,wBAAwB;AACxB,MAAM,WAAW,oBAAoB;IACnC,0DAA0D;IAC1D,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,oDAAoD;IACpD,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,GAAG,IAAI,CAAC;IAC7C,4DAA4D;IAC5D,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,gDAAgD;IAChD,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,0CAA0C;IAC1C,QAAQ,CAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,4CAA4C;IAC5C,QAAQ,CAAC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3C,8BAA8B;IAC9B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,6CAA6C;IAC7C,QAAQ,CAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,4DAA4D;IAC5D,QAAQ,CAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,yDAAyD;IACzD,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,kDAAkD;AAClD,UAAU,iBAAiB;IACzB,QAAQ,CAAC,OAAO,CAAC,EAAE,iBAAiB,CAAC;IACrC,QAAQ,CAAC,UAAU,CAAC,EAAE,iBAAiB,CAAC;IACxC,8DAA8D;IAC9D,QAAQ,CAAC,GAAG,CAAC,EAAE,iBAAiB,CAAC;CAClC;AAgBD;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,GAAG,SAAS,CAe9E;AA6HD;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,EAAE,0BAA0B,CAAC,iBAAiB,CAqEhF,CAAC;AAEF,+CAA+C;AAC/C,MAAM,WAAW,iBAAiB;IAChC,uCAAuC;IACvC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,0CAA0C;IAC1C,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,0BAmBjC,CAAC"}
1
+ {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/client/definition.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EACV,iBAAiB,EAEjB,0BAA0B,EAC3B,MAAM,gDAAgD,CAAC;AAExD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAKnE,uCAAuC;AACvC,eAAO,MAAM,oBAAoB,kBAAkB,CAAC;AAEpD,0CAA0C;AAC1C,eAAO,MAAM,oBAAoB,eAAe,CAAC;AAEjD,OAAO,QAAQ,wCAAwC,CAAC;IACtD,UAAU,eAAe;QACvB,sCAAsC;QACtC,eAAe,EAAE,oBAAoB,CAAC;QACtC,+BAA+B;QAC/B,YAAY,EAAE,iBAAiB,CAAC;KACjC;CACF;AAED,wBAAwB;AACxB,MAAM,WAAW,oBAAoB;IACnC,0DAA0D;IAC1D,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,oDAAoD;IACpD,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,GAAG,IAAI,CAAC;IAC7C,4DAA4D;IAC5D,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,gDAAgD;IAChD,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,0CAA0C;IAC1C,QAAQ,CAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,4CAA4C;IAC5C,QAAQ,CAAC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3C,8BAA8B;IAC9B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,6CAA6C;IAC7C,QAAQ,CAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,4DAA4D;IAC5D,QAAQ,CAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,yDAAyD;IACzD,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,kDAAkD;AAClD,UAAU,iBAAiB;IACzB,QAAQ,CAAC,OAAO,CAAC,EAAE,iBAAiB,CAAC;IACrC,QAAQ,CAAC,UAAU,CAAC,EAAE,iBAAiB,CAAC;IACxC,8DAA8D;IAC9D,QAAQ,CAAC,GAAG,CAAC,EAAE,iBAAiB,CAAC;CAClC;AAgBD;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,GAAG,SAAS,CAe9E;AA6HD;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,EAAE,0BAA0B,CAAC,iBAAiB,CAqEhF,CAAC;AAEF,+CAA+C;AAC/C,MAAM,WAAW,iBAAiB;IAChC,uCAAuC;IACvC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,0CAA0C;IAC1C,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,0BAmBjC,CAAC"}
@@ -6,7 +6,7 @@
6
6
  * feedback/record)渲染为「功能降级」警告行。
7
7
  */
8
8
  import type { Context } from '@deepseek-ai/cordis';
9
- /** Required services: 聊天节点槽、会话事件注册表与 locale 服务。 */
9
+ /** Required services: 聊天节点槽、uiConversation 会话定义注册表与 locale 服务。 */
10
10
  export declare const inject: string[];
11
11
  /** Client plugin body: 注册压缩卡片的业务定义与 keyed 渲染器(随插件卸载移除)。 */
12
12
  export declare function apply(ctx: Context): void;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAYnD,mDAAmD;AACnD,eAAO,MAAM,MAAM,UAA4C,CAAC;AAEhE,2DAA2D;AAC3D,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAyBxC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAYnD,kEAAkE;AAClE,eAAO,MAAM,MAAM,UAAwC,CAAC;AAE5D,2DAA2D;AAC3D,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAyBxC"}
package/dist/client.js CHANGED
@@ -467,10 +467,10 @@ window.__ModuleLoader__.load({
467
467
  const bodyStyle = { whiteSpace: "pre-wrap" };
468
468
  //#endregion
469
469
  //#region src/client/index.ts
470
- /** Required services: 聊天节点槽、会话事件注册表与 locale 服务。 */
470
+ /** Required services: 聊天节点槽、uiConversation 会话定义注册表与 locale 服务。 */
471
471
  const inject = [
472
472
  "slots",
473
- "conversationEvents",
473
+ "uiConversation",
474
474
  "locale"
475
475
  ];
476
476
  /** Client plugin body: 注册压缩卡片的业务定义与 keyed 渲染器(随插件卸载移除)。 */
@@ -479,8 +479,8 @@ window.__ModuleLoader__.load({
479
479
  zh,
480
480
  en
481
481
  }), "dsh-plugin-om: compaction card dictionaries");
482
- ctx.effect(() => ctx.conversationEvents.register(omCompactionDefinition), "dsh-plugin-om: compaction definition");
483
- ctx.effect(() => ctx.conversationEvents.register(omWarningDefinition), "dsh-plugin-om: om warning definition");
482
+ ctx.effect(() => ctx.uiConversation.events.register(omCompactionDefinition), "dsh-plugin-om: compaction definition");
483
+ ctx.effect(() => ctx.uiConversation.events.register(omWarningDefinition), "dsh-plugin-om: om warning definition");
484
484
  ctx.slots.inject("conversation.chat.node", () => ctx.slots.register({
485
485
  name: "conversation.chat.node",
486
486
  key: "om-compaction",
@@ -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包裹的纯文本;<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 return { kind: omKind, data: rest, seq: event.seq } 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.events) {\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 {\n ConversationMatch,\n ConversationNodeContext,\n ConversationNodeDefinition,\n} from '@deepseek-ai/dsh-client-runtime/client';\nimport type { ChatNode, ChatNodeDataMap } 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-conversation/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: ChatNodeDataMap[Kind],\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-conversation/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-conversation/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: 拉取 runtime 的 Context 合并(ctx.conversationEvents)。\nimport type {} from '@deepseek-ai/dsh-client-runtime/client';\n// Type-only: 'conversation.chat.node' 的 SlotMap 行与 ChatNodeDataMap 声明合并。\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/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: 聊天节点槽、会话事件注册表与 locale 服务。 */\nexport const inject = ['slots', 'conversationEvents', '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.conversationEvents.register(omCompactionDefinition),\n 'dsh-plugin-om: compaction definition',\n );\n ctx.effect(\n () => ctx.conversationEvents.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 * 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包裹的纯文本;<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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"}
@@ -70,10 +70,9 @@ export declare function buildObserveView(session: Session, seqs: readonly number
70
70
  /** 提取 <history> 块的内文(去开/闭标签;非块文本原样返回)。 */
71
71
  export declare function historyInner(text: string): string;
72
72
  /**
73
- * 向元素追加 CDATA 正文:正文统一以 CDATA 包裹(逐字原样,不做实体转义)。
74
- * 正文含 ]]> 时拆为相邻多个 CDATA 段,拼接后逐字还原原文,对读取方透明。
73
+ * 向元素追加 CDATA 正文(实现在 utils.ts,此处再导出保持既有导入路径)。
75
74
  */
76
- export declare function appendCdataText(doc: Document, el: Element, text: string): void;
75
+ export { appendCdataText } from './utils.ts';
77
76
  /**
78
77
  * 反思视图:全部 <history> 块(historySection 收集,按表层顺序)的内条目投影为条目。
79
78
  * 要求区间为全部块内条目引用的最小 / 最大 index;块解析失败降级为不可定位遗留条目;
@@ -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;AAIxD,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,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,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,CAmEjB;AAiBD,0CAA0C;AAC1C,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASjD;AAyCD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAW9E;AAsFD;;;;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,CAkDvE;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;AAIxD,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,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,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,CAmEjB;AAiBD,0CAA0C;AAC1C,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASjD;AAyCD;;GAEG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAsF7C;;;;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,CAkDvE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,MAAM,CAO7D"}
@@ -1 +1 @@
1
- {"version":3,"file":"compress.d.ts","sourceRoot":"","sources":["../src/compress.ts"],"names":[],"mappings":"AAmDA,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,CA8BpE;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;AAgID;;;;;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":"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"}
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { scopeOf } from "@deepseek-ai/dsh-scope";
2
+ import { SessionId, SessionSeq } from "@deepseek-ai/dsh-session";
2
3
  import { renderPrompt } from "@deepseek-ai/dsh-system-prompt";
3
4
  import { BlockAssembler, createToolResultMessage } from "@deepseek-ai/dsh-llm";
4
- import { SessionId } from "@deepseek-ai/dsh-session";
5
5
  import { SUBAGENT_DESCRIPTOR_VERSION } from "@deepseek-ai/dsh-subagent";
6
6
  import { copyFileSync, existsSync, mkdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
7
7
  import { homedir } from "node:os";
@@ -99,7 +99,7 @@ function renderMessageText(message) {
99
99
  const parts = [];
100
100
  for (const block of message.content) if (block.type === "text") parts.push(block.text);
101
101
  else if (block.type === "tool-call") parts.push(`[tool-call ${block.name} id=${String(block.id)}]
102
- ${safeJson(block.arguments)}`);
102
+ ${toolArgsJson(block.arguments)}`);
103
103
  else if (block.type === "tool-result") parts.push(blocksToText(block.content));
104
104
  return parts.join("\n");
105
105
  }
@@ -111,6 +111,27 @@ function safeJson(value) {
111
111
  return String(value);
112
112
  }
113
113
  }
114
+ /**
115
+ * 工具调用参数的 JSON 文本(CDATA 内保持只有一层 JSON 转义):
116
+ * 字符串参数是模型产出的原始 JSON 串,原样返回(本身即合法 JSON,不再二次序列化);
117
+ * 其余结构 JSON.stringify 序列化一次。
118
+ */
119
+ function toolArgsJson(args) {
120
+ if (typeof args === "string") return args;
121
+ return safeJson(args);
122
+ }
123
+ /**
124
+ * 向元素追加 CDATA 正文:正文统一以 CDATA 包裹(逐字原样,不做实体转义)。
125
+ * 正文含 ]]> 时拆为相邻多个 CDATA 段,拼接后逐字还原原文,对读取方透明。
126
+ */
127
+ function appendCdataText(doc, el, text) {
128
+ const parts = text.split("]]>");
129
+ for (let i = 0; i < parts.length; i += 1) if (i === 0) el.appendChild(doc.createCDATASection(parts[0] ?? ""));
130
+ else {
131
+ el.appendChild(doc.createCDATASection("]]"));
132
+ el.appendChild(doc.createCDATASection(`>${parts[i] ?? ""}`));
133
+ }
134
+ }
114
135
  /** 主会话判定:subagent 会话 header.origin === 'subagent'。 */
115
136
  function isMainSession(session) {
116
137
  return session.header?.origin !== "subagent";
@@ -7388,7 +7409,8 @@ var import_lib = (/* @__PURE__ */ __commonJSMin(((exports) => {
7388
7409
  * 会话日志索引:完整消息索引与渲染。
7389
7410
  * 导出 indexCompleteMessages(完整消息四类折叠索引,recall 与摘要共用同一套编号)、
7390
7411
  * indexMessages / surfaceIndexOf / messageIdOfEvent(消息级定位辅助)、
7391
- * collectImageRefs / toolResultMessageOf / renderToolResultText / renderCompleteMessageParts /
7412
+ * collectImageRefs / toolCallBlockOf / toolResultMessageOf / renderToolResultText /
7413
+ * renderCompleteMessageParts /
7392
7414
  * renderCompleteMessage(完整消息渲染与图片附件收集)。事件日志仅追加(被遮蔽的事件仍可读,
7393
7415
  * recall 依赖此性质)。
7394
7416
  *
@@ -7409,7 +7431,7 @@ function surfaceIndexOf(nodes, seq) {
7409
7431
  function indexCompleteMessages(session) {
7410
7432
  const cms = [];
7411
7433
  const pending = /* @__PURE__ */ new Map();
7412
- const events = session.events;
7434
+ const events = session.snapshotEvents();
7413
7435
  for (let seq = 0; seq < events.length; seq += 1) {
7414
7436
  const event = events[seq];
7415
7437
  if (!event) continue;
@@ -7491,13 +7513,26 @@ function collectImageRefs(content, out) {
7491
7513
  }
7492
7514
  }
7493
7515
  /**
7516
+ * 取 toolcall 完整消息对应的 tool-call 块(调用参数渲染与 XML 条目渲染共用):
7517
+ * 非 toolcall、调用事件缺失或块内 id 不匹配时返回 undefined。
7518
+ */
7519
+ function toolCallBlockOf(session, cm) {
7520
+ if (cm.type !== "toolcall") return void 0;
7521
+ const callSeq = cm.seqs[0];
7522
+ const callEvent = callSeq === void 0 ? void 0 : session.snapshotEvents()[callSeq];
7523
+ if (callEvent?.type !== "assistant/message") return void 0;
7524
+ const message = session.deriveEventMessage(callEvent);
7525
+ if (!message || !Array.isArray(message.content)) return void 0;
7526
+ for (const block of message.content) if (block.type === "tool-call" && String(block.id ?? "") === (cm.callId ?? "")) return block;
7527
+ }
7528
+ /**
7494
7529
  * 取 toolcall 完整消息的 tool/result 消息(超大结果经 pruner 裁剪):
7495
7530
  * 结果文本渲染与 <skill> 条目正文共用;非 toolcall 或无配对 result 时返回 undefined。
7496
7531
  */
7497
7532
  function toolResultMessageOf(session, cm, pruner) {
7498
7533
  if (cm.type !== "toolcall") return void 0;
7499
7534
  const resultSeq = cm.seqs[1];
7500
- const resultEvent = resultSeq === void 0 ? void 0 : session.events[resultSeq];
7535
+ const resultEvent = resultSeq === void 0 ? void 0 : session.snapshotEvents()[resultSeq];
7501
7536
  if (resultEvent?.type !== "tool/result") return void 0;
7502
7537
  const message = session.deriveEventMessage(resultEvent);
7503
7538
  if (!message) return void 0;
@@ -7521,7 +7556,7 @@ function renderCompleteMessageParts(session, cm, pruner) {
7521
7556
  const images = [];
7522
7557
  if (cm.type === "user" || cm.type === "sys") {
7523
7558
  const seq = cm.seqs[0];
7524
- const event = seq === void 0 ? void 0 : session.events[seq];
7559
+ const event = seq === void 0 ? void 0 : session.snapshotEvents()[seq];
7525
7560
  const message = event ? session.deriveEventMessage(event) : null;
7526
7561
  if (message && Array.isArray(message.content)) collectImageRefs(message.content, images);
7527
7562
  return {
@@ -7531,7 +7566,7 @@ function renderCompleteMessageParts(session, cm, pruner) {
7531
7566
  }
7532
7567
  if (cm.type === "assistant") {
7533
7568
  const seq = cm.seqs[0];
7534
- const event = seq === void 0 ? void 0 : session.events[seq];
7569
+ const event = seq === void 0 ? void 0 : session.snapshotEvents()[seq];
7535
7570
  const message = event ? session.deriveEventMessage(event) : null;
7536
7571
  if (!message || !Array.isArray(message.content)) return {
7537
7572
  text: "",
@@ -7546,19 +7581,8 @@ function renderCompleteMessageParts(session, cm, pruner) {
7546
7581
  };
7547
7582
  }
7548
7583
  const parts = [];
7549
- const callSeq = cm.seqs[0];
7550
- const callEvent = callSeq === void 0 ? void 0 : session.events[callSeq];
7551
- if (callEvent?.type === "assistant/message") {
7552
- const message = session.deriveEventMessage(callEvent);
7553
- if (message && Array.isArray(message.content)) {
7554
- let call;
7555
- for (const block of message.content) if (block.type === "tool-call" && String(block.id ?? "") === (cm.callId ?? "")) {
7556
- call = block;
7557
- break;
7558
- }
7559
- if (call) parts.push(`[tool-call ${String(call.name ?? "")} id=${String(call.id ?? "")}]\n${safeJson(call.arguments)}`);
7560
- }
7561
- }
7584
+ const call = toolCallBlockOf(session, cm);
7585
+ if (call) parts.push(`[tool-call ${String(call.name ?? "")} id=${String(call.id ?? "")}]\n${toolArgsJson(call.arguments)}`);
7562
7586
  const resultMessage = toolResultMessageOf(session, cm, pruner);
7563
7587
  if (resultMessage && Array.isArray(resultMessage.content)) {
7564
7588
  collectImageRefs(resultMessage.content, images);
@@ -7577,7 +7601,7 @@ function renderCompleteMessage(session, cm, pruner) {
7577
7601
  //#endregion
7578
7602
  //#region src/compress-view.ts
7579
7603
  /** 静默 DOMParser:非致命解析问题不刷 console,fatalError 仍抛 ParseError、解析语义不变。 */
7580
- function newQuietParser() {
7604
+ function newQuietParser$1() {
7581
7605
  return new import_lib.DOMParser({ onError: () => {} });
7582
7606
  }
7583
7607
  /**
@@ -7586,7 +7610,7 @@ function newQuietParser() {
7586
7610
  */
7587
7611
  function userEntryParts(session, cm) {
7588
7612
  const seq = cm.seqs[0];
7589
- const event = seq === void 0 ? void 0 : session.events[seq];
7613
+ const event = seq === void 0 ? void 0 : session.snapshotEvents()[seq];
7590
7614
  const message = event ? session.deriveEventMessage(event) : null;
7591
7615
  if (!message || !Array.isArray(message.content)) return null;
7592
7616
  const texts = [];
@@ -7611,7 +7635,7 @@ function userEntryParts(session, cm) {
7611
7635
  function toolCallNameOf(session, cm) {
7612
7636
  if (cm.type !== "toolcall") return void 0;
7613
7637
  const seq = cm.seqs[0];
7614
- const event = seq === void 0 ? void 0 : session.events[seq];
7638
+ const event = seq === void 0 ? void 0 : session.snapshotEvents()[seq];
7615
7639
  if (event?.type !== "assistant/message") return void 0;
7616
7640
  const message = event.data.message;
7617
7641
  if (!message || !Array.isArray(message.content)) return void 0;
@@ -7624,7 +7648,7 @@ function toolCallNameOf(session, cm) {
7624
7648
  function skillNameOf(session, cm) {
7625
7649
  if (toolCallNameOf(session, cm) !== "skill") return void 0;
7626
7650
  const seq = cm.seqs[0];
7627
- const event = seq === void 0 ? void 0 : session.events[seq];
7651
+ const event = seq === void 0 ? void 0 : session.snapshotEvents()[seq];
7628
7652
  if (event?.type !== "assistant/message") return "";
7629
7653
  const message = event.data.message;
7630
7654
  if (!message || !Array.isArray(message.content)) return "";
@@ -7648,7 +7672,7 @@ function buildObserveView(session, seqs, options = {}) {
7648
7672
  const shadowed = new Set(seqs);
7649
7673
  const reasoningBySeq = /* @__PURE__ */ new Map();
7650
7674
  for (const seq of seqs) {
7651
- const event = session.events[seq];
7675
+ const event = session.snapshotEvents()[seq];
7652
7676
  if (event?.type !== "assistant/message") continue;
7653
7677
  const message = event.data.message;
7654
7678
  if (!message || !Array.isArray(message.content)) continue;
@@ -7774,18 +7798,6 @@ function skillContentSections(text) {
7774
7798
  };
7775
7799
  }
7776
7800
  /**
7777
- * 向元素追加 CDATA 正文:正文统一以 CDATA 包裹(逐字原样,不做实体转义)。
7778
- * 正文含 ]]> 时拆为相邻多个 CDATA 段,拼接后逐字还原原文,对读取方透明。
7779
- */
7780
- function appendCdataText(doc, el, text) {
7781
- const parts = text.split("]]>");
7782
- for (let i = 0; i < parts.length; i += 1) if (i === 0) el.appendChild(doc.createCDATASection(parts[0] ?? ""));
7783
- else {
7784
- el.appendChild(doc.createCDATASection("]]"));
7785
- el.appendChild(doc.createCDATASection(`>${parts[i] ?? ""}`));
7786
- }
7787
- }
7788
- /**
7789
7801
  * 解析一个已有 <history> 块的内条目(反思视图):user_message / sys / assistant
7790
7802
  * (index 单条或 start/end 区间)/ skill_content(name 属性 + index 定位)/ reasoning。
7791
7803
  * 整块无法解析或根非 <history> 时降级为单条不可定位的历史遗留条目(text 为块内文原文,
@@ -7799,7 +7811,7 @@ function parseBlockEntries(blockText, blockSeq) {
7799
7811
  }];
7800
7812
  let doc;
7801
7813
  try {
7802
- doc = newQuietParser().parseFromString(blockText, "text/xml");
7814
+ doc = newQuietParser$1().parseFromString(blockText, "text/xml");
7803
7815
  } catch {
7804
7816
  return opaque();
7805
7817
  }
@@ -7948,7 +7960,7 @@ function entryToElement(doc, entry) {
7948
7960
  */
7949
7961
  function renderEntriesXml(entries) {
7950
7962
  if (entries.length === 0) return "";
7951
- const doc = newQuietParser().parseFromString("<root />", "text/xml");
7963
+ const doc = newQuietParser$1().parseFromString("<root />", "text/xml");
7952
7964
  const serializer = new import_lib.XMLSerializer();
7953
7965
  return entries.map((entry) => serializer.serializeToString(entryToElement(doc, entry))).join("\n");
7954
7966
  }
@@ -8655,7 +8667,7 @@ function appendOmEvent(session, kind, data) {
8655
8667
  }
8656
8668
  function findOmEvents(session, kind) {
8657
8669
  const result = [];
8658
- for (const event of session.events) {
8670
+ for (const event of session.snapshotEvents()) {
8659
8671
  const om = readOmEvent(event);
8660
8672
  if (om !== void 0 && (kind === void 0 || om.kind === kind)) result.push(om);
8661
8673
  }
@@ -8794,7 +8806,7 @@ function historyInnerText(text) {
8794
8806
  function isPairBalancedAfter(session, seq) {
8795
8807
  let inProgress = 0;
8796
8808
  for (const node of session.surface.nodes) {
8797
- const event = session.events[node];
8809
+ const event = session.snapshotEvents()[node];
8798
8810
  if (event?.type === "assistant/message") inProgress += event.data.message.content.filter((block) => block.type === "tool-call").length;
8799
8811
  else if (event?.type === "tool/result") inProgress -= 1;
8800
8812
  if (node === seq) return inProgress === 0;
@@ -8811,7 +8823,7 @@ function computeCompressRange(session, endMessageIndex) {
8811
8823
  const surface = [...session.surface.nodes];
8812
8824
  if (surface.length === 0) return void 0;
8813
8825
  const { boundarySeq } = historySection(session);
8814
- const startIdx = boundarySeq === void 0 ? 0 : surface.indexOf(boundarySeq) + 1;
8826
+ const startIdx = boundarySeq === void 0 ? 0 : surface.findIndex((node) => node === boundarySeq) + 1;
8815
8827
  if (startIdx >= surface.length) return void 0;
8816
8828
  const target = indexCompleteMessages(session).find((cm) => cm.index === endMessageIndex);
8817
8829
  if (target === void 0) return void 0;
@@ -8848,7 +8860,7 @@ function historySection(session) {
8848
8860
  const blocks = [];
8849
8861
  let boundarySeq;
8850
8862
  for (const seq of session.surface.nodes) {
8851
- const text = historyTextOf(session.events[seq]);
8863
+ const text = historyTextOf(session.snapshotEvents()[seq]);
8852
8864
  if (text === void 0) continue;
8853
8865
  blocks.push({
8854
8866
  text,
@@ -8869,8 +8881,8 @@ function historySection(session) {
8869
8881
  */
8870
8882
  function findObservePending(session) {
8871
8883
  let pending;
8872
- for (let seq = 0; seq < session.events.length; seq += 1) {
8873
- const event = session.events[seq];
8884
+ for (let seq = 0; seq < session.snapshotEvents().length; seq += 1) {
8885
+ const event = session.snapshotEvents()[seq];
8874
8886
  if (!event) continue;
8875
8887
  const om = readOmEvent(event);
8876
8888
  if (om?.kind === "om/observe-pending") pending = {
@@ -8895,7 +8907,7 @@ function appendObserveInvalidate(session, pendingSeq) {
8895
8907
  /** 当前打开中的 turn 号(最近 turn/start 且未被 turn/end 关闭);无则 null。 */
8896
8908
  function openTurnOf(session) {
8897
8909
  let turn = null;
8898
- for (const event of session.events) if (event.type === "turn/start") turn = event.data.turn;
8910
+ for (const event of session.snapshotEvents()) if (event.type === "turn/start") turn = event.data.turn;
8899
8911
  else if (event.type === "turn/end") turn = null;
8900
8912
  return turn;
8901
8913
  }
@@ -8924,8 +8936,11 @@ function appendCompactionSummary(session, data) {
8924
8936
  type: "text",
8925
8937
  text: data.summary
8926
8938
  }],
8927
- shadowedRange: data.shadowedRange,
8928
- shadowedSeqs: data.shadowedSeqs,
8939
+ shadowedRange: {
8940
+ start: SessionSeq(data.shadowedRange.start),
8941
+ end: SessionSeq(data.shadowedRange.end)
8942
+ },
8943
+ shadowedSeqs: data.shadowedSeqs.map(SessionSeq),
8929
8944
  shadowedTokenCount: data.shadowedTokenCount,
8930
8945
  shadowedCharCount: data.shadowedCharCount,
8931
8946
  provider: data.provider,
@@ -8969,8 +8984,12 @@ function appendHistoryMessage(session, content, sourceEventSeqs, surfaceOp, comp
8969
8984
  }
8970
8985
  };
8971
8986
  session.append("user/message", message, {
8972
- surfaceOp,
8973
- sourceEventSeqs
8987
+ surfaceOp: {
8988
+ op: "replace",
8989
+ start: SessionSeq(surfaceOp.start),
8990
+ end: SessionSeq(surfaceOp.end)
8991
+ },
8992
+ sourceEventSeqs: sourceEventSeqs.map(SessionSeq)
8974
8993
  });
8975
8994
  }
8976
8995
  /**
@@ -9261,7 +9280,7 @@ async function observePass(ctx, agent, config, waitCount, target, signal) {
9261
9280
  const report = summaryResult.text;
9262
9281
  const usage = summaryResult.usage;
9263
9282
  const shadowedTokenCount = replaceSeqs.reduce((total, seq) => {
9264
- const event = session.events[seq];
9283
+ const event = session.snapshotEvents()[seq];
9265
9284
  const message = event ? session.deriveEventMessage(event) : null;
9266
9285
  let tokens = 0;
9267
9286
  if (message) try {
@@ -9272,7 +9291,7 @@ async function observePass(ctx, agent, config, waitCount, target, signal) {
9272
9291
  return total + tokens;
9273
9292
  }, 0);
9274
9293
  const shadowedCharCount = replaceSeqs.reduce((total, seq) => {
9275
- const event = session.events[seq];
9294
+ const event = session.snapshotEvents()[seq];
9276
9295
  const message = event ? session.deriveEventMessage(event) : null;
9277
9296
  return total + (message ? textCharCount(message) : 0);
9278
9297
  }, 0);
@@ -9640,7 +9659,7 @@ const RECALL_OUTPUT_SCHEMA = {
9640
9659
  properties: {
9641
9660
  text: {
9642
9661
  type: "string",
9643
- description: "完整消息内容的文本部分(带图位置以 [图片附件:…] 标注行提示)。"
9662
+ description: "完整消息的 XML 条目序列(CDATA 包裹正文;图片位置以 XML 注释 [图片附件:…] 标注)。"
9644
9663
  },
9645
9664
  images: {
9646
9665
  type: "array",
@@ -9702,12 +9721,112 @@ function renderRecallOutput(value) {
9702
9721
  return blocks;
9703
9722
  }
9704
9723
  //#endregion
9724
+ //#region src/recall-xml.ts
9725
+ /** 静默 DOMParser:非致命解析问题不刷 console。 */
9726
+ function newQuietParser() {
9727
+ return new import_lib.DOMParser({ onError: () => {} });
9728
+ }
9729
+ /** XML 注释文本:注释内不允许连续连字符,`--` 统一替换为破折号。 */
9730
+ function xmlCommentText(text) {
9731
+ return text.replace(/--/g, "——");
9732
+ }
9733
+ /** 向元素追加图片附件注释(每张图片一条,附在元素正文之后)。 */
9734
+ function appendImageComments(doc, el, images) {
9735
+ for (const ref of images) el.appendChild(doc.createComment(` ${xmlCommentText(imageNote(ref))} `));
9736
+ }
9737
+ /** 正文有内容时以 CDATA 追加,无内容时不追加(元素自然自闭合或仅含注释)。 */
9738
+ function appendBodyText(doc, el, text) {
9739
+ if (text !== "") appendCdataText(doc, el, text);
9740
+ }
9741
+ /** toolcall 完整消息的元素:<assistant type="toolcall"> 内嵌 <tool-args> / <tool-result>。 */
9742
+ function toolcallElement(doc, session, cm, pruner, images) {
9743
+ const el = doc.createElement("assistant");
9744
+ el.setAttribute("index", String(cm.index));
9745
+ el.setAttribute("type", "toolcall");
9746
+ const call = toolCallBlockOf(session, cm);
9747
+ const toolName = call === void 0 ? "" : String(call.name ?? "");
9748
+ if (toolName !== "") el.setAttribute("tool-name", toolName);
9749
+ if (cm.callId) el.setAttribute("callId", cm.callId);
9750
+ if (call) {
9751
+ const args = doc.createElement("tool-args");
9752
+ appendCdataText(doc, args, toolArgsJson(call.arguments));
9753
+ el.appendChild(args);
9754
+ }
9755
+ const resultMessage = toolResultMessageOf(session, cm, pruner);
9756
+ if (resultMessage && Array.isArray(resultMessage.content)) {
9757
+ collectImageRefs(resultMessage.content, images);
9758
+ const resultText = renderMessageText(resultMessage);
9759
+ if (resultText.trim() !== "") {
9760
+ const result = doc.createElement("tool-result");
9761
+ appendCdataText(doc, result, resultText);
9762
+ el.appendChild(result);
9763
+ }
9764
+ }
9765
+ appendImageComments(doc, el, images);
9766
+ return el;
9767
+ }
9768
+ /** 按完整消息类别构建元素(user / sys / assistant 文本条目复用 parts 渲染)。 */
9769
+ function buildElement(doc, session, cm, pruner, images) {
9770
+ if (cm.type === "toolcall") return toolcallElement(doc, session, cm, pruner, images);
9771
+ const parts = renderCompleteMessageParts(session, cm, pruner);
9772
+ images.push(...parts.images);
9773
+ if (cm.type === "sys") {
9774
+ const el = doc.createElement("sys");
9775
+ el.setAttribute("index", String(cm.index));
9776
+ if (cm.kind !== void 0) el.setAttribute("type", cm.kind);
9777
+ appendBodyText(doc, el, parts.text);
9778
+ appendImageComments(doc, el, parts.images);
9779
+ return el;
9780
+ }
9781
+ const el = doc.createElement(cm.type === "user" ? "user_message" : "assistant");
9782
+ el.setAttribute("index", String(cm.index));
9783
+ if (cm.type === "assistant") el.setAttribute("type", "text");
9784
+ appendBodyText(doc, el, parts.text);
9785
+ appendImageComments(doc, el, parts.images);
9786
+ return el;
9787
+ }
9788
+ /** 主渲染失败时的回退元素:按完整消息类别输出最简形态,正文为回退文本。 */
9789
+ function fallbackElement(doc, cm, text) {
9790
+ if (cm.type === "sys") {
9791
+ const el = doc.createElement("sys");
9792
+ el.setAttribute("index", String(cm.index));
9793
+ if (cm.kind !== void 0) el.setAttribute("type", cm.kind);
9794
+ return el;
9795
+ }
9796
+ const el = doc.createElement(cm.type === "user" ? "user_message" : "assistant");
9797
+ el.setAttribute("index", String(cm.index));
9798
+ if (cm.type !== "user") el.setAttribute("type", cm.type === "toolcall" ? "toolcall" : "text");
9799
+ appendBodyText(doc, el, text);
9800
+ return el;
9801
+ }
9802
+ /**
9803
+ * 渲染一条完整消息为 XML 条目(序列化后的字符串)与其携带的图片附件元数据。
9804
+ * 主渲染失败且提供 fallbackText 时降级为最简元素;两者皆不可用时向上抛出,
9805
+ * 由调用方决定跳过或回退。
9806
+ */
9807
+ function renderCompleteMessageXml(session, cm, options = {}) {
9808
+ const images = [];
9809
+ const doc = newQuietParser().parseFromString("<root />", "text/xml");
9810
+ let el;
9811
+ try {
9812
+ el = buildElement(doc, session, cm, options.pruner, images);
9813
+ } catch (error) {
9814
+ if (options.fallbackText === void 0) throw error;
9815
+ images.length = 0;
9816
+ el = fallbackElement(doc, cm, options.fallbackText);
9817
+ }
9818
+ return {
9819
+ xml: new import_lib.XMLSerializer().serializeToString(el),
9820
+ images
9821
+ };
9822
+ }
9823
+ //#endregion
9705
9824
  //#region src/recall.ts
9706
9825
  /**
9707
9826
  * recall 工具:按完整消息 index 区间回看原始会话(含被压缩内容)。
9708
9827
  * 导出 recallArgsSchema / RecallArgs / parseRecallArgs / buildRecallTool。
9709
- * 输出值为 { text, images }(契约见 recall-output.ts);recall 自身不设输出上限,
9710
- * 超大工具结果由 tool-result-pruner 裁剪。
9828
+ * 输出值为 { text, images }(契约见 recall-output.ts),text 为 XML 条目序列
9829
+ * (形态见 recall-xml.ts);recall 自身不设输出上限,超大工具结果由 tool-result-pruner 裁剪。
9711
9830
  */
9712
9831
  /**
9713
9832
  * recall 工具参数 schema:start 必填;end 与 offset 至少提供一个(同时给出时 end 优先)。
@@ -9731,7 +9850,7 @@ function parseRecallArgs(raw) {
9731
9850
  function buildRecallTool(getPruner) {
9732
9851
  return {
9733
9852
  name: "recall",
9734
- description: `${COMPLETE_MESSAGE_DEFINITION}按 index 区间精确返回区间内全部完整消息的内容。`,
9853
+ description: `在你需要查看历史消息时调用。${COMPLETE_MESSAGE_DEFINITION}此工具按 index 区间精确返回区间内全部完整消息的内容。`,
9735
9854
  parameters: parametersFromZod(recallArgsSchema),
9736
9855
  output: {
9737
9856
  schema: RECALL_OUTPUT_SCHEMA,
@@ -9762,24 +9881,15 @@ function buildRecallTool(getPruner) {
9762
9881
  for (let i = lo; i <= hi; i += 1) {
9763
9882
  const cm = cms[i];
9764
9883
  if (!cm) continue;
9765
- let text = "";
9766
- let cmImages = [];
9767
9884
  try {
9768
- const rendered = renderCompleteMessageParts(session, cm, pruner);
9769
- text = rendered.text;
9770
- cmImages = rendered.images;
9885
+ const rendered = renderCompleteMessageXml(session, cm, { pruner });
9886
+ parts.push(rendered.xml);
9887
+ images.push(...rendered.images);
9771
9888
  } catch {}
9772
- const callAttr = cm.type === "toolcall" && cm.callId ? ` callId=${cm.callId}` : "";
9773
- let body = text;
9774
- if (cmImages.length > 0) {
9775
- body += (body === "" ? "" : "\n") + cmImages.map(imageNote).join("\n");
9776
- images.push(...cmImages);
9777
- }
9778
- parts.push(`-- [index ${cm.index}] ${cm.type}${callAttr} --\n${body}`);
9779
9889
  }
9780
9890
  if (parts.length === 0) return textOnly("指定区间没有完整消息");
9781
9891
  return {
9782
- text: parts.join("\n\n"),
9892
+ text: parts.join("\n"),
9783
9893
  images
9784
9894
  };
9785
9895
  }
@@ -9794,7 +9904,9 @@ function buildRecallTool(getPruner) {
9794
9904
  * resolveSemanticRange / tokenize / matchExplanation / buildSemanticRecallTool。
9795
9905
  * 向量为本地 ONNX 嵌入(cosine 相似度);只匹配文本,纯图片消息不进候选池;
9796
9906
  * 区间缺省检索全部、区间不合法回退全量并在输出中告知;输出契约同 recall
9797
- * ({ text, images },超大结果由 tool-result-pruner 裁剪);仅主会话可用。
9907
+ * ({ text, images },条目为 XML 形态见 recall-xml.ts,超大结果由 tool-result-pruner
9908
+ * 裁剪);候选池排除本次调用自身的 toolcall 完整消息(其渲染文本含 query 原文,
9909
+ * 必居榜首);仅主会话可用。
9798
9910
  */
9799
9911
  /** recall-semantic 工具参数 schema:query 必填;top_k 默认 3(1-10);区间参数均可选。 */
9800
9912
  const semanticRecallArgsSchema = z.object({
@@ -9882,7 +9994,7 @@ function buildSemanticRecallTool(options) {
9882
9994
  const embed = options?.embedder ?? ((texts) => getEmbedder().then((fn) => fn(texts)));
9883
9995
  return {
9884
9996
  name: "recall-semantic",
9885
- description: `${COMPLETE_MESSAGE_DEFINITION}按自然语言含义检索最符合的完整消息,默认全量搜索,可指定区间。注意:只匹配文本。`,
9997
+ description: `在你需要按语义检索历史消息时调用。${COMPLETE_MESSAGE_DEFINITION}此工具按自然语言含义检索最符合的完整消息,默认全量搜索,可指定区间。注意:只匹配文本。`,
9886
9998
  parameters: parametersFromZod(semanticRecallArgsSchema),
9887
9999
  output: {
9888
10000
  schema: RECALL_OUTPUT_SCHEMA,
@@ -9901,10 +10013,12 @@ function buildSemanticRecallTool(options) {
9901
10013
  end,
9902
10014
  offset
9903
10015
  });
10016
+ const selfCallId = String(exec.callId ?? "");
9904
10017
  const candidates = [];
9905
10018
  for (let i = range.lo; i <= range.hi; i += 1) {
9906
10019
  const cm = cms[i];
9907
10020
  if (!cm) continue;
10021
+ if (selfCallId !== "" && cm.type === "toolcall" && cm.callId === selfCallId) continue;
9908
10022
  let text = "";
9909
10023
  try {
9910
10024
  text = renderCompleteMessage(session, cm);
@@ -9929,27 +10043,32 @@ function buildSemanticRecallTool(options) {
9929
10043
  const parts = [];
9930
10044
  const images = [];
9931
10045
  const rangeNote = range.fallback ? "指定区间不合法(start/end 越界等),已回退检索全部消息" : start === void 0 ? `检索全部消息(${candidates.length} 条可嵌入)` : `检索区间 [${range.lo}..${range.hi}](${candidates.length} 条可嵌入)`;
9932
- parts.push(`查询: ${query}`);
9933
- parts.push(rangeNote);
9934
- parts.push(`匹配 TOP-${hits.length}(共 ${scored.length} 条候选):`);
10046
+ parts.push(`<!-- ${xmlCommentText(`查询: ${query}`)} -->`);
10047
+ parts.push(`<!-- ${xmlCommentText(rangeNote)} -->`);
10048
+ parts.push(`<!-- ${xmlCommentText(`匹配 TOP-${hits.length}(共 ${scored.length} 条候选)`)} -->`);
9935
10049
  for (let i = 0; i < hits.length; i += 1) {
9936
10050
  const hit = hits[i];
9937
10051
  if (!hit) continue;
9938
- const callAttr = hit.cm.type === "toolcall" && hit.cm.callId ? ` callId=${hit.cm.callId}` : "";
9939
- let text = hit.text;
10052
+ const note = `<!-- ${xmlCommentText(`${i + 1}. ${matchExplanation(query, hit.text, hit.score)}`)} -->`;
10053
+ let xml;
9940
10054
  let hitImages = [];
9941
10055
  try {
9942
10056
  const pruner = getPruner();
9943
- const rendered = renderCompleteMessageParts(session, hit.cm, pruner);
9944
- text = rendered.text;
10057
+ const rendered = renderCompleteMessageXml(session, hit.cm, {
10058
+ pruner,
10059
+ fallbackText: hit.text
10060
+ });
10061
+ xml = rendered.xml;
9945
10062
  hitImages = rendered.images;
9946
- } catch {}
9947
- parts.push(`-- [${i + 1}] index ${hit.cm.index} ${hit.cm.type}${callAttr} — ${matchExplanation(query, hit.text, hit.score)} --`);
9948
- parts.push(hitImages.length > 0 ? [text, ...hitImages.map(imageNote)].join("\n") : text);
10063
+ } catch {
10064
+ xml = hit.text;
10065
+ }
10066
+ parts.push(note);
10067
+ parts.push(xml);
9949
10068
  images.push(...hitImages);
9950
10069
  }
9951
10070
  return {
9952
- text: parts.join("\n\n"),
10071
+ text: parts.join("\n"),
9953
10072
  images
9954
10073
  };
9955
10074
  }
@@ -21,6 +21,15 @@ export declare function indexCompleteMessages(session: Session): CompleteMessage
21
21
  * image 块按附件元数据收集(字段不全则忽略);tool-result 块递归收集其 content。
22
22
  */
23
23
  export declare function collectImageRefs(content: unknown, out: ImageRefValue[]): void;
24
+ /**
25
+ * 取 toolcall 完整消息对应的 tool-call 块(调用参数渲染与 XML 条目渲染共用):
26
+ * 非 toolcall、调用事件缺失或块内 id 不匹配时返回 undefined。
27
+ */
28
+ export declare function toolCallBlockOf(session: Session, cm: CompleteMessage): {
29
+ name?: unknown;
30
+ id?: unknown;
31
+ arguments?: unknown;
32
+ } | undefined;
24
33
  /**
25
34
  * 取 toolcall 完整消息的 tool/result 消息(超大结果经 pruner 裁剪):
26
35
  * 结果文本渲染与 <skill> 条目正文共用;非 toolcall 或无配对 result 时返回 undefined。
@@ -1 +1 @@
1
- {"version":3,"file":"log-index.d.ts","sourceRoot":"","sources":["../src/log-index.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EACV,eAAe,EACf,OAAO,EACP,YAAY,EAEZ,OAAO,EACP,YAAY,EACb,MAAM,YAAY,CAAC;AAGpB,+CAA+C;AAC/C,MAAM,MAAM,UAAU,GAAG;IAAE,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,KAAK,OAAO,EAAE,GAAG,IAAI,CAAA;CAAE,CAAC;AAE7F,oCAAoC;AACpC,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAG5E;AAED,gEAAgE;AAChE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,YAAY,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAMpF;AAED,6CAA6C;AAC7C,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,YAAY,CAoB5D;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,eAAe,EAAE,CA+DzE;AACD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,aAAa,EAAE,GAAG,IAAI,CA+B7E;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,OAAO,EAChB,EAAE,EAAE,eAAe,EACnB,MAAM,CAAC,EAAE,UAAU,GAClB,OAAO,GAAG,SAAS,CASrB;AAED,4DAA4D;AAC5D,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,OAAO,EAChB,EAAE,EAAE,eAAe,EACnB,MAAM,CAAC,EAAE,UAAU,GAClB,MAAM,CAGR;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,OAAO,EAChB,EAAE,EAAE,eAAe,EACnB,MAAM,CAAC,EAAE,UAAU,GAClB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,aAAa,EAAE,CAAA;CAAE,CAiD3C;AAED,kEAAkE;AAClE,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,OAAO,EAChB,EAAE,EAAE,eAAe,EACnB,MAAM,CAAC,EAAE,UAAU,GAClB,MAAM,CAER"}
1
+ {"version":3,"file":"log-index.d.ts","sourceRoot":"","sources":["../src/log-index.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EACV,eAAe,EACf,OAAO,EACP,YAAY,EAEZ,OAAO,EACP,YAAY,EACb,MAAM,YAAY,CAAC;AAGpB,+CAA+C;AAC/C,MAAM,MAAM,UAAU,GAAG;IAAE,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,KAAK,OAAO,EAAE,GAAG,IAAI,CAAA;CAAE,CAAC;AAE7F,oCAAoC;AACpC,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAG5E;AAED,gEAAgE;AAChE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,YAAY,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAMpF;AAED,6CAA6C;AAC7C,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,YAAY,CAoB5D;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,eAAe,EAAE,CA+DzE;AACD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,aAAa,EAAE,GAAG,IAAI,CA+B7E;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,OAAO,EAChB,EAAE,EAAE,eAAe,GAClB;IAAE,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,EAAE,CAAC,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,SAAS,CAWnE;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,OAAO,EAChB,EAAE,EAAE,eAAe,EACnB,MAAM,CAAC,EAAE,UAAU,GAClB,OAAO,GAAG,SAAS,CASrB;AAED,4DAA4D;AAC5D,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,OAAO,EAChB,EAAE,EAAE,eAAe,EACnB,MAAM,CAAC,EAAE,UAAU,GAClB,MAAM,CAGR;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,OAAO,EAChB,EAAE,EAAE,eAAe,EACnB,MAAM,CAAC,EAAE,UAAU,GAClB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,aAAa,EAAE,CAAA;CAAE,CAoC3C;AAED,kEAAkE;AAClE,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,OAAO,EAChB,EAAE,EAAE,eAAe,EACnB,MAAM,CAAC,EAAE,UAAU,GAClB,MAAM,CAER"}
@@ -1 +1 @@
1
- {"version":3,"file":"om-event.d.ts","sourceRoot":"","sources":["../src/om-event.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAExD,kDAAkD;AAClD,eAAO,MAAM,eAAe,UAAU,CAAC;AAEvC,6BAA6B;AAC7B,MAAM,MAAM,WAAW;AACrB,4CAA4C;AAC1C,YAAY;AACd,qCAAqC;GACnC,oBAAoB;AACtB,uCAAuC;GACrC,uBAAuB,CAAC;AAE5B,iCAAiC;AACjC,MAAM,MAAM,iBAAiB,GAAG;IAC9B,YAAY,EAAE;QACZ,qCAAqC;QACrC,OAAO,EAAE,MAAM,CAAC;QAChB,iBAAiB;QACjB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,oBAAoB,EAAE;QACpB,8BAA8B;QAC9B,mBAAmB,EAAE,MAAM,CAAC;KAC7B,CAAC;IACF,uBAAuB,EAAE;QACvB,sCAAsC;QACtC,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;CACH,CAAC;AAEF,0CAA0C;AAC1C,MAAM,MAAM,OAAO,GAAG;KACnB,CAAC,IAAI,WAAW,GAAG;QAAE,IAAI,EAAE,CAAC,CAAC;QAAC,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE;CACzE,CAAC,WAAW,CAAC,CAAC;AAiBf;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,YAAY,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO,GAAG,SAAS,CAmBvF;AAOD,qEAAqE;AACrE,wBAAgB,aAAa,CAAC,CAAC,SAAS,WAAW,EACjD,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,CAAC,EACP,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,GACzB,MAAM,CAER;AAED,8BAA8B;AAC9B,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,EAAE,CAAC;AAC1D,2CAA2C;AAC3C,wBAAgB,YAAY,CAAC,CAAC,SAAS,WAAW,EAChD,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,CAAC,GACN,KAAK,CAAC;IAAE,IAAI,EAAE,CAAC,CAAC;IAAC,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC"}
1
+ {"version":3,"file":"om-event.d.ts","sourceRoot":"","sources":["../src/om-event.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAExD,kDAAkD;AAClD,eAAO,MAAM,eAAe,UAAU,CAAC;AAEvC,6BAA6B;AAC7B,MAAM,MAAM,WAAW;AACrB,4CAA4C;AAC1C,YAAY;AACd,qCAAqC;GACnC,oBAAoB;AACtB,uCAAuC;GACrC,uBAAuB,CAAC;AAE5B,iCAAiC;AACjC,MAAM,MAAM,iBAAiB,GAAG;IAC9B,YAAY,EAAE;QACZ,qCAAqC;QACrC,OAAO,EAAE,MAAM,CAAC;QAChB,iBAAiB;QACjB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,oBAAoB,EAAE;QACpB,8BAA8B;QAC9B,mBAAmB,EAAE,MAAM,CAAC;KAC7B,CAAC;IACF,uBAAuB,EAAE;QACvB,sCAAsC;QACtC,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;CACH,CAAC;AAEF,0CAA0C;AAC1C,MAAM,MAAM,OAAO,GAAG;KACnB,CAAC,IAAI,WAAW,GAAG;QAAE,IAAI,EAAE,CAAC,CAAC;QAAC,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE;CACzE,CAAC,WAAW,CAAC,CAAC;AAiBf;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,YAAY,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO,GAAG,SAAS,CAoBvF;AAOD,qEAAqE;AACrE,wBAAgB,aAAa,CAAC,CAAC,SAAS,WAAW,EACjD,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,CAAC,EACP,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,GACzB,MAAM,CAER;AAED,8BAA8B;AAC9B,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,EAAE,CAAC;AAC1D,2CAA2C;AAC3C,wBAAgB,YAAY,CAAC,CAAC,SAAS,WAAW,EAChD,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,CAAC,GACN,KAAK,CAAC;IAAE,IAAI,EAAE,CAAC,CAAC;IAAC,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC"}
@@ -1,8 +1,9 @@
1
1
  /**
2
2
  * recall / recall-semantic 共享输出契约:输出值为固定形态 { text, images }。
3
- * text 为完整消息的文本内容(带图消息附图片标注行),images 为图片附件元数据
4
- * (按 attachmentId 引用,不含字节)。导出 ImageRefValue / RecallOutputValue /
5
- * RECALL_OUTPUT_SCHEMA / textOnly / imageNote / renderRecallOutput。
3
+ * text 为完整消息的 XML 条目序列(形态见 recall-xml.ts,图片位置以 XML 注释标注),
4
+ * images 为图片附件元数据(按 attachmentId 引用,不含字节)。
5
+ * 导出 ImageRefValue / RecallOutputValue / RECALL_OUTPUT_SCHEMA / textOnly / imageNote /
6
+ * renderRecallOutput。
6
7
  */
7
8
  import type { ContentBlock } from '@deepseek-ai/dsh-llm';
8
9
  import type { JsonSchemaNode } from '@deepseek-ai/dsh-tools';
@@ -1 +1 @@
1
- {"version":3,"file":"recall-output.d.ts","sourceRoot":"","sources":["../src/recall-output.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAc,MAAM,sBAAsB,CAAC;AACrE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE7D,wDAAwD;AACxD,MAAM,MAAM,aAAa,GAAG;IAC1B,yCAAyC;IACzC,YAAY,EAAE,MAAM,CAAC;IACrB,2BAA2B;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW;IACX,KAAK,EAAE,MAAM,CAAC;IACd,kBAAkB;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,kBAAkB;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,6DAA6D;AAC7D,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,aAAa,EAAE,CAAC;CACzB,CAAC;AAEF,uBAAuB;AACvB,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,CAExD;AAED,qDAAqD;AACrD,wBAAgB,SAAS,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAGpD;AAED,0CAA0C;AAC1C,eAAO,MAAM,oBAAoB,EAAE,cA4BlC,CAAC;AAEF,iDAAiD;AACjD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,iBAAiB,GAAG,YAAY,EAAE,CAY3E"}
1
+ {"version":3,"file":"recall-output.d.ts","sourceRoot":"","sources":["../src/recall-output.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAc,MAAM,sBAAsB,CAAC;AACrE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE7D,wDAAwD;AACxD,MAAM,MAAM,aAAa,GAAG;IAC1B,yCAAyC;IACzC,YAAY,EAAE,MAAM,CAAC;IACrB,2BAA2B;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW;IACX,KAAK,EAAE,MAAM,CAAC;IACd,kBAAkB;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,kBAAkB;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,6DAA6D;AAC7D,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,aAAa,EAAE,CAAC;CACzB,CAAC;AAEF,uBAAuB;AACvB,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,CAExD;AAED,qDAAqD;AACrD,wBAAgB,SAAS,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAGpD;AAED,0CAA0C;AAC1C,eAAO,MAAM,oBAAoB,EAAE,cA6BlC,CAAC;AAEF,iDAAiD;AACjD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,iBAAiB,GAAG,YAAY,EAAE,CAY3E"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * 完整消息的 XML 条目渲染:recall / recall-semantic 的输出条目形态。
3
+ * 每条完整消息渲染为一个 XML 元素,正文统一以 CDATA 包裹(逐字原样,不做实体转义与
4
+ * 再次序列化),从构建源头避免多层转义:
5
+ * - user → <user_message index>,正文 CDATA,图片等非文本块为 XML 注释
6
+ * - sys → <sys index type>,无正文时自闭合(与压缩日志的 sys 条目同形态)
7
+ * - assistant 文本 → <assistant index type="text">,正文 CDATA
8
+ * - toolcall → <assistant index type="toolcall" tool-name callId>,内嵌 <tool-args>
9
+ * (合法 JSON,仅一层 JSON 转义)与 <tool-result>(工具返回正文)两个 CDATA 子元素
10
+ * 导出 RenderCompleteMessageXmlOptions / renderCompleteMessageXml / xmlCommentText。
11
+ */
12
+ import { type PrunerLike } from './log-index.ts';
13
+ import { type ImageRefValue } from './recall-output.ts';
14
+ import type { CompleteMessage, Session } from './types.ts';
15
+ /** 渲染选项:pruner 裁剪超大工具结果;fallbackText 为主渲染失败时的回退正文。 */
16
+ export type RenderCompleteMessageXmlOptions = {
17
+ pruner?: PrunerLike | undefined;
18
+ fallbackText?: string;
19
+ };
20
+ /** XML 注释文本:注释内不允许连续连字符,`--` 统一替换为破折号。 */
21
+ export declare function xmlCommentText(text: string): string;
22
+ /**
23
+ * 渲染一条完整消息为 XML 条目(序列化后的字符串)与其携带的图片附件元数据。
24
+ * 主渲染失败且提供 fallbackText 时降级为最简元素;两者皆不可用时向上抛出,
25
+ * 由调用方决定跳过或回退。
26
+ */
27
+ export declare function renderCompleteMessageXml(session: Session, cm: CompleteMessage, options?: RenderCompleteMessageXmlOptions): {
28
+ xml: string;
29
+ images: ImageRefValue[];
30
+ };
31
+ //# sourceMappingURL=recall-xml.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recall-xml.d.ts","sourceRoot":"","sources":["../src/recall-xml.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,EAEL,KAAK,UAAU,EAIhB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,KAAK,aAAa,EAAa,MAAM,oBAAoB,CAAC;AACnE,OAAO,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAG3D,sDAAsD;AACtD,MAAM,MAAM,+BAA+B,GAAG;IAC5C,MAAM,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IAChC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAOF,0CAA0C;AAC1C,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD;AA0FD;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,OAAO,EAChB,EAAE,EAAE,eAAe,EACnB,OAAO,GAAE,+BAAoC,GAC5C;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,aAAa,EAAE,CAAA;CAAE,CAY1C"}
package/dist/recall.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * recall 工具:按完整消息 index 区间回看原始会话(含被压缩内容)。
3
3
  * 导出 recallArgsSchema / RecallArgs / parseRecallArgs / buildRecallTool。
4
- * 输出值为 { text, images }(契约见 recall-output.ts);recall 自身不设输出上限,
5
- * 超大工具结果由 tool-result-pruner 裁剪。
4
+ * 输出值为 { text, images }(契约见 recall-output.ts),text 为 XML 条目序列
5
+ * (形态见 recall-xml.ts);recall 自身不设输出上限,超大工具结果由 tool-result-pruner 裁剪。
6
6
  */
7
7
  import { z } from 'zod';
8
8
  import type { ToolDefinition } from './types.ts';
@@ -1 +1 @@
1
- {"version":3,"file":"recall.d.ts","sourceRoot":"","sources":["../src/recall.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAYxB,OAAO,KAAK,EAAE,cAAc,EAAkB,MAAM,YAAY,CAAC;AAGjE;;;GAGG;AACH,eAAO,MAAM,gBAAgB;;;;iBAYzB,CAAC;AAEL,4CAA4C;AAC5C,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE1D,8DAA8D;AAC9D,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,UAAU,CAUxD;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,SAAS,CAAC,EAAE,MAAM,OAAO,GAAG,cAAc,CAoEzE"}
1
+ {"version":3,"file":"recall.d.ts","sourceRoot":"","sources":["../src/recall.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAYxB,OAAO,KAAK,EAAE,cAAc,EAAkB,MAAM,YAAY,CAAC;AAGjE;;;GAGG;AACH,eAAO,MAAM,gBAAgB;;;;iBAYzB,CAAC;AAEL,4CAA4C;AAC5C,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE1D,8DAA8D;AAC9D,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,UAAU,CAUxD;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,SAAS,CAAC,EAAE,MAAM,OAAO,GAAG,cAAc,CA2DzE"}
@@ -5,7 +5,9 @@
5
5
  * resolveSemanticRange / tokenize / matchExplanation / buildSemanticRecallTool。
6
6
  * 向量为本地 ONNX 嵌入(cosine 相似度);只匹配文本,纯图片消息不进候选池;
7
7
  * 区间缺省检索全部、区间不合法回退全量并在输出中告知;输出契约同 recall
8
- * ({ text, images },超大结果由 tool-result-pruner 裁剪);仅主会话可用。
8
+ * ({ text, images },条目为 XML 形态见 recall-xml.ts,超大结果由 tool-result-pruner
9
+ * 裁剪);候选池排除本次调用自身的 toolcall 完整消息(其渲染文本含 query 原文,
10
+ * 必居榜首);仅主会话可用。
9
11
  */
10
12
  import { z } from 'zod';
11
13
  import { type EmbedFn, type ModelStatus } from './embedding.ts';
@@ -1 +1 @@
1
- {"version":3,"file":"semantic-recall.d.ts","sourceRoot":"","sources":["../src/semantic-recall.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAoB,KAAK,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAgB/F,OAAO,KAAK,EAAmB,cAAc,EAAkB,MAAM,YAAY,CAAC;AAGlF,qEAAqE;AACrE,eAAO,MAAM,wBAAwB;;;;;;iBAoBjC,CAAC;AAEL,6DAA6D;AAC7D,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,+CAA+C;AAC/C,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,OAAO,GAAG,kBAAkB,CAUxE;AAED,6DAA6D;AAC7D,MAAM,MAAM,WAAW,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC;AAExE;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,IAAI,CAAC,kBAAkB,EAAE,OAAO,GAAG,KAAK,GAAG,QAAQ,CAAC,GACzD,WAAW,CAqBb;AAED,uCAAuC;AACvC,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAMlD;AAED,+CAA+C;AAC/C,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAUnF;AAED,qCAAqC;AACrC,eAAO,MAAM,gCAAgC,6HAAyB,CAAC;AAEvE,uEAAuE;AACvE,wBAAgB,uBAAuB,CAAC,OAAO,CAAC,EAAE;IAChD,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sCAAsC;IACtC,WAAW,CAAC,EAAE,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CACxD,GAAG,cAAc,CA+EjB"}
1
+ {"version":3,"file":"semantic-recall.d.ts","sourceRoot":"","sources":["../src/semantic-recall.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAoB,KAAK,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAW/F,OAAO,KAAK,EAAmB,cAAc,EAAkB,MAAM,YAAY,CAAC;AAGlF,qEAAqE;AACrE,eAAO,MAAM,wBAAwB;;;;;;iBAoBjC,CAAC;AAEL,6DAA6D;AAC7D,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,+CAA+C;AAC/C,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,OAAO,GAAG,kBAAkB,CAUxE;AAED,6DAA6D;AAC7D,MAAM,MAAM,WAAW,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC;AAExE;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,IAAI,CAAC,kBAAkB,EAAE,OAAO,GAAG,KAAK,GAAG,QAAQ,CAAC,GACzD,WAAW,CAqBb;AAED,uCAAuC;AACvC,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAMlD;AAED,+CAA+C;AAC/C,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAUnF;AAED,qCAAqC;AACrC,eAAO,MAAM,gCAAgC,6HAAyB,CAAC;AAEvE,uEAAuE;AACvE,wBAAgB,uBAAuB,CAAC,OAAO,CAAC,EAAE;IAChD,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sCAAsC;IACtC,WAAW,CAAC,EAAE,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CACxD,GAAG,cAAc,CAsFjB"}
package/dist/utils.d.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  /**
2
2
  * 零依赖工具函数:文本呈现、主会话判定、路由解析等通用辅助(不 import 运行时包)。
3
- * 导出 isRecord / uuid / blocksToText / textCharCount / renderMessageText / safeJson /
4
- * isMainSession / routedTarget。
3
+ * 导出 isRecord / uuid / blocksToText / textCharCount / renderMessageText / toolArgsJson /
4
+ * safeJson / appendCdataText / isMainSession / routedTarget。
5
5
  */
6
6
  import type { Message } from '@deepseek-ai/dsh-llm';
7
+ import type { Document, Element } from '@xmldom/xmldom';
7
8
  import type { Session } from './types.ts';
8
9
  /** 判断值是否为普通对象(非 null、非数组)。 */
9
10
  export declare function isRecord(value: unknown): value is Record<string, unknown>;
@@ -17,6 +18,17 @@ export declare function textCharCount(message: Message | null | undefined): numb
17
18
  export declare function renderMessageText(message: Message | null | undefined): string;
18
19
  /** 安全 JSON 序列化:序列化失败时退回 String 呈现。 */
19
20
  export declare function safeJson(value: unknown): string;
21
+ /**
22
+ * 工具调用参数的 JSON 文本(CDATA 内保持只有一层 JSON 转义):
23
+ * 字符串参数是模型产出的原始 JSON 串,原样返回(本身即合法 JSON,不再二次序列化);
24
+ * 其余结构 JSON.stringify 序列化一次。
25
+ */
26
+ export declare function toolArgsJson(args: unknown): string;
27
+ /**
28
+ * 向元素追加 CDATA 正文:正文统一以 CDATA 包裹(逐字原样,不做实体转义)。
29
+ * 正文含 ]]> 时拆为相邻多个 CDATA 段,拼接后逐字还原原文,对读取方透明。
30
+ */
31
+ export declare function appendCdataText(doc: Document, el: Element, text: string): void;
20
32
  /** 主会话判定:subagent 会话 header.origin === 'subagent'。 */
21
33
  export declare function isMainSession(session: Session): boolean;
22
34
  /** 会话路由目标:provider + model。 */
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,8BAA8B;AAC9B,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzE;AAED,iDAAiD;AACjD,wBAAgB,IAAI,IAAI,MAAM,CAI7B;AAED,4DAA4D;AAC5D,wBAAgB,YAAY,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAQpD;AAED,8CAA8C;AAC9C,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAWzE;AAED,qEAAqE;AACrE,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAc7E;AAED,sCAAsC;AACtC,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAM/C;AAED,sDAAsD;AACtD,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAEvD;AAED,+BAA+B;AAC/B,MAAM,MAAM,YAAY,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/D,iDAAiD;AACjD,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,YAAY,GAAG,SAAS,CAQvE"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,8BAA8B;AAC9B,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzE;AAED,iDAAiD;AACjD,wBAAgB,IAAI,IAAI,MAAM,CAI7B;AAED,4DAA4D;AAC5D,wBAAgB,YAAY,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAQpD;AAED,8CAA8C;AAC9C,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAWzE;AAED,qEAAqE;AACrE,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAc7E;AAED,sCAAsC;AACtC,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAM/C;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAGlD;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAW9E;AAED,sDAAsD;AACtD,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAEvD;AAED,+BAA+B;AAC/B,MAAM,MAAM,YAAY,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/D,iDAAiD;AACjD,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,YAAY,GAAG,SAAS,CAQvE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-plugin-om",
3
- "version": "0.0.33",
3
+ "version": "0.0.35",
4
4
  "type": "module",
5
5
  "main": "./dist/index.mjs",
6
6
  "module": "./dist/index.mjs",
@@ -39,7 +39,6 @@
39
39
  "client": {
40
40
  "inject": [
41
41
  "@deepseek-ai/dsh-client-locale",
42
- "@deepseek-ai/dsh-client-runtime",
43
42
  "@deepseek-ai/dsh-client-ui-conversation"
44
43
  ],
45
44
  "platform": "web"
@@ -66,24 +65,26 @@
66
65
  "devDependencies": {
67
66
  "@biomejs/biome": "^2.5.8",
68
67
  "@deepseek-ai/cordis": "^4.0.1",
69
- "@deepseek-ai/dsh-agent": "^0.1.1-rc.1",
70
- "@deepseek-ai/dsh-code-runtime": "^0.1.1-rc.1",
71
- "@deepseek-ai/dsh-compaction": "^0.1.1-rc.1",
72
- "@deepseek-ai/dsh-compaction-tool-result-pruner": "^0.1.1-rc.1",
73
- "@deepseek-ai/dsh-invariants": "^0.1.1-rc.1",
74
- "@deepseek-ai/dsh-llm": "^0.1.1-rc.1",
75
- "@deepseek-ai/dsh-scope": "^0.1.1-rc.1",
76
- "@deepseek-ai/dsh-session": "^0.1.1-rc.1",
77
- "@deepseek-ai/dsh-subagent": "^0.1.1-rc.1",
78
- "@deepseek-ai/dsh-system-prompt": "^0.1.1-rc.1",
79
- "@deepseek-ai/dsh-token-meter": "^0.1.1-rc.1",
80
- "@deepseek-ai/dsh-tools": "^0.1.1-rc.1",
81
- "@deepseek-ai/dsh-client-locale": "^0.1.1-rc.1",
82
- "@deepseek-ai/dsh-client-runtime": "^0.1.1-rc.1",
83
- "@deepseek-ai/dsh-client-ui-conversation": "^0.1.1-rc.1",
84
- "@deepseek-ai/dsh-client-ui-slots": "^0.1.1-rc.1",
85
- "@deepseek-ai/dsh-client-ui-primitives": "^0.1.1-rc.1",
86
- "@deepseek-ai/dsh-user-approval": "^0.1.1-rc.1",
68
+ "@deepseek-ai/dsh-agent": "^0.1.2-rc.1",
69
+ "@deepseek-ai/dsh-client-locale": "^0.1.2-rc.1",
70
+ "@deepseek-ai/dsh-client-ui-chat": "^0.1.2-rc.1",
71
+ "@deepseek-ai/dsh-client-ui-conversation": "^0.1.2-rc.1",
72
+ "@deepseek-ai/dsh-client-ui-primitives": "^0.1.2-rc.1",
73
+ "@deepseek-ai/dsh-client-ui-renderer": "^0.1.2-rc.1",
74
+ "@deepseek-ai/dsh-client-ui-slots": "^0.1.2-rc.1",
75
+ "@deepseek-ai/dsh-code-runtime": "^0.1.2-rc.1",
76
+ "@deepseek-ai/dsh-compaction": "^0.1.2-rc.1",
77
+ "@deepseek-ai/dsh-compaction-tool-result-pruner": "^0.1.2-rc.1",
78
+ "@deepseek-ai/dsh-invariants": "^0.1.2-rc.1",
79
+ "@deepseek-ai/dsh-llm": "^0.1.2-rc.1",
80
+ "@deepseek-ai/dsh-scope": "^0.1.2-rc.1",
81
+ "@deepseek-ai/dsh-session": "^0.1.2-rc.1",
82
+ "@deepseek-ai/dsh-session-projection": "0.1.2-rc.1",
83
+ "@deepseek-ai/dsh-subagent": "^0.1.2-rc.1",
84
+ "@deepseek-ai/dsh-system-prompt": "^0.1.2-rc.1",
85
+ "@deepseek-ai/dsh-token-meter": "^0.1.2-rc.1",
86
+ "@deepseek-ai/dsh-tools": "^0.1.2-rc.1",
87
+ "@deepseek-ai/dsh-user-approval": "^0.1.2-rc.1",
87
88
  "@types/node": "^22.20.0",
88
89
  "@types/react": "~18.3.1",
89
90
  "@types/react-dom": "~18.3.0",