dsh-plugin-om 0.0.26 → 0.0.28
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 +67 -64
- package/dist/client/OmWarningCard.d.ts +2 -2
- package/dist/client/definition.d.ts +8 -6
- package/dist/client/definition.d.ts.map +1 -1
- package/dist/client/index.d.ts +2 -2
- package/dist/client.js +47 -7
- package/dist/client.js.map +1 -1
- package/dist/compaction-log.d.ts +21 -21
- package/dist/compaction-log.d.ts.map +1 -1
- package/dist/compress.d.ts +7 -7
- package/dist/compress.d.ts.map +1 -1
- package/dist/config.d.ts +2 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/degrade.d.ts +3 -3
- package/dist/degrade.d.ts.map +1 -1
- package/dist/index.mjs +202 -116
- package/dist/om-event.d.ts +65 -0
- package/dist/om-event.d.ts.map +1 -0
- package/dist/summarize.d.ts +24 -13
- package/dist/summarize.d.ts.map +1 -1
- package/dist/types.d.ts +10 -32
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,36 +2,37 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/dsh-plugin-om)
|
|
4
4
|
|
|
5
|
-
在 DSH 里应用 [Observational Memory](https://mastra.ai/research/observational-memory)
|
|
5
|
+
在 DSH 里应用 [Observational Memory](https://mastra.ai/research/observational-memory) 风格的上下文管理:自动把历史消息压缩为摘要并提供工具回看原始内容。
|
|
6
6
|
|
|
7
7
|
## 功能
|
|
8
8
|
|
|
9
|
-
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
-
|
|
9
|
+
- **自动压缩**:仅主会话,在 agent/pre-step 阻塞串行执行。净压力达到 `observeThresholdTokens` 后再累计 `tailMessageCount` 条完整消息时,把触发点前的全部消息摘要为新 `<history>` 块并精确替换对应消息区间;全部 `<history>` 块 token 合计达到 `reflectThresholdTokens` 时把全部块内文拼合为单个 `<history>` 块送入摘要,合并为一条更紧凑的摘要。待定标记以 log-only 会话事件持久化,重启后从日志恢复
|
|
10
|
+
- **输出容错**:摘要输出按 `<history>` 标签定位,整块非法时按条目标签模糊提取并重建为合法块。重试全部耗尽后拒绝当前 step;每次实际发出的摘要调用无论成功失败都把完整提示词与模型原始输出即时落盘为 one-shot 诊断子会话
|
|
11
|
+
- **降级容错**:systemPrompt 或 tokenMeter 服务异常时按 0 计继续压缩,问题通过 console 输出与 log-only 会话事件上报,同会话同一问题至多一条
|
|
12
|
+
- **recall 工具**:按完整消息 index 区间回看原始会话,含被压缩内容,图片附件随结果保留
|
|
13
|
+
- **recall-semantic 工具**:本地嵌入模型 paraphrase-multilingual-MiniLM-L12-v2 按语义检索全部完整消息,只匹配文本,纯图片消息不进候选池
|
|
14
|
+
- **压缩卡片**:浏览器客户端渲染折叠式已压缩卡片、压缩中提示行与可展开的失败错误行
|
|
15
|
+
- **降级警告行**:浏览器客户端把 om 警告会话事件渲染为可展开的警告行
|
|
16
|
+
|
|
17
|
+
## 已知风险
|
|
18
|
+
|
|
19
|
+
- **借用 `feedback/record` 事件**:插件的 log-only 会话事件(警告与观察压缩标记)写入宿主已知类型 `feedback/record` 的 `text` 字段(`om:1:` 前缀 JSON 信封,见 `src/om-event.ts`)。原因是持久化读取路径拒绝目录外未知事件类型而 `Session.append` 不提供 ignorable 写入途径,借用宿主目录内的无配对审计事件是插件写入私有事件的唯一可行通道
|
|
20
20
|
|
|
21
21
|
## 安装与启用
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
`$DSH_HOME` 缺省为 `~/.dsh`,profile 描述 dsh 进程的启动模式。
|
|
24
24
|
|
|
25
25
|
```sh
|
|
26
26
|
dsh plugin --profile <profile> add dsh-plugin-om
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
安装完成后重启 dsh
|
|
29
|
+
安装完成后重启 dsh,可用 `dsh --profile <profile> --dump-config` 审查配置。
|
|
30
30
|
|
|
31
|
-
> pnpm 11+ 默认禁止依赖构建脚本,安装失败时把 `$DSH_HOME/profiles/<profile>/pnpm-workspace.yaml` 的 `allowBuilds` 改为 `true
|
|
32
|
-
> `dsh plugin --profile <profile> add dsh-plugin-om --allow-build=onnxruntime-node --allow-build=protobufjs --allow-build=sharp`
|
|
31
|
+
> pnpm 11+ 默认禁止依赖构建脚本,安装失败时把 `$DSH_HOME/profiles/<profile>/pnpm-workspace.yaml` 的 `allowBuilds` 改为 `true`,或安装时追加 `--allow-build=onnxruntime-node --allow-build=protobufjs --allow-build=sharp`
|
|
33
32
|
|
|
34
|
-
|
|
33
|
+
### 配置覆盖
|
|
34
|
+
|
|
35
|
+
编辑 `$DSH_HOME/profiles/<profile>/cordis.patch.yml`,删除空数组并加入,可热更新:
|
|
35
36
|
|
|
36
37
|
```yaml
|
|
37
38
|
- id: dsh-plugin-om
|
|
@@ -41,7 +42,7 @@ dsh plugin --profile <profile> add dsh-plugin-om
|
|
|
41
42
|
|
|
42
43
|
### 开发插件
|
|
43
44
|
|
|
44
|
-
运行 `pnpm dev`
|
|
45
|
+
运行 `pnpm dev` 构建,本地嵌入模型运行时自动下载,也可 `pnpm run download:model` 预下载。在 `cordis.patch.yml` 加入,可热重载:
|
|
45
46
|
|
|
46
47
|
```yaml
|
|
47
48
|
- insert:
|
|
@@ -51,27 +52,28 @@ dsh plugin --profile <profile> add dsh-plugin-om
|
|
|
51
52
|
|
|
52
53
|
### 与 compaction-basic 的关系
|
|
53
54
|
|
|
54
|
-
preset-agent 自带
|
|
55
|
+
preset-agent 自带 compaction-basic 压缩,阈值为上下文窗口的 80%,一般先用 om 进行压缩。
|
|
55
56
|
|
|
56
57
|
## 插件配置项
|
|
57
58
|
|
|
58
59
|
| 键 | 默认 | 含义 |
|
|
59
60
|
| --- | --- | --- |
|
|
60
|
-
| `observeThresholdTokens` | `45000` |
|
|
61
|
-
| `reflectThresholdTokens` | `120000` |
|
|
62
|
-
| `compressMaxTokens` | 不设置 |
|
|
63
|
-
| `rateLimitWaitMs` | `60000` | 遇 429
|
|
64
|
-
| `tailMessageCount` | `5` |
|
|
65
|
-
| `compressRetryCount` | `5` |
|
|
66
|
-
| `
|
|
67
|
-
| `
|
|
68
|
-
| `
|
|
61
|
+
| `observeThresholdTokens` | `45000` | 净压力达到该值时触发观察压缩 |
|
|
62
|
+
| `reflectThresholdTokens` | `120000` | 全部 `<history>` 块 token 合计达到该值时触发反思合并 |
|
|
63
|
+
| `compressMaxTokens` | 不设置 | 单次摘要生成上限,不设置时由模型适配器默认值决定 |
|
|
64
|
+
| `rateLimitWaitMs` | `60000` | 遇 429 限流后下一次摘要请求前的等待毫秒数,`0` 不限流 |
|
|
65
|
+
| `tailMessageCount` | `5` | 观察触发后等待新增完整消息达到该条数才执行压缩,`0` 表示触发当轮立即执行 |
|
|
66
|
+
| `compressRetryCount` | `5` | 摘要失败后的最大重试次数,不含首次 |
|
|
67
|
+
| `compressSkipReasoning` | `true` | 观察压缩请求是否携带被压缩 assistant 消息的 reasoning 思考文本,`true` 时不携带 `<reasoning>` 参考条目,压缩指令同步省略对应说明 |
|
|
68
|
+
| `modelDir` | 共享目录 | recall-semantic 嵌入模型目录,默认 `$DSH_HOME/plugin-data/dsh-plugin-om/models/<id>`,onnx 缺失且启用语义召回时运行时自动下载 |
|
|
69
|
+
| `omEnabled` | `true` | 是否启用自动压缩,关闭后 recall 工具不受影响 |
|
|
70
|
+
| `debug` | dev | 步骤级日志开关,缺省按 `NODE_ENV` 非 production 判定,压缩尝试结果与失败日志始终输出 |
|
|
69
71
|
| `recallEnabled` | `true` | 是否注册 `recall` 工具 |
|
|
70
|
-
| `semanticRecallEnabled` | `true` | 是否注册 `recall-semantic`
|
|
72
|
+
| `semanticRecallEnabled` | `true` | 是否注册 `recall-semantic` 工具,关闭时不触发模型下载 |
|
|
71
73
|
|
|
72
74
|
> 不建议把观察阈值设置得过高:越早压缩收益越高,且机制依赖模型对消息计数,过多消息会导致历史混乱。
|
|
73
75
|
|
|
74
|
-
> 想直观理解机制并估算不同参数下的 token 成本,可打开交互式[机制说明与成本计算器](https://fanethedivine.github.io/dsh-plugin-om/)
|
|
76
|
+
> 想直观理解机制并估算不同参数下的 token 成本,可打开交互式[机制说明与成本计算器](https://fanethedivine.github.io/dsh-plugin-om/),部署在 GitHub Pages,不随插件包分发。
|
|
75
77
|
|
|
76
78
|
## npm 命令
|
|
77
79
|
|
|
@@ -81,45 +83,46 @@ preset-agent 自带 `compaction-basic` 压缩,也会压缩上下文,其压
|
|
|
81
83
|
| `pnpm typecheck` | TypeScript 类型检查 |
|
|
82
84
|
| `pnpm lint` / `pnpm format` | 代码检查 / 格式化 |
|
|
83
85
|
| `pnpm test` | vitest 单元测试 |
|
|
84
|
-
| `pnpm run download:model` |
|
|
86
|
+
| `pnpm run download:model` | 手动预下载嵌入模型,已存在跳过,`--force` 重下 |
|
|
85
87
|
| `pnpm build` / `pnpm dev` | 构建 / 自动打包 |
|
|
86
88
|
| `pnpm run release` | check → CHANGELOG 归档 → 版本号更新 → 打 tag 推送 |
|
|
87
89
|
|
|
88
90
|
## 文件地图
|
|
89
91
|
|
|
90
92
|
```
|
|
91
|
-
cordis.patch.yml
|
|
93
|
+
cordis.patch.yml # bundle patch,dsh plugin add 后作为组合层插入插件行
|
|
92
94
|
src/
|
|
93
|
-
├── index.ts
|
|
94
|
-
├── config.ts
|
|
95
|
-
├── constants.ts
|
|
96
|
-
├── degrade.ts
|
|
97
|
-
├──
|
|
98
|
-
├──
|
|
99
|
-
├──
|
|
100
|
-
├──
|
|
101
|
-
├──
|
|
102
|
-
├──
|
|
103
|
-
├──
|
|
104
|
-
├──
|
|
105
|
-
├──
|
|
106
|
-
├──
|
|
107
|
-
├──
|
|
108
|
-
├──
|
|
109
|
-
├──
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
├──
|
|
114
|
-
├──
|
|
115
|
-
├──
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
95
|
+
├── index.ts # 打包入口:注册 recall 工具并接线 pre-step 自动压缩
|
|
96
|
+
├── config.ts # 配置默认值与宽松合并,未知键忽略、非法值回退默认
|
|
97
|
+
├── constants.ts # 共享常量:插件标识、history 标签、完整消息定义
|
|
98
|
+
├── degrade.ts # 挂载失败降级上报:console 外部输出与 om 警告会话事件
|
|
99
|
+
├── om-event.ts # om 事件借用通道:feedback/record 信封的编解码与读写
|
|
100
|
+
├── types.ts # type-only:宿主类型再导出与领域类型
|
|
101
|
+
├── utils.ts # 零依赖工具函数:文本渲染、主会话判定、路由解析
|
|
102
|
+
├── json-schema.ts # zod schema 到工具 wire 参数 JSON Schema 的转换
|
|
103
|
+
├── logger.ts # 插件日志门面,step 按 debug 开关过滤
|
|
104
|
+
├── rate-limit.ts # 全局 429 限流冷却门,进程级共享状态
|
|
105
|
+
├── log-index.ts # 完整消息索引与渲染,recall 与摘要共用同一套编号
|
|
106
|
+
├── recall.ts # recall 工具:按完整消息 index 区间回看
|
|
107
|
+
├── recall-output.ts # recall 输出契约:{ text, images } 与 render 投影
|
|
108
|
+
├── semantic-recall.ts # recall-semantic 工具:本地嵌入语义检索
|
|
109
|
+
├── embedding.ts # 本地 ONNX 嵌入:懒加载、批量、运行时按需下载编排
|
|
110
|
+
├── model-download.ts # 模型下载原语:URL、跳过判定、原子落盘
|
|
111
|
+
├── summarize.ts # 共享压缩提示词、history 块渲染与输出校验、摘要调用
|
|
112
|
+
├── compaction-log.ts # 压缩日志落盘:诊断子会话创建与单次尝试原样消息组
|
|
113
|
+
├── compress.ts # 两级自动压缩:观察与反思、失败中断传播、compaction 生命周期事件
|
|
114
|
+
└── client/ # 浏览器客户端 bundle:压缩卡片
|
|
115
|
+
├── index.ts # 客户端入口:注册卡片定义与渲染器
|
|
116
|
+
├── definition.ts # 压缩卡片业务定义:认领生命周期事件、检查点替换与 om 警告事件
|
|
117
|
+
├── OmCompactionCard.tsx # 折叠卡片渲染器:统计标题与 summary、失败报错展开
|
|
118
|
+
├── OmWarningCard.tsx # 功能降级警告行渲染器:折叠摘要与完整说明展开
|
|
119
|
+
├── format.ts # 统计数字紧凑格式化:k、w、M
|
|
120
|
+
└── locales.ts # om-compaction 文案字典:zh 与 en
|
|
121
|
+
models/ # 嵌入模型目录:小文件随包分发,onnx 运行时按需下载,不进 git
|
|
122
|
+
scripts/ # release-archive.mjs 为 CHANGELOG 归档脚本,download-model.mjs 为预下载 CLI
|
|
123
|
+
tests/ # vitest 测试:服务端各模块、客户端卡片、成本模型与整条链路集成测试
|
|
124
|
+
web/ # 机制说明与成本计算器站点:独立 Vite + React + Tailwind CSS + shadcn/ui 工程,发布到 GitHub Pages,不随插件包分发
|
|
125
|
+
├── src/model.ts # 成本模型纯函数:om 开关全会话模拟与三类 token 计价
|
|
126
|
+
└── src/components/ # 机制简述、侧边栏参数面板、合并单元格成本表、shadcn/ui 原语
|
|
127
|
+
.github/workflows/web-deploy.yml # web/ 变更合入 main 时构建并部署 GitHub Pages
|
|
124
128
|
```
|
|
125
|
-
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 功能降级警告行渲染器:与压缩卡片同款的折叠行。
|
|
3
|
-
* 折叠行显示降级说明摘要,展开体显示完整说明;数据来自 om/warning
|
|
4
|
-
*
|
|
3
|
+
* 折叠行显示降级说明摘要,展开体显示完整说明;数据来自 om/warning 信封载荷
|
|
4
|
+
* (借用 feedback/record),服务端按会话同问题去重后追加(每会话同一问题至多一行)。
|
|
5
5
|
*/
|
|
6
6
|
import type { ChatNode } from '@deepseek-ai/dsh-client-ui-conversation/client';
|
|
7
7
|
import type { TranslateNS } from '@deepseek-ai/dsh-client-ui-slots';
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 压缩卡片业务定义:认领插件自产的压缩生命周期事件(compaction/start|summary|end)
|
|
3
3
|
* 与替换检查点(source.plugin = 'dsh-plugin-om'),聚合出可渲染的摘要卡片节点;
|
|
4
|
-
* 并认领 om/warning
|
|
4
|
+
* 并认领 om 警告信封事件(借用 feedback/record,kind 为 om/warning,见 om-event.ts)
|
|
5
|
+
* 渲染为警告行。
|
|
5
6
|
* 导出 COMPACTION_CARD_KIND / OmCompactionChatData / checkpointCompactionId /
|
|
6
7
|
* omCompactionDefinition / OM_WARNING_CARD_KIND / OmWarningChatData / omWarningDefinition。
|
|
7
8
|
* 宿主的 'compact' 检查点由宿主自己渲染,本定义不认领
|
|
@@ -66,16 +67,17 @@ export declare function checkpointCompactionId(event: SessionEvent): string | un
|
|
|
66
67
|
* 提示行。
|
|
67
68
|
*/
|
|
68
69
|
export declare const omCompactionDefinition: ConversationNodeDefinition<OmCompactionState>;
|
|
69
|
-
/**
|
|
70
|
+
/** 功能降级警告行载荷:降级问题标识与面向用户的说明(信封载荷非法时为 null)。 */
|
|
70
71
|
export interface OmWarningChatData {
|
|
71
|
-
/** 降级问题标识(om/warning
|
|
72
|
+
/** 降级问题标识(om/warning 信封载荷 problem)。 */
|
|
72
73
|
readonly problem: string | null;
|
|
73
|
-
/** 面向用户的降级说明(om/warning
|
|
74
|
+
/** 面向用户的降级说明(om/warning 信封载荷 message)。 */
|
|
74
75
|
readonly message: string | null;
|
|
75
76
|
}
|
|
76
77
|
/**
|
|
77
|
-
* 插件功能降级警告定义:每条 om/warning
|
|
78
|
-
*
|
|
78
|
+
* 插件功能降级警告定义:每条 om/warning 信封事件独立成节点(id 含 seq),渲染为可
|
|
79
|
+
* 展开的「功能降级」警告行。服务端按会话同问题去重后追加,每会话同一问题至多一行;
|
|
80
|
+
* 不带 om 信封的 feedback/record 记录(用户自写反馈)不认领。
|
|
79
81
|
*/
|
|
80
82
|
export declare const omWarningDefinition: ConversationNodeDefinition;
|
|
81
83
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/client/definition.ts"],"names":[],"mappings":"AAAA
|
|
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,+BAA+B;IAC/B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,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;AAuID;;;;;;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"}
|
package/dist/client/index.d.ts
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* 浏览器客户端入口(exports["./client"] → dist/client.js):注册压缩卡片与功能降级
|
|
3
3
|
* 警告行的 locale 字典、conversation 业务定义与 keyed 渲染器。宿主 conversation UI 只
|
|
4
4
|
* 识别内置 'compact' 检查点,插件自产的压缩检查点(source.plugin = 'dsh-plugin-om')
|
|
5
|
-
* 由本 bundle 认领并在消息列表渲染「已压缩」卡片;om
|
|
6
|
-
*
|
|
5
|
+
* 由本 bundle 认领并在消息列表渲染「已压缩」卡片;om 警告信封事件(借用
|
|
6
|
+
* feedback/record)渲染为「功能降级」警告行。
|
|
7
7
|
*/
|
|
8
8
|
import type { Context } from '@deepseek-ai/cordis';
|
|
9
9
|
/** Required services: 聊天节点槽、会话事件注册表与 locale 服务。 */
|
package/dist/client.js
CHANGED
|
@@ -7,6 +7,44 @@ window.__ModuleLoader__.load({
|
|
|
7
7
|
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
8
8
|
let react = require("react");
|
|
9
9
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
10
|
+
/** 校验载荷字段与类别匹配(运行时守卫,保证返回类型的诚实性)。 */
|
|
11
|
+
function isValidPayload(kind, data) {
|
|
12
|
+
switch (kind) {
|
|
13
|
+
case "om/warning": return typeof data.problem === "string" && typeof data.message === "string";
|
|
14
|
+
case "om/observe-pending": return typeof data.triggerMessageIndex === "number" && Number.isSafeInteger(data.triggerMessageIndex);
|
|
15
|
+
case "om/observe-invalidate": return typeof data.pendingSeq === "number" && Number.isSafeInteger(data.pendingSeq);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* 解码一条会话事件为 om 私有事件:仅识别 feedback/record 中带 om 信封前缀的
|
|
20
|
+
* text;前缀缺失、JSON 非法、kind 未知或载荷字段缺失时返回 undefined。
|
|
21
|
+
*/
|
|
22
|
+
function readOmEvent(event) {
|
|
23
|
+
if (event === void 0 || event === null || event.type !== "feedback/record") return void 0;
|
|
24
|
+
const text = event.data?.text;
|
|
25
|
+
if (typeof text !== "string" || !text.startsWith("om:1:")) return void 0;
|
|
26
|
+
let envelope;
|
|
27
|
+
try {
|
|
28
|
+
envelope = JSON.parse(text.slice(5));
|
|
29
|
+
} catch {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (envelope === null || typeof envelope !== "object" || Array.isArray(envelope)) return void 0;
|
|
33
|
+
const { kind, ...rest } = envelope;
|
|
34
|
+
if (typeof kind !== "string") return void 0;
|
|
35
|
+
if (![
|
|
36
|
+
"om/warning",
|
|
37
|
+
"om/observe-pending",
|
|
38
|
+
"om/observe-invalidate"
|
|
39
|
+
].includes(kind)) return void 0;
|
|
40
|
+
const omKind = kind;
|
|
41
|
+
if (!isValidPayload(omKind, rest)) return void 0;
|
|
42
|
+
return {
|
|
43
|
+
kind: omKind,
|
|
44
|
+
data: rest,
|
|
45
|
+
seq: event.seq
|
|
46
|
+
};
|
|
47
|
+
}
|
|
10
48
|
//#endregion
|
|
11
49
|
//#region src/client/definition.ts
|
|
12
50
|
/** 压缩卡片渲染器分发键(合并进 ChatNodeDataMap)。 */
|
|
@@ -189,14 +227,15 @@ window.__ModuleLoader__.load({
|
|
|
189
227
|
}
|
|
190
228
|
};
|
|
191
229
|
/**
|
|
192
|
-
* 插件功能降级警告定义:每条 om/warning
|
|
193
|
-
*
|
|
230
|
+
* 插件功能降级警告定义:每条 om/warning 信封事件独立成节点(id 含 seq),渲染为可
|
|
231
|
+
* 展开的「功能降级」警告行。服务端按会话同问题去重后追加,每会话同一问题至多一行;
|
|
232
|
+
* 不带 om 信封的 feedback/record 记录(用户自写反馈)不认领。
|
|
194
233
|
*/
|
|
195
234
|
const omWarningDefinition = {
|
|
196
235
|
kind: OM_WARNING_CARD_KIND,
|
|
197
236
|
target: "chat",
|
|
198
237
|
match: (event) => {
|
|
199
|
-
if (event
|
|
238
|
+
if (readOmEvent(event)?.kind !== "om/warning") return null;
|
|
200
239
|
return {
|
|
201
240
|
id: `om-warning:${event.seq}`,
|
|
202
241
|
role: "start"
|
|
@@ -207,9 +246,10 @@ window.__ModuleLoader__.load({
|
|
|
207
246
|
buildViewNode: (context) => {
|
|
208
247
|
const start = context.start;
|
|
209
248
|
if (start === void 0) return null;
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
const
|
|
249
|
+
const om = readOmEvent(start.event);
|
|
250
|
+
if (om?.kind !== "om/warning") return null;
|
|
251
|
+
const problem = om.data.problem !== "" ? om.data.problem : null;
|
|
252
|
+
const message = om.data.message !== "" ? om.data.message : null;
|
|
213
253
|
if (problem === null && message === null) return null;
|
|
214
254
|
return chatNode(context, OM_WARNING_CARD_KIND, start.event.seq, {
|
|
215
255
|
problem,
|
|
@@ -448,7 +488,7 @@ window.__ModuleLoader__.load({
|
|
|
448
488
|
en
|
|
449
489
|
}), "dsh-plugin-om: compaction card dictionaries");
|
|
450
490
|
ctx.effect(() => ctx.conversationEvents.register(omCompactionDefinition), "dsh-plugin-om: compaction definition");
|
|
451
|
-
ctx.effect(() => ctx.conversationEvents.register(omWarningDefinition), "dsh-plugin-om: om
|
|
491
|
+
ctx.effect(() => ctx.conversationEvents.register(omWarningDefinition), "dsh-plugin-om: om warning definition");
|
|
452
492
|
ctx.slots.inject("conversation.chat.node", () => ctx.slots.register({
|
|
453
493
|
name: "conversation.chat.node",
|
|
454
494
|
key: "om-compaction",
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["memo","useState","DisclosureRow","IconBrowseOutline16","memo","useState","DisclosureRow","IconBrowseOutline16"],"sources":["../src/constants.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 * COMPACT_CHECKPOINT_PLUGIN / COMPACTION_ABORTED_ERROR / isPluginOwnedSource。\n */\n\n/** 插件标识:压缩消息 source.plugin 取值与日志前缀。 */\nexport const PLUGIN_LABEL = 'dsh-plugin-om';\n\n/** 压缩日志标签名:<history>...</history> 包裹观察/反思日志块。 */\nexport const HISTORY_TAG = 'history';\n\n/** 压缩日志块开标签的 tip 属性(对 AI 的提醒:本块是历史压缩产物,不要复述)。 */\nexport const HISTORY_TIP = '当前块是历史消息的压缩产物,不要复述';\n\n/**\n * 「完整消息」定义(提示词 / 工具描述 / 块顶注释共用)。\n * 完整消息是摘要日志与 recall 共用的定位单位;首条 index 为 0,按会话顺序递增、全局稳定。\n */\nexport const COMPLETE_MESSAGE_DEFINITION =\n '`完整消息`指一条`用户消息`、`系统消息`、`模型输出文本`或`具有result的toolcall`;首条 index 为 0,按会话顺序递增。';\n\n/** 旧日志压缩消息的宿主 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 * 压缩卡片业务定义:认领插件自产的压缩生命周期事件(compaction/start|summary|end)\n * 与替换检查点(source.plugin = 'dsh-plugin-om'),聚合出可渲染的摘要卡片节点;\n * 并认领 om/warning 功能降级警告事件渲染为警告行。\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 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 /** 摘要调用重试次数,载荷缺失或非法时为 null。 */\n readonly retryCount: 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 let retryCount: 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 retryCount =\n data.attemptCount !== undefined &&\n Number.isSafeInteger(data.attemptCount) &&\n data.attemptCount >= 0\n ? data.attemptCount\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 retryCount,\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 retryCount: 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 retryCount: 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 */\nexport const omWarningDefinition: ConversationNodeDefinition = {\n kind: OM_WARNING_CARD_KIND,\n target: 'chat',\n match: (event) => {\n if (event.type !== '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 data = start.event.data as { problem?: unknown; message?: unknown } | undefined;\n const problem = typeof data?.problem === 'string' && data.problem !== '' ? data.problem : null;\n const message = typeof data?.message === 'string' && data.message !== '' ? 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 'compaction.retries': '重试 {count} 次',\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 'compaction.retries': 'Retried {count} times',\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 const retry =\n data.retryCount !== null && data.retryCount > 0\n ? ` \\u00b7 ${t('compaction.retries', { count: data.retryCount })}`\n : '';\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 {retry}\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 * 服务端按会话同问题去重后追加(每会话同一问题至多一行)。\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/warning 事件渲染为「功能降级」\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 声明合并。\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 * COMPACT_CHECKPOINT_PLUGIN / COMPACTION_ABORTED_ERROR / isPluginOwnedSource。\n */\n\n/** 插件标识:压缩消息 source.plugin 取值与日志前缀。 */\nexport const PLUGIN_LABEL = 'dsh-plugin-om';\n\n/** 压缩日志标签名:<history>...</history> 包裹观察/反思日志块。 */\nexport const HISTORY_TAG = 'history';\n\n/** 压缩日志块开标签的 tip 属性(对 AI 的提醒:本块是历史压缩产物,不要复述)。 */\nexport const HISTORY_TIP = '当前块是历史消息的压缩产物,不要复述';\n\n/**\n * 「完整消息」定义(提示词 / 工具描述 / 块顶注释共用)。\n * 完整消息是摘要日志与 recall 共用的定位单位;首条 index 为 0,按会话顺序递增、全局稳定。\n */\nexport const COMPLETE_MESSAGE_DEFINITION =\n '`完整消息`指一条`用户消息`、`系统消息`、`模型输出文本`或`具有result的toolcall`;首条 index 为 0,按会话顺序递增。';\n\n/** 旧日志压缩消息的宿主 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 /** 摘要调用重试次数,载荷缺失或非法时为 null。 */\n readonly retryCount: 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 let retryCount: 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 retryCount =\n data.attemptCount !== undefined &&\n Number.isSafeInteger(data.attemptCount) &&\n data.attemptCount >= 0\n ? data.attemptCount\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 retryCount,\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 retryCount: 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 retryCount: 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 'compaction.retries': '重试 {count} 次',\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 'compaction.retries': 'Retried {count} times',\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 const retry =\n data.retryCount !== null && data.retryCount > 0\n ? ` \\u00b7 ${t('compaction.retries', { count: data.retryCount })}`\n : '';\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 {retry}\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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"}
|