dsh-plugin-om 0.0.15 → 0.0.17

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
@@ -84,13 +84,24 @@ dsh的"预设"分为两层,`dsh web`等同于`dsh --profile web`,调用的
84
84
 
85
85
  - 观察压缩只精确替换被压缩的新消息区间:旧 <history> 块保留为独立消息,新观察日志作为新块追加在其后(多块并存按序排列),历史不会随压缩次数膨胀;反思合并时才把多个块合并为一条更紧凑的摘要
86
86
  - 压缩边界:消息列表中最后一个合法的 <history> 块(source 为插件,plugin 为插件标识 `dsh-plugin-om`;兼容旧日志的宿主 checkpoint 标记 `compact`)之后的消息视为未压缩;其前(含自身)视为已压缩,不重复压缩、不计入观察阈值
87
- - 观察输入经 `@xmldom/xmldom` 构建为合法 <history> 块(用户消息文本/assistant 文本/reasoning 特殊字符自动转义,图片/文件以注释补充;assistant 文本与 toolcall&result 原样;用户消息中合法的 <system-reminder> 块——完整开闭标签对且内容可被 XML 解析——整块原样保留、不转义,非法片段照常转义)
87
+ - 观察输入经 `@xmldom/xmldom` 构建为合法 <history> 块(用户消息文本/assistant 文本/reasoning 特殊字符自动转义,图片/文件以注释补充;assistant 文本与 toolcall&result 原样;系统消息——user_message 中 source.kind 非 user 的部分,如宿主注入的上下文——渲染为 <sys type="KIND" index="N"></sys> 空块,内容不进入压缩输入)
88
88
  - 输出经 `@xmldom/xmldom` 解析校验:结构合法(标签匹配/闭合/单块)、不含 <reasoning>、index/start/end 连续(与预期覆盖区间一致),失败按 `compressRetryCount` 重试
89
89
  - 块开标签带 `tip` 属性(对 AI 的提醒:"当前块是历史消息的压缩产物,不要复述");块顶为构成逻辑注释(完整消息定义串 + 条目标签语义),消息正文不再附加前缀句
90
90
 
91
+ ### 压缩卡片(消息列表中的「已压缩」展示)
92
+
93
+ 插件自产的替换消息使用插件自身标记(source.plugin = `dsh-plugin-om`);宿主 conversation UI 只识别内置的 `compact` 检查点,因此插件额外注册一个浏览器客户端 bundle(`src/client/`,经 `dsh.client` 声明、exports["./client"] → `dist/client.js`,由 dsh 客户端模块系统按 `/plugins/dsh-plugin-om/client.js` 加载),自行认领压缩生命周期事件与替换检查点,在消息列表渲染折叠式「已压缩」卡片:
94
+
95
+ - 卡片默认折叠,采用与宿主「上下文注入」卡片同款样式:同一 DisclosureRow 外壳组件 + IconBrowseOutline16 图标,行内统计与展开体样式按宿主 ContextInjectionRow 的规则注入(插件 bundle 无法引用宿主编译期哈希的 CSS Module 类名,按宿主 client bundle 的同一机制注入 <style>),视觉一致
96
+ - 标题直接展示「压缩前 N 条消息 · X 字符(约 A tokens)→ 压缩后 Y 字符(约 B tokens)」:压缩前字符数来自插件扩展 shadowedCharCount,压缩前 token 来自 shadowedTokenCount,压缩后字符数为摘要文本长度,压缩后 token 在客户端按 4 字符 ≈ 1 token 估算(与服务端 estimateTextTokens 同一启发式);旧会话载荷缺少 shadowedCharCount 时回落为「已压缩 N 条历史记录(约 M tokens)」
97
+ - 点击展开显示压缩摘要文本,按代码块样式呈现(缩小字号、代码背景与等宽字体、保留换行)
98
+ - summary 事件落在当前加载窗口之外时卡片不可展开(不显示空内容)
99
+ - 卡片只认领插件自产的检查点(source.plugin = `dsh-plugin-om`);宿主 `compact` 检查点仍由宿主自己渲染,不会出现双卡片
100
+ - 平台模块(react / cordis / ui-primitives / ui-slots 等)走宿主冻结模块表(保持 external),其余依赖内联进 bundle
101
+
91
102
  ### 注意
92
103
 
93
- - 未压缩消息的 token 统计排除用户消息中合法 <system-reminder> 块(宿主注入的工作区/会话提醒不计入观察阈值的触发量)
104
+ - 未压缩消息的 token 统计排除系统消息(user_message source.kind 非 user 的部分,如宿主注入的上下文;宿主注入的提醒不计入观察阈值的触发量)
94
105
  - recall 不截断,建议保留 `tool-result-pruner`
95
106
  - recall-semantic 使用本地多语言嵌入模型(paraphrase-multilingual-MiniLM-L12-v2),
96
107
 
@@ -98,6 +109,7 @@ dsh的"预设"分为两层,`dsh web`等同于`dsh --profile web`,调用的
98
109
 
99
110
  - dsh宿主提供的依赖,直接复用即可,如 cordis / dsh-tools / zod 等
100
111
  - `@xmldom/xmldom` 用于 <history> 块的 XML 构建(输入转义)与解析校验(输出结构合法性),经 tsdown `deps.alwaysBundle` 打包进 dist 产物
112
+ - 浏览器客户端 bundle(`src/client/` → `dist/client.js`)复用宿主冻结模块表:react / cordis / @deepseek-ai/dsh-client-ui-primitives / dsh-client-ui-slots 等平台种子与 runtime/client 豁免保持 external,其余依赖内联;相关 @deepseek-ai/dsh-client-* 仅作 devDependencies(类型与构建期使用)
101
113
  - 向量模型模型二进制:量化 ONNX 约 113MB,启用语义召回时下载,位置`$DSH_HOME/plugin-data/dsh-plugin-om/models/<id>/onnx/model_quantized.onnx`。下载失败可以设置`HF_ENDPOINT=https://hf-mirror.com`
102
114
 
103
115
  ## 插件配置项
@@ -159,17 +171,22 @@ src/
159
171
  ├── types.ts # type-only:宿主类型再导出 + 领域类型(MessageNode / MessageIndex)
160
172
  ├── config.ts # 配置默认值 / 宽松合并(缺省、null、空串回退默认值;未知键忽略、非法值回退默认;数值键/布尔键/omEnabled/modelDir)
161
173
  ├── utils.ts # 零依赖工具函数(配置校验 / 文本渲染 / 主会话判定 / 路由解析)
162
- ├── log-index.ts # 完整消息索引(index 定位 user/assistant/具有result的toolcall;未闭合 tool-call 不占位;recall 与摘要共用)
174
+ ├── log-index.ts # 完整消息索引(index 定位 user/sys/assistant/具有result的toolcall;user_message 按 source.kind 分类:kind:user 为用户消息、其余为系统消息;本插件自产压缩日志消息不占位;未闭合 tool-call 不占位;recall 与摘要共用)
163
175
  ├── embedding.ts # 本地 ONNX 嵌入(@huggingface/transformers + 本地模型;共享目录解析 / 小文件补齐 / 运行时按需下载编排 / 懒加载 / 批量 / cosine)
164
176
  ├── model-download.ts # 模型下载原语(modelSourceUrl / needsDownload / 原子落盘 / 开始结束日志与失败镜像建议;运行时与 dev CLI 共用)
165
- ├── summarize.ts # 共享提示词 buildHistoryPrompt(观察/反思同一套)+ renderMessages(@xmldom/xmldom 构建 <history> 块输入,自动转义)+ 直连 ctx.llm.stream() 摘要(new 方式:指令作 system、输入为渲染消息;extractSummaryLog 提取校验:XML 结构合法 / 无 reasoning / index 连续 / 覆盖区间;重试与流式 usage 归入主会话)
177
+ ├── summarize.ts # 共享提示词 buildHistoryPrompt(观察/反思同一套)+ renderMessages(@xmldom/xmldom 构建 <history> 块输入:用户消息原样、系统消息渲染为 <sys> 空块、自动转义)+ 直连 ctx.llm.stream() 摘要(new 方式:指令作 system、输入为渲染消息;extractSummaryLog 提取校验:XML 结构合法 / 无 reasoning / index 连续 / 覆盖区间;重试与流式 usage 归入主会话)
166
178
  ├── recall.ts # recall 工具
167
179
  ├── semantic-recall.ts # recall-semantic 工具(query 语义检索 + 区间限定 + 回退全量 + 匹配说明)
168
180
  └── compress.ts # 两级自动压缩(测量 / mid-turn 区间计算 / 配对平衡回退 / source 标记判定摘要消息 / compaction/* 生命周期事件 + 替换消息 source 插件标识)
181
+ src/client/
182
+ ├── index.ts # 浏览器客户端入口(exports["./client"] → dist/client.js):注入 slots/conversationEvents/locale,注册卡片定义与渲染器
183
+ ├── definition.ts # 压缩卡片业务定义:认领插件生命周期事件与替换检查点(source.plugin = dsh-plugin-om),聚合摘要卡片节点
184
+ ├── OmCompactionCard.tsx # 与宿主「上下文注入」同款的折叠卡片渲染器(统计标题 + 代码块样式 summary 展开)
185
+ └── locales.ts # om-compaction 命名空间字典(zh/en)与 LocaleNamespaceMap 声明合并
169
186
  models/
170
187
  └── paraphrase-multilingual-MiniLM-L12-v2/ # 嵌入模型目录(小文件随包分发;onnx 二进制不随包分发、由运行时按需下载到跨版本共享目录,不进 git)
171
188
  scripts/ # release-archive.mjs(CHANGELOG 归档)/ download-model.mjs(开发手动预下载 CLI)
172
- tests/ # vitest 单元测试(151 例)
189
+ tests/ # vitest 单元测试(服务端 src 各模块 + tests/client/ 客户端卡片定义)
173
190
  .dsh/skills/ # 项目级 skill(feature-defect-workflow:需求/缺陷完成工作流)
174
191
  ```
175
192
 
@@ -0,0 +1,22 @@
1
+ /**
2
+ * dsh-plugin-om 压缩卡片渲染器:与宿主「上下文注入」卡片同款的折叠行。
3
+ *
4
+ * 复用平台原语 DisclosureRow(宿主 ContextInjectionRow 用的同一外壳组件);行内
5
+ * 统计与展开体样式按宿主 ContextInjectionRow.module.css 的规则注入——宿主该卡片
6
+ * 的样式是编译期哈希的 CSS Module,插件 bundle 无法引用其类名,故按宿主 client
7
+ * bundle 的同一机制(注入 <style>)注册逐字一致的规则,保证视觉同款。
8
+ *
9
+ * 压缩检查点遮蔽的是模型可见表层,人类转录中的历史仍在其上方;卡片只报告
10
+ * 模型从何处起不再看到那段历史。summary 来自检查点引用的 compaction/summary
11
+ * 事件;窗口裁剪把该事件留在窗外时,行不可展开而不是显示空内容。
12
+ */
13
+ import type { ChatNode } from '@deepseek-ai/dsh-client-ui-conversation/client';
14
+ import type { TranslateNS } from '@deepseek-ai/dsh-client-ui-slots';
15
+ /** Keyed renderer props: 装配好的卡片节点 + 绑定 `om-compaction` 命名空间的 locale 座。 */
16
+ export interface OmCompactionCardProps {
17
+ readonly node: ChatNode<'om-compaction'>;
18
+ readonly t: TranslateNS<'om-compaction'>;
19
+ }
20
+ /** 折叠式压缩卡片(统计标题行 + 代码块样式 summary 展开,同「上下文注入」卡片)。 */
21
+ export declare const OmCompactionCard: import("react").MemoExoticComponent<({ node, t }: OmCompactionCardProps) => import("react").JSX.Element>;
22
+ //# sourceMappingURL=OmCompactionCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OmCompactionCard.d.ts","sourceRoot":"","sources":["../../src/client/OmCompactionCard.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gDAAgD,CAAC;AAE/E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAIpE,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,oDAAoD;AACpD,eAAO,MAAM,gBAAgB,oDAA+C,qBAAqB,iCAyD/F,CAAC"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * 压缩卡片业务定义:认领插件自产的压缩生命周期事件与替换检查点,
3
+ * 聚合出可渲染的摘要卡片节点。
4
+ *
5
+ * 宿主 conversation 客户端仅识别 source.plugin === 'compact' 的压缩检查点
6
+ * (ui-conversation 的 compactionDefinition),插件自产的检查点标记为
7
+ * PLUGIN_LABEL('dsh-plugin-om'),由本定义认领。生命周期事件(compaction/start
8
+ * |summary|end)同时会被宿主的 compactionDefinition 匹配,但宿主没有检查点证据
9
+ * 时不产出节点(buildViewNode 返回 null),因此双方共存无视觉冲突。
10
+ */
11
+ import type { ConversationMatch, ConversationNodeDefinition } from '@deepseek-ai/dsh-client-runtime/client';
12
+ import type { SessionEvent } from '@deepseek-ai/dsh-session/types';
13
+ /** 压缩卡片渲染器分发键(合并进 ChatNodeDataMap)。 */
14
+ export declare const COMPACTION_CARD_KIND = "om-compaction";
15
+ declare module '@deepseek-ai/dsh-client-ui-conversation/client' {
16
+ interface ChatNodeDataMap {
17
+ /** dsh-plugin-om 压缩替换检查点渲染的摘要卡片数据。 */
18
+ 'om-compaction': OmCompactionChatData;
19
+ }
20
+ }
21
+ /** 压缩卡片载荷:摘要文本与遮蔽统计(seq/time 由节点本体提供,不重复存放)。 */
22
+ export interface OmCompactionChatData {
23
+ /** compaction/summary 的文本摘要;窗口裁剪把该事件留在窗外时为 null(卡片不可展开)。 */
24
+ readonly summary: string | null;
25
+ /** 已载入的 compaction/summary 事件 seq,窗外时为 null。 */
26
+ readonly summaryEventSeq: number | null;
27
+ /** 被遮蔽的表层节点数,summary 事件缺失或载荷非法时为 null。 */
28
+ readonly shadowedItemCount: number | null;
29
+ /** 遮蔽的 token 数,summary 事件缺失或载荷非法时为 null。 */
30
+ readonly shadowedTokenCount: number | null;
31
+ /** 压缩前的字符数(被压缩内容文本长度合计),载荷缺失或非法时为 null。 */
32
+ readonly shadowedCharCount: number | null;
33
+ /** 压缩后的字符数(摘要文本长度),summary 不可用或非法时为 null。 */
34
+ readonly summaryCharCount: number | null;
35
+ /** 压缩后的估算 token 数(4 字符 ≈ 1 token,与服务端 estimateTextTokens 同一启发式),summary 不可用或非法时为 null。 */
36
+ readonly summaryTokenCount: number | null;
37
+ }
38
+ /** 压缩生命周期关联状态:summary / checkpoint 事件证据。 */
39
+ interface OmCompactionState {
40
+ readonly summary?: ConversationMatch;
41
+ readonly checkpoint?: ConversationMatch;
42
+ }
43
+ /**
44
+ * 从压缩替换检查点(user/message + replace surface + source.plugin 为本插件)
45
+ * 读取关联 identity。宿主的 'compact' 检查点由宿主自己渲染,本插件不认领,
46
+ * 避免同一压缩出现两张卡片。
47
+ */
48
+ export declare function checkpointCompactionId(event: SessionEvent): string | undefined;
49
+ /**
50
+ * 插件压缩生命周期定义:compaction/start 开启上下文,summary / 替换检查点 /
51
+ * end 作为 update 折叠证据;仅在存在替换检查点时产出卡片节点。
52
+ */
53
+ export declare const omCompactionDefinition: ConversationNodeDefinition<OmCompactionState>;
54
+ export {};
55
+ //# sourceMappingURL=definition.d.ts.map
@@ -0,0 +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;AAInE,uCAAuC;AACvC,eAAO,MAAM,oBAAoB,kBAAkB,CAAC;AAEpD,OAAO,QAAQ,gDAAgD,CAAC;IAC9D,UAAU,eAAe;QACvB,sCAAsC;QACtC,eAAe,EAAE,oBAAoB,CAAC;KACvC;CACF;AAED,gDAAgD;AAChD,MAAM,WAAW,oBAAoB;IACnC,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,2CAA2C;IAC3C,QAAQ,CAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,6CAA6C;IAC7C,QAAQ,CAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,0FAA0F;IAC1F,QAAQ,CAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3C;AAED,4CAA4C;AAC5C,UAAU,iBAAiB;IACzB,QAAQ,CAAC,OAAO,CAAC,EAAE,iBAAiB,CAAC;IACrC,QAAQ,CAAC,UAAU,CAAC,EAAE,iBAAiB,CAAC;CACzC;AAgBD;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,GAAG,SAAS,CAe9E;AAyED;;;GAGG;AACH,eAAO,MAAM,sBAAsB,EAAE,0BAA0B,CAAC,iBAAiB,CA8BhF,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * dsh-plugin-om 浏览器客户端贡献:压缩卡片。
3
+ *
4
+ * 服务端压缩替换消息继续使用插件自身的检查点标记(source.plugin =
5
+ * 'dsh-plugin-om');宿主 conversation UI 只识别内置的 'compact' 标记,因此本
6
+ * bundle 自行注册一条 conversation 业务定义 + keyed 渲染器,认领插件的压缩
7
+ * 生命周期事件与替换检查点,在消息列表渲染「已压缩」卡片。
8
+ */
9
+ import type { Context } from '@deepseek-ai/cordis';
10
+ /** Required services: 聊天节点槽、会话事件注册表与 locale 服务。 */
11
+ export declare const inject: string[];
12
+ /**
13
+ * Client plugin body: 注册压缩卡片的业务定义与 keyed 渲染器。
14
+ * 注册挂在 effect 包装器上,插件卸载时随之移除。
15
+ * @param ctx - client root context.
16
+ */
17
+ export declare function apply(ctx: Context): void;
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAYnD,mDAAmD;AACnD,eAAO,MAAM,MAAM,UAA4C,CAAC;AAEhE;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAexC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * `om-compaction` namespace dictionaries: 插件压缩卡片的界面文案。
3
+ *
4
+ * 与宿主 conversation 命名空间分离(独立 NS),插件卡片走自己的 keyed 渲染器,
5
+ * 文案键不与对话插件的键冲突。
6
+ */
7
+ /** Dictionary namespace owned by this plugin. */
8
+ export declare const NS = "om-compaction";
9
+ /** Simplified Chinese dictionary (the key-set source of truth). */
10
+ export declare const zh: {
11
+ readonly compaction: "上下文已压缩";
12
+ readonly 'compaction.completed': "已压缩 {items} 条历史记录(约 {tokens} tokens)";
13
+ readonly 'compaction.stats': "压缩前 {items} 条消息 · {beforeChars} 字符(约 {beforeTokens} tokens)→ 压缩后 {afterChars} 字符(约 {afterTokens} tokens)";
14
+ readonly 'compaction.expand': "点击查看压缩摘要";
15
+ readonly 'compaction.unavailable': "压缩摘要不可用";
16
+ };
17
+ /** English dictionary(键集与 zh 一致)。 */
18
+ export declare const en: Record<keyof typeof zh, string>;
19
+ declare module '@deepseek-ai/dsh-client-ui-slots' {
20
+ interface LocaleNamespaceMap {
21
+ /** Compaction card copy owned by dsh-plugin-om. */
22
+ 'om-compaction': keyof typeof zh;
23
+ }
24
+ }
25
+ //# sourceMappingURL=locales.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../src/client/locales.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,iDAAiD;AACjD,eAAO,MAAM,EAAE,kBAAkB,CAAC;AAElC,mEAAmE;AACnE,eAAO,MAAM,EAAE;;;;;;CAOL,CAAC;AAEX,qCAAqC;AACrC,eAAO,MAAM,EAAE,EAAE,MAAM,CAAC,MAAM,OAAO,EAAE,EAAE,MAAM,CAO9C,CAAC;AAEF,OAAO,QAAQ,kCAAkC,CAAC;IAChD,UAAU,kBAAkB;QAC1B,mDAAmD;QACnD,eAAe,EAAE,MAAM,OAAO,EAAE,CAAC;KAClC;CACF"}
package/dist/client.js ADDED
@@ -0,0 +1,259 @@
1
+ window.__ModuleLoader__.load({
2
+ id: "dsh-plugin-om",
3
+ factory: (require) => {
4
+ var module = { exports: {} };
5
+ var exports = module.exports;
6
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
+ let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
8
+ let react = require("react");
9
+ let react_jsx_runtime = require("react/jsx-runtime");
10
+ //#endregion
11
+ //#region src/client/definition.ts
12
+ /** 压缩卡片渲染器分发键(合并进 ChatNodeDataMap)。 */
13
+ const COMPACTION_CARD_KIND = "om-compaction";
14
+ /**
15
+ * replace-surface 判定:surfaceOp 为 { op: 'replace' } 对象(与宿主 runtime 的
16
+ * isReplacementSurfaceEvent 同义)。宿主该助手位于浏览器 bundle 内
17
+ * (window.__ModuleLoader__ 闭包),node 端测试无法求值,故本地实现同一形状检查。
18
+ */
19
+ function isReplacementSurface(event) {
20
+ const surfaceOp = event.surfaceOp;
21
+ return typeof surfaceOp === "object" && surfaceOp !== null && surfaceOp.op === "replace";
22
+ }
23
+ /**
24
+ * 从压缩替换检查点(user/message + replace surface + source.plugin 为本插件)
25
+ * 读取关联 identity。宿主的 'compact' 检查点由宿主自己渲染,本插件不认领,
26
+ * 避免同一压缩出现两张卡片。
27
+ */
28
+ function checkpointCompactionId(event) {
29
+ if (event.type !== "user/message" || !isReplacementSurface(event)) return void 0;
30
+ const source = event.data.source;
31
+ if (source === void 0 || source.kind !== "plugin" || source.plugin !== "dsh-plugin-om" || typeof source.compactionId !== "string") return;
32
+ return source.compactionId;
33
+ }
34
+ /** 从 compaction/summary 载荷提取摘要文本与遮蔽统计(载荷非法时各字段回落 null)。 */
35
+ function compactSummaryData(summaryMatch) {
36
+ let summary = null;
37
+ let shadowedItemCount = null;
38
+ let shadowedTokenCount = null;
39
+ let shadowedCharCount = null;
40
+ if (summaryMatch?.event.type === "compaction/summary") {
41
+ const data = summaryMatch.event.data;
42
+ if (Array.isArray(data.summary)) {
43
+ const text = data.summary.map((block) => block.type === "text" ? block.text : "").join("");
44
+ summary = text.trim() === "" ? null : text;
45
+ }
46
+ shadowedItemCount = Array.isArray(data.shadowedSeqs) && data.shadowedSeqs.every((seq) => Number.isSafeInteger(seq) && seq >= 0) ? data.shadowedSeqs.length : null;
47
+ shadowedTokenCount = Number.isSafeInteger(data.shadowedTokenCount) && data.shadowedTokenCount >= 0 ? data.shadowedTokenCount : null;
48
+ shadowedCharCount = data.shadowedCharCount !== void 0 && Number.isSafeInteger(data.shadowedCharCount) && data.shadowedCharCount >= 0 ? data.shadowedCharCount : null;
49
+ }
50
+ return {
51
+ summary,
52
+ summaryEventSeq: summaryMatch?.event.seq ?? null,
53
+ shadowedItemCount,
54
+ shadowedTokenCount,
55
+ shadowedCharCount,
56
+ summaryCharCount: summary === null ? null : summary.length,
57
+ summaryTokenCount: summary === null ? null : Math.ceil(summary.length / 4)
58
+ };
59
+ }
60
+ /** 窗口只载入检查点(生命周期事件在窗外)时的回落证据扫描。 */
61
+ function fallbackState(context) {
62
+ const summary = context.matches.find((match) => match.event.type === "compaction/summary");
63
+ const checkpoint = context.matches.find((match) => checkpointCompactionId(match.event) !== void 0);
64
+ return {
65
+ ...summary === void 0 ? {} : { summary },
66
+ ...checkpoint === void 0 ? {} : { checkpoint }
67
+ };
68
+ }
69
+ /** 构建最终 Chat 目标节点(与 ui-conversation 的 chatNode 助手同构)。 */
70
+ function chatNode(context, kind, anchorSeq, data) {
71
+ return {
72
+ key: context.key,
73
+ kind,
74
+ id: context.id,
75
+ target: "chat",
76
+ anchorSeq,
77
+ location: context.start?.location ?? context.matches[0]?.location ?? { kind: "unresolved" },
78
+ visibility: "visible",
79
+ data
80
+ };
81
+ }
82
+ /**
83
+ * 插件压缩生命周期定义:compaction/start 开启上下文,summary / 替换检查点 /
84
+ * end 作为 update 折叠证据;仅在存在替换检查点时产出卡片节点。
85
+ */
86
+ const omCompactionDefinition = {
87
+ kind: COMPACTION_CARD_KIND,
88
+ target: "chat",
89
+ match: (event) => {
90
+ const compactionId = checkpointCompactionId(event);
91
+ if (compactionId !== void 0) return {
92
+ id: compactionId,
93
+ role: "update"
94
+ };
95
+ if (event.type === "compaction/start" || event.type === "compaction/summary" || event.type === "compaction/end") {
96
+ const id = event.data.compactionId;
97
+ if (typeof id !== "string" || id === "") return null;
98
+ return {
99
+ id,
100
+ role: event.type === "compaction/start" ? "start" : "update"
101
+ };
102
+ }
103
+ return null;
104
+ },
105
+ start: () => ({}),
106
+ update: (context, match) => {
107
+ if (match.event.type === "compaction/summary") return {
108
+ ...context.state,
109
+ summary: match
110
+ };
111
+ if (checkpointCompactionId(match.event) !== void 0) return {
112
+ ...context.state,
113
+ checkpoint: match
114
+ };
115
+ return context.state;
116
+ },
117
+ buildViewNode: (context) => {
118
+ const state = context.state ?? fallbackState(context);
119
+ if (state.checkpoint === void 0) return null;
120
+ const data = compactSummaryData(state.summary);
121
+ return chatNode(context, COMPACTION_CARD_KIND, state.checkpoint.event.seq, data);
122
+ }
123
+ };
124
+ //#endregion
125
+ //#region src/client/locales.ts
126
+ /**
127
+ * `om-compaction` namespace dictionaries: 插件压缩卡片的界面文案。
128
+ *
129
+ * 与宿主 conversation 命名空间分离(独立 NS),插件卡片走自己的 keyed 渲染器,
130
+ * 文案键不与对话插件的键冲突。
131
+ */
132
+ /** Dictionary namespace owned by this plugin. */
133
+ const NS = "om-compaction";
134
+ /** Simplified Chinese dictionary (the key-set source of truth). */
135
+ const zh = {
136
+ compaction: "上下文已压缩",
137
+ "compaction.completed": "已压缩 {items} 条历史记录(约 {tokens} tokens)",
138
+ "compaction.stats": "压缩前 {items} 条消息 · {beforeChars} 字符(约 {beforeTokens} tokens)→ 压缩后 {afterChars} 字符(约 {afterTokens} tokens)",
139
+ "compaction.expand": "点击查看压缩摘要",
140
+ "compaction.unavailable": "压缩摘要不可用"
141
+ };
142
+ /** English dictionary(键集与 zh 一致)。 */
143
+ const en = {
144
+ compaction: "Context compacted",
145
+ "compaction.completed": "Compacted {items} messages (~{tokens} tokens)",
146
+ "compaction.stats": "{items} messages · {beforeChars} chars (~{beforeTokens} tokens) before → {afterChars} chars (~{afterTokens} tokens) after",
147
+ "compaction.expand": "Click to view summary",
148
+ "compaction.unavailable": "Summary unavailable"
149
+ };
150
+ //#endregion
151
+ //#region src/client/OmCompactionCard.tsx
152
+ /** 卡片样式类名(与宿主 ContextInjectionRow.module.css 同款规则,见下方注册)。 */
153
+ const css = {
154
+ root: "om-compaction-root",
155
+ chevron: "om-compaction-chevron",
156
+ sep: "om-compaction-sep",
157
+ summary: "om-compaction-summary",
158
+ body: "om-compaction-body"
159
+ };
160
+ /** 宿主 ContextInjectionRow.module.css 的规则(逐字一致,仅类名按插件前缀)。 */
161
+ const cardCss = `
162
+ .${css.root}{min-width:0}
163
+ .${css.root}[data-open]{padding-bottom:4px}
164
+ .${css.chevron}{color:var(--dsw-alias-label-secondary)}
165
+ .${css.sep}{background:var(--dsw-alias-label-caption);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}
166
+ .${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}
167
+ .${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}
168
+ `;
169
+ /** 注册卡片样式(与宿主 client bundle 同机制;无 document 的环境如 node 测试直接跳过)。 */
170
+ if (typeof document !== "undefined" && document.querySelector("style[data-dsh-plugin-om-card]") === null) {
171
+ const tag = document.createElement("style");
172
+ tag.dataset.dshPluginOmCard = "true";
173
+ tag.textContent = cardCss;
174
+ document.head.appendChild(tag);
175
+ }
176
+ /** 折叠式压缩卡片(统计标题行 + 代码块样式 summary 展开,同「上下文注入」卡片)。 */
177
+ const OmCompactionCard = (0, react.memo)(function OmCompactionCard({ node, t }) {
178
+ const [expanded, setExpanded] = (0, react.useState)(false);
179
+ const { data } = node;
180
+ const expandable = data.summary !== null;
181
+ const open = expandable && expanded;
182
+ const stats = data.shadowedItemCount !== null && data.shadowedCharCount !== null && data.shadowedTokenCount !== null && data.summaryCharCount !== null && data.summaryTokenCount !== null ? t("compaction.stats", {
183
+ items: data.shadowedItemCount,
184
+ beforeChars: data.shadowedCharCount,
185
+ beforeTokens: data.shadowedTokenCount,
186
+ afterChars: data.summaryCharCount,
187
+ afterTokens: data.summaryTokenCount
188
+ }) : data.shadowedItemCount !== null && data.shadowedTokenCount !== null ? t("compaction.completed", {
189
+ items: data.shadowedItemCount,
190
+ tokens: data.shadowedTokenCount
191
+ }) : expandable ? t("compaction.expand") : t("compaction.unavailable");
192
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
193
+ style: styles.row,
194
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.DisclosureRow, {
195
+ className: css.root,
196
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBrowseOutline16, { size: 14 }),
197
+ chevronClassName: css.chevron,
198
+ title: t("compaction"),
199
+ collapsedContent: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
200
+ className: css.sep,
201
+ "aria-hidden": true
202
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
203
+ className: css.summary,
204
+ "data-om-compaction-summary": true,
205
+ children: stats
206
+ })] }),
207
+ keepContentWhenOpen: true,
208
+ expandable,
209
+ expandOnRowClick: true,
210
+ open,
211
+ onToggle: () => {
212
+ setExpanded((value) => !value);
213
+ },
214
+ children: data.summary !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
215
+ className: css.body,
216
+ style: styles.body,
217
+ children: data.summary
218
+ })
219
+ })
220
+ });
221
+ });
222
+ const styles = {
223
+ row: { padding: "2px 12px" },
224
+ /** 摘要为 <history> 文本,保留换行(宿主 body 的白色空间由内容形态各自处理)。 */
225
+ body: { whiteSpace: "pre-wrap" }
226
+ };
227
+ //#endregion
228
+ //#region src/client/index.ts
229
+ /** Required services: 聊天节点槽、会话事件注册表与 locale 服务。 */
230
+ const inject = [
231
+ "slots",
232
+ "conversationEvents",
233
+ "locale"
234
+ ];
235
+ /**
236
+ * Client plugin body: 注册压缩卡片的业务定义与 keyed 渲染器。
237
+ * 注册挂在 effect 包装器上,插件卸载时随之移除。
238
+ * @param ctx - client root context.
239
+ */
240
+ function apply(ctx) {
241
+ ctx.effect(() => ctx.locale.register(NS, {
242
+ zh,
243
+ en
244
+ }), "dsh-plugin-om: compaction card dictionaries");
245
+ ctx.effect(() => ctx.conversationEvents.register(omCompactionDefinition), "dsh-plugin-om: compaction definition");
246
+ ctx.slots.inject("conversation.chat.node", () => ctx.slots.register({
247
+ name: "conversation.chat.node",
248
+ key: "om-compaction",
249
+ locale: NS
250
+ }, OmCompactionCard));
251
+ }
252
+ //#endregion
253
+ exports.apply = apply;
254
+ exports.inject = inject;
255
+ return module.exports;
256
+ }
257
+ });
258
+
259
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","names":["memo","useState","DisclosureRow","IconBrowseOutline16"],"sources":["../src/constants.ts","../src/client/definition.ts","../src/client/locales.ts","../src/client/OmCompactionCard.tsx","../src/client/index.ts"],"sourcesContent":["/**\n * 共享常量:集中定义插件级魔法字符串与事件名,避免散落各模块。\n */\n\n/** 插件标识:压缩消息 source.plugin 取值(注入压缩日志的来源标记)与日志前缀。 */\nexport const PLUGIN_LABEL = 'dsh-plugin-om';\n\n/** 压缩日志标签名:<history>...</history> 包裹观察/反思日志块(输入与输出均为合法 history 块)。 */\nexport const HISTORY_TAG = 'history';\n\n/** 压缩日志块开标签上的 tip 属性(对 AI 的提醒:本块是历史压缩产物,不要复述)。 */\nexport const HISTORY_TIP = '当前块是历史消息的压缩产物,不要复述';\n\n/**\n * 「完整消息」定义(提示词 / recall 工具描述 / 块顶注释共用同一字符串)。\n * 完整消息是摘要日志与 recall 共用的定位单位;首条 index 为 0,按会话顺序递增、全局稳定。\n * 用户消息指 user_message 中 source.kind 为 user 的部分;其余部分(宿主注入的上下文等)\n * 为系统消息,同样是一条完整消息。\n */\nexport const COMPLETE_MESSAGE_DEFINITION =\n '`完整消息`被定义为`用户消息`,`系统消息`,`模型输出文本`和`具有result的toolcall`的集合。首条`完整消息`的index是0,后续的index递增。';\n\n/** 判定 user/message 的 source 是否为本插件自产(压缩日志机制消息;含兼容旧宿主 checkpoint 标记 'compact')。这类消息不占完整消息 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/** 旧日志压缩消息的宿主 checkpoint 标记 plugin 名(dsh-compaction-basic 的 COMPACT_CHECKPOINT_MARKER.plugin;历史兼容识别用)。 */\nexport const COMPACT_CHECKPOINT_PLUGIN = 'compact';\n","/**\n * 压缩卡片业务定义:认领插件自产的压缩生命周期事件与替换检查点,\n * 聚合出可渲染的摘要卡片节点。\n *\n * 宿主 conversation 客户端仅识别 source.plugin === 'compact' 的压缩检查点\n * (ui-conversation 的 compactionDefinition),插件自产的检查点标记为\n * PLUGIN_LABEL('dsh-plugin-om'),由本定义认领。生命周期事件(compaction/start\n * |summary|end)同时会被宿主的 compactionDefinition 匹配,但宿主没有检查点证据\n * 时不产出节点(buildViewNode 返回 null),因此双方共存无视觉冲突。\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 { PLUGIN_LABEL } from '../constants.ts';\nimport type { CompactionSummaryPayload } from '../types.ts';\n\n/** 压缩卡片渲染器分发键(合并进 ChatNodeDataMap)。 */\nexport const COMPACTION_CARD_KIND = 'om-compaction';\n\ndeclare module '@deepseek-ai/dsh-client-ui-conversation/client' {\n interface ChatNodeDataMap {\n /** dsh-plugin-om 压缩替换检查点渲染的摘要卡片数据。 */\n 'om-compaction': OmCompactionChatData;\n }\n}\n\n/** 压缩卡片载荷:摘要文本与遮蔽统计(seq/time 由节点本体提供,不重复存放)。 */\nexport interface OmCompactionChatData {\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,与服务端 estimateTextTokens 同一启发式),summary 不可用或非法时为 null。 */\n readonly summaryTokenCount: number | null;\n}\n\n/** 压缩生命周期关联状态:summary / checkpoint 事件证据。 */\ninterface OmCompactionState {\n readonly summary?: ConversationMatch;\n readonly checkpoint?: ConversationMatch;\n}\n\n/**\n * replace-surface 判定:surfaceOp 为 { op: 'replace' } 对象(与宿主 runtime 的\n * isReplacementSurfaceEvent 同义)。宿主该助手位于浏览器 bundle 内\n * (window.__ModuleLoader__ 闭包),node 端测试无法求值,故本地实现同一形状检查。\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 * 读取关联 identity。宿主的 'compact' 检查点由宿主自己渲染,本插件不认领,\n * 避免同一压缩出现两张卡片。\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 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/** 窗口只载入检查点(生命周期事件在窗外)时的回落证据扫描。 */\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 return {\n ...(summary === undefined ? {} : { summary }),\n ...(checkpoint === undefined ? {} : { checkpoint }),\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): 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: 'visible',\n data,\n };\n}\n\n/**\n * 插件压缩生命周期定义:compaction/start 开启上下文,summary / 替换检查点 /\n * end 作为 update 折叠证据;仅在存在替换检查点时产出卡片节点。\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 (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 if (state.checkpoint === undefined) return null;\n const data = compactSummaryData(state.summary);\n return chatNode(context, COMPACTION_CARD_KIND, state.checkpoint.event.seq, data);\n },\n};\n","/**\n * `om-compaction` namespace dictionaries: 插件压缩卡片的界面文案。\n *\n * 与宿主 conversation 命名空间分离(独立 NS),插件卡片走自己的 keyed 渲染器,\n * 文案键不与对话插件的键冲突。\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} 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} messages · {beforeChars} chars (~{beforeTokens} tokens) before → {afterChars} chars (~{afterTokens} tokens) after',\n 'compaction.expand': 'Click to view summary',\n 'compaction.unavailable': 'Summary unavailable',\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 * dsh-plugin-om 压缩卡片渲染器:与宿主「上下文注入」卡片同款的折叠行。\n *\n * 复用平台原语 DisclosureRow(宿主 ContextInjectionRow 用的同一外壳组件);行内\n * 统计与展开体样式按宿主 ContextInjectionRow.module.css 的规则注入——宿主该卡片\n * 的样式是编译期哈希的 CSS Module,插件 bundle 无法引用其类名,故按宿主 client\n * bundle 的同一机制(注入 <style>)注册逐字一致的规则,保证视觉同款。\n *\n * 压缩检查点遮蔽的是模型可见表层,人类转录中的历史仍在其上方;卡片只报告\n * 模型从何处起不再看到那段历史。summary 来自检查点引用的 compaction/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';\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/** 注册卡片样式(与宿主 client bundle 同机制;无 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 const expandable = data.summary !== null;\n const open = expandable && expanded;\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: data.shadowedItemCount,\n beforeChars: data.shadowedCharCount,\n beforeTokens: data.shadowedTokenCount,\n afterChars: data.summaryCharCount,\n afterTokens: data.summaryTokenCount,\n })\n : data.shadowedItemCount !== null && data.shadowedTokenCount !== null\n ? t('compaction.completed', {\n items: data.shadowedItemCount,\n tokens: 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: { padding: '2px 12px' },\n /** 摘要为 <history> 文本,保留换行(宿主 body 的白色空间由内容形态各自处理)。 */\n body: { whiteSpace: 'pre-wrap' },\n};\n","/**\n * dsh-plugin-om 浏览器客户端贡献:压缩卡片。\n *\n * 服务端压缩替换消息继续使用插件自身的检查点标记(source.plugin =\n * 'dsh-plugin-om');宿主 conversation UI 只识别内置的 'compact' 标记,因此本\n * bundle 自行注册一条 conversation 业务定义 + keyed 渲染器,认领插件的压缩\n * 生命周期事件与替换检查点,在消息列表渲染「已压缩」卡片。\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 声明合并\n// (均由 ui-conversation 声明),注册调用才得以类型化。\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client';\nimport { omCompactionDefinition } from './definition.ts';\nimport { en, NS, zh } from './locales.ts';\nimport { OmCompactionCard } from './OmCompactionCard.tsx';\n\n/** Required services: 聊天节点槽、会话事件注册表与 locale 服务。 */\nexport const inject = ['slots', 'conversationEvents', 'locale'];\n\n/**\n * Client plugin body: 注册压缩卡片的业务定义与 keyed 渲染器。\n * 注册挂在 effect 包装器上,插件卸载时随之移除。\n * @param ctx - client root context.\n */\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.slots.inject('conversation.chat.node', () =>\n ctx.slots.register(\n { name: 'conversation.chat.node', key: 'om-compaction', locale: NS },\n OmCompactionCard,\n ),\n );\n}\n"],"mappings":"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"}
@@ -9,7 +9,7 @@ export type TokenEstimator = {
9
9
  /**
10
10
  * 未压缩消息 token 估算:最后一个 <history> 块之后的表层节点合计
11
11
  * (其前含自身视为已压缩,不计入观察阈值衡量对象;无压缩日志时计全部)。
12
- * 用户消息中合法 <system-reminder> 块(宿主注入的提醒)的 token 扣除,不计入阈值。
12
+ * 系统消息(user/message 中非 kind:user 的部分,如宿主注入的上下文)不计入阈值。
13
13
  */
14
14
  export declare function measureUncompressedTokens(session: Session, meter: TokenEstimator): number;
15
15
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"compress.d.ts","sourceRoot":"","sources":["../src/compress.ts"],"names":[],"mappings":"AAqCA,OAAO,KAAK,EACV,KAAK,EAEL,OAAO,EACP,YAAY,EACZ,OAAO,EAIR,MAAM,YAAY,CAAC;AACpB,OAAO,EAA0B,KAAK,YAAY,EAAsB,MAAM,YAAY,CAAC;AAE3F,+DAA+D;AAC/D,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvD;AA0CD,+DAA+D;AAC/D,MAAM,MAAM,cAAc,GAAG;IAAE,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAA;CAAE,CAAC;AAmB3E;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,cAAc,GAAG,MAAM,CAwBzF;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAc1E;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,MAAM,GAChB;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,CAaA;AA4FD;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,QAAQ,CAAC,YAAY,CAAC,EAC9B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,YAAY,EACpB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CA2Gf;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,QAAQ,CAAC,YAAY,CAAC,EAC9B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,YAAY,EACpB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAkIf;AAED;;;GAGG;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,IAAI,CAAC,CAwCf"}
1
+ {"version":3,"file":"compress.d.ts","sourceRoot":"","sources":["../src/compress.ts"],"names":[],"mappings":"AAoCA,OAAO,KAAK,EACV,KAAK,EAGL,OAAO,EACP,YAAY,EACZ,OAAO,EAIR,MAAM,YAAY,CAAC;AACpB,OAAO,EAAgB,KAAK,YAAY,EAAqC,MAAM,YAAY,CAAC;AAEhG,+DAA+D;AAC/D,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvD;AAoDD,+DAA+D;AAC/D,MAAM,MAAM,cAAc,GAAG;IAAE,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAA;CAAE,CAAC;AAE3E;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,cAAc,GAAG,MAAM,CAyBzF;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAc1E;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,MAAM,GAChB;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,CAaA;AAiGD;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,QAAQ,CAAC,YAAY,CAAC,EAC9B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,YAAY,EACpB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAiHf;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,QAAQ,CAAC,YAAY,CAAC,EAC9B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,YAAY,EACpB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CA2If;AAED;;;GAGG;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,IAAI,CAAC,CAwCf"}
@@ -10,8 +10,15 @@ export declare const HISTORY_TIP = "\u5F53\u524D\u5757\u662F\u5386\u53F2\u6D88\u
10
10
  /**
11
11
  * 「完整消息」定义(提示词 / recall 工具描述 / 块顶注释共用同一字符串)。
12
12
  * 完整消息是摘要日志与 recall 共用的定位单位;首条 index 为 0,按会话顺序递增、全局稳定。
13
+ * 用户消息指 user_message 中 source.kind 为 user 的部分;其余部分(宿主注入的上下文等)
14
+ * 为系统消息,同样是一条完整消息。
13
15
  */
14
- export declare const COMPLETE_MESSAGE_DEFINITION = "`\u7528\u6237\u6D88\u606F`\uFF0C`\u6A21\u578B\u8F93\u51FA\u6587\u672C`\u548C`\u5177\u6709result\u7684toolcall`\u88AB\u89C6\u4F5C`\u5B8C\u6574\u6D88\u606F`\u3002\u9996\u6761`\u5B8C\u6574\u6D88\u606F`\u7684index\u662F0\uFF0C\u540E\u7EED\u7684index\u9012\u589E\u3002";
16
+ export declare const COMPLETE_MESSAGE_DEFINITION = "`\u5B8C\u6574\u6D88\u606F`\u88AB\u5B9A\u4E49\u4E3A`\u7528\u6237\u6D88\u606F`\uFF0C`\u7CFB\u7EDF\u6D88\u606F`\uFF0C`\u6A21\u578B\u8F93\u51FA\u6587\u672C`\u548C`\u5177\u6709result\u7684toolcall`\u7684\u96C6\u5408\u3002\u9996\u6761`\u5B8C\u6574\u6D88\u606F`\u7684index\u662F0\uFF0C\u540E\u7EED\u7684index\u9012\u589E\u3002";
17
+ /** 判定 user/message 的 source 是否为本插件自产(压缩日志机制消息;含兼容旧宿主 checkpoint 标记 'compact')。这类消息不占完整消息 index。 */
18
+ export declare function isPluginOwnedSource(source: {
19
+ kind?: string;
20
+ plugin?: string;
21
+ } | undefined): boolean;
15
22
  /** 旧日志压缩消息的宿主 checkpoint 标记 plugin 名(dsh-compaction-basic 的 COMPACT_CHECKPOINT_MARKER.plugin;历史兼容识别用)。 */
16
23
  export declare const COMPACT_CHECKPOINT_PLUGIN = "compact";
17
24
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,oDAAoD;AACpD,eAAO,MAAM,YAAY,kBAAkB,CAAC;AAE5C,sEAAsE;AACtE,eAAO,MAAM,WAAW,YAAY,CAAC;AAErC,kDAAkD;AAClD,eAAO,MAAM,WAAW,iHAAuB,CAAC;AAEhD;;;GAGG;AACH,eAAO,MAAM,2BAA2B,4QACqC,CAAC;AAE9E,0GAA0G;AAC1G,eAAO,MAAM,yBAAyB,YAAY,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,oDAAoD;AACpD,eAAO,MAAM,YAAY,kBAAkB,CAAC;AAE5C,sEAAsE;AACtE,eAAO,MAAM,WAAW,YAAY,CAAC;AAErC,kDAAkD;AAClD,eAAO,MAAM,WAAW,iHAAuB,CAAC;AAEhD;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,oUACgD,CAAC;AAEzF,mGAAmG;AACnG,wBAAgB,mBAAmB,CACjC,MAAM,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,GACrD,OAAO,CAGT;AAED,0GAA0G;AAC1G,eAAO,MAAM,yBAAyB,YAAY,CAAC"}