dsh-plugin-om 0.0.21 → 0.0.22

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.
Files changed (47) hide show
  1. package/README.md +69 -159
  2. package/dist/client/OmCompactionCard.d.ts +5 -11
  3. package/dist/client/OmCompactionCard.d.ts.map +1 -1
  4. package/dist/client/definition.d.ts +17 -19
  5. package/dist/client/definition.d.ts.map +1 -1
  6. package/dist/client/format.d.ts +2 -2
  7. package/dist/client/format.d.ts.map +1 -1
  8. package/dist/client/index.d.ts +5 -11
  9. package/dist/client/index.d.ts.map +1 -1
  10. package/dist/client/locales.d.ts +2 -4
  11. package/dist/client/locales.d.ts.map +1 -1
  12. package/dist/client.js +17 -26
  13. package/dist/client.js.map +1 -1
  14. package/dist/compress.d.ts +15 -47
  15. package/dist/compress.d.ts.map +1 -1
  16. package/dist/config.d.ts +12 -21
  17. package/dist/config.d.ts.map +1 -1
  18. package/dist/constants.d.ts +10 -10
  19. package/dist/constants.d.ts.map +1 -1
  20. package/dist/embedding.d.ts +19 -36
  21. package/dist/embedding.d.ts.map +1 -1
  22. package/dist/index.d.ts +1 -22
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.mjs +436 -722
  25. package/dist/json-schema.d.ts +4 -7
  26. package/dist/json-schema.d.ts.map +1 -1
  27. package/dist/log-index.d.ts +19 -12
  28. package/dist/log-index.d.ts.map +1 -1
  29. package/dist/logger.d.ts +3 -3
  30. package/dist/logger.d.ts.map +1 -1
  31. package/dist/model-download.d.ts +7 -11
  32. package/dist/model-download.d.ts.map +1 -1
  33. package/dist/rate-limit.d.ts +9 -14
  34. package/dist/rate-limit.d.ts.map +1 -1
  35. package/dist/recall-output.d.ts +37 -0
  36. package/dist/recall-output.d.ts.map +1 -0
  37. package/dist/recall.d.ts +7 -17
  38. package/dist/recall.d.ts.map +1 -1
  39. package/dist/semantic-recall.d.ts +10 -19
  40. package/dist/semantic-recall.d.ts.map +1 -1
  41. package/dist/summarize.d.ts +29 -46
  42. package/dist/summarize.d.ts.map +1 -1
  43. package/dist/types.d.ts +22 -35
  44. package/dist/types.d.ts.map +1 -1
  45. package/dist/utils.d.ts +9 -8
  46. package/dist/utils.d.ts.map +1 -1
  47. package/package.json +1 -1
package/README.md CHANGED
@@ -2,48 +2,42 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/dsh-plugin-om.svg)](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
- ## 安装与启用
8
-
9
- ### 说明
7
+ ## 功能
10
8
 
11
- - `$DSH_HOME` 缺省为 `~/.dsh`
12
- - *profile*描述了dsh进程的启动模式,官方的启动命令就是名为`web`的profile
9
+ - **自动压缩**(仅主会话,`agent/pre-step` 时阻塞串行执行):
10
+ - **观察**:净压力(上下文压力 − 已压缩 `<history>` 块 token 估算合计)≥ `observeThresholdTokens` 时,摘要未压缩消息并追加为新 `<history>` 块,精确替换被压缩的消息区间(旧块保留)
11
+ - **反思**:全部 `<history>` 块 token 合计 ≥ `reflectThresholdTokens` 时,把多个摘要块合并为一条更紧凑的摘要
12
+ - **输出容错**:摘要输出按首个 `<history>` 开标签到最后一个 `</history>` 定位;整块 XML 非法时按条目标签模糊提取并重建为合法块,再校验无 reasoning 与 index 连续
13
+ - **recall 工具**:按完整消息 index 区间回看原始会话(含被压缩内容;命中消息中的图片附件随结果保留)
14
+ - **recall-semantic 工具**:本地嵌入模型(paraphrase-multilingual-MiniLM-L12-v2)按语义检索全部完整消息(只匹配文本,纯图片消息不进候选池)
15
+ - **压缩卡片**:浏览器客户端在消息列表渲染折叠式「已压缩」卡片与「正在压缩上下文(观察/反思)…」提示行
13
16
 
14
- ### 生产使用
17
+ ## 安装与启用
15
18
 
16
- 安装插件
19
+ - `$DSH_HOME` 缺省为 `~/.dsh`;*profile* 描述 dsh 进程的启动模式(官方启动命令即名为 `web` 的 profile)
17
20
 
18
21
  ```sh
19
22
  dsh plugin --profile <profile> add dsh-plugin-om
20
23
  ```
21
24
 
22
- > 对于 pnpm11+ 添加脚本失败的说明:
23
- > 插件的依赖 `@huggingface/transformers` 自带原生构建脚本,pnpm 11 默认禁止依赖构建脚本,并会抛出异常。
24
- > 把 `$DSH_HOME/profiles/<profile>/pnpm-workspace.yaml` 的 `allowBuilds` 改为 `true` 即可
25
- > 或者使用`dsh plugin --profile <profile> add dsh-plugin-om --allow-build=onnxruntime-node --allow-build=protobufjs --allow-build=sharp`
26
-
27
- 安装完成后,需要重启dsh
25
+ 安装完成后重启 dsh;可用 `dsh --profile <profile> --dump-config` 审查配置。
28
26
 
29
- 可以通过`dsh --profile <profile> --dump-config`审查配置是否正确
27
+ > pnpm 11+ 默认禁止依赖构建脚本,安装失败时把 `$DSH_HOME/profiles/<profile>/pnpm-workspace.yaml` 的 `allowBuilds` 改为 `true`,或使用
28
+ > `dsh plugin --profile <profile> add dsh-plugin-om --allow-build=onnxruntime-node --allow-build=protobufjs --allow-build=sharp`
30
29
 
31
- 如果需要覆盖默认配置,打开 `$DSH_HOME/profiles/<profile>/cordis.patch.yml` 删除里面的空数组,加入
30
+ 覆盖默认配置:编辑 `$DSH_HOME/profiles/<profile>/cordis.patch.yml`,删除空数组并加入(可热更新):
32
31
 
33
32
  ```yaml
34
33
  - id: dsh-plugin-om
35
34
  config:
36
- observeThresholdTokens: 100000
37
- # 其他配置参考下文
35
+ observeThresholdTokens: 35000
38
36
  ```
39
37
 
40
- 不需要重启 可以热更新
41
-
42
38
  ### 开发插件
43
39
 
44
- 运行`pnpm dev`,等待`dist/index.mjs`构筑完毕(本地嵌入模型可在运行时自动下载到跨版本共享目录;如需提前预下载用`pnpm run download:model`,已存在则跳过)
45
-
46
- 在 `cordis.patch.yml` 里加入
40
+ 运行 `pnpm dev` 构建(本地嵌入模型运行时自动下载,也可 `pnpm run download:model` 预下载),在 `cordis.patch.yml` 加入(可热重载):
47
41
 
48
42
  ```yaml
49
43
  - insert:
@@ -51,152 +45,68 @@ dsh plugin --profile <profile> add dsh-plugin-om
51
45
  name: file:///<repo>/dist/index.mjs
52
46
  ```
53
47
 
54
- 可以热重载
55
-
56
- ### 关于`compaction-basic`
57
-
58
- dsh的"预设"分为两层,`dsh web`等同于`dsh --profile web`,调用的是"名为web的profile",进程上的预设
59
-
60
- 而`web-profile`里定义了多个"预设agent"`preset-agent` 这里主要说的是`preset-agent`的问题
61
-
62
- `preset-agent`配置里自带一个`compaction-basic`,会在到达阈值后做简单的摘要,与此插件冲突。
63
-
64
- 由于配置注入的顺序是层级低的覆盖层级高的,所以`cordis.patch.yml`对`compaction-basic`的禁用不会生效。
65
-
66
- 此外,这个插件位于`preset-agent`的定义而非额外的安装,也无法通过`dsh plugin`卸载。
67
-
68
- 解决方案:
69
-
70
- - 直接改`preset-agent`的定义(不推荐)
71
- - 定义不含`compaction-basic`的`preset-agent`
72
- - `compaction-basic`压缩阈值是80%上下文窗口,而OM的观察阈值是绝对 token 数(默认 `observeThresholdTokens`=100000):模型窗口小于该值/0.8(即 12.5 万 tokens)时宿主强制摘要会先于 OM 触发,需要把 `observeThresholdTokens` 调低到窗口的 0.8 以下
73
-
74
- ## 工作原理
48
+ ### 与 compaction-basic 的关系
75
49
 
76
- 1. 在未压缩的消息到达观察阈值后,进行摘要
77
- 2. 将新生成摘要追加到已有摘要后(每条压缩日志是独立的消息/块,旧块原地保留)
78
- 3. 如果摘要总长到达反思阈值,对其本身进行摘要(把全部 <history> 块拼接合并为一条)
79
- 4. 提供recall/recall-semantic两个tool进行检索
80
-
81
- 观察与反思共用同一套系统提示词(buildHistoryPrompt):输入与输出都是合法的 <history> 块(模型消息 + index 的表达形式),先定义块、要求压缩、再给出数据源(下方 <history> 消息记录)。
82
- 观察压缩按 `observeChunkTokens` 边界把未压缩消息分块(完整消息不跨块,thinking/text/toolcall&result 同块)压缩摘要,最多 `observeChunkParallelism` 块同时进行、其余块排队,各块合并为一个 <history> 块提交;提示词按块位次分档——前块要求简单摘要,最后一块要求「越往后越细」保留细节。任一摘要请求遇 429 限流后,插件全局进入冷却期:后续所有摘要请求在 `rateLimitWaitMs` 内不会发出。
83
-
84
- ### 压缩日志块结构
85
-
86
- - 观察压缩只精确替换被压缩的新消息区间:旧 <history> 块保留为独立消息,新观察日志作为新块追加在其后(多块并存按序排列),历史不会随压缩次数膨胀;反思合并时才把多个块合并为一条更紧凑的摘要
87
- - 压缩边界:消息列表中最后一个合法的 <history> 块(source 为插件,plugin 为插件标识 `dsh-plugin-om`;兼容旧日志的宿主 checkpoint 标记 `compact`)之后的消息视为未压缩;其前(含自身)视为已压缩,不重复压缩、不计入观察阈值
88
- - 观察输入经 `@xmldom/xmldom` 构建为合法 <history> 块(用户消息文本/assistant 文本/reasoning 特殊字符自动转义,图片/文件以注释补充;assistant 文本与 toolcall&result 原样;系统消息——user_message 中 source.kind 非 user 的部分,如宿主注入的上下文——渲染为 <sys type="KIND" index="N"></sys> 空块,内容不进入压缩输入)
89
- - 输出经 `@xmldom/xmldom` 解析校验:结构合法(标签匹配/闭合/单块)、不含 <reasoning>、index/start/end 连续(与预期覆盖区间一致),失败按 `compressRetryCount` 重试;观察分块时每块独立校验(预期覆盖各自 index 区间,失败按 `compressRetryCount` 重试),各块校验通过后再合并为一个 <history> 块提交
90
- - 块开标签带 `tip` 属性(对 AI 的提醒:"当前块是历史消息的压缩产物,不要复述");块顶为构成逻辑注释(完整消息定义串 + 条目标签语义),消息正文不再附加前缀句
91
- - 压缩生命周期:每次摘要调用前先追加 `compaction/start`(载荷带 `phase`:`observe`/观察 或 `reflect`/反思,客户端据此渲染「正在压缩上下文(观察/反思)…」提示行);摘要成功提交 summary + 替换消息 + end,summary 载荷带 `attemptCount`(重试次数;观察分块为各块重试之和,反思为尝试次数 - 1);摘要失败或重试耗尽时追加 `compaction/end(error)` 关闭生命周期(不产生 summary/替换),客户端随之撤回提示行
92
-
93
- ### 压缩卡片(消息列表中的「已压缩」展示)
94
-
95
- 插件自产的替换消息使用插件自身标记(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` 加载),自行认领压缩生命周期事件与替换检查点,在消息列表渲染折叠式「已压缩」卡片:
96
-
97
- - 卡片默认折叠,采用与宿主「上下文注入」卡片同款样式:同一 DisclosureRow 外壳组件 + IconBrowseOutline16 图标,行内统计与展开体样式按宿主 ContextInjectionRow 的规则注入(插件 bundle 无法引用宿主编译期哈希的 CSS Module 类名,按宿主 client bundle 的同一机制注入 <style>),视觉一致
98
- - 标题直接展示紧凑统计「N 条 · X 字符(A tokens)→ Y 字符(B tokens)」,数字按 k/w/M 单位化(≥1k 用 k、≥1w 用 w、≥1M 用 M,如 8.6k/3.5w/1.2M):压缩前字符数来自插件扩展 shadowedCharCount,压缩前 token 来自 shadowedTokenCount,压缩后字符数为摘要文本长度,压缩后 token 在客户端按 4 字符 ≈ 1 token 估算(与服务端 estimateTextTokens 同一启发式);旧会话载荷缺少 shadowedCharCount 时回落为「已压缩 N 条历史记录(约 M tokens)」
99
- - 点击展开显示压缩摘要文本,按代码块样式呈现(缩小字号、代码背景与等宽字体、保留换行)
100
- - summary 事件落在当前加载窗口之外时卡片不可展开(不显示空内容)
101
- - 卡片只认领插件自产的检查点(source.plugin = `dsh-plugin-om`);宿主 `compact` 检查点仍由宿主自己渲染,不会出现双卡片
102
- - 压缩进行中(`compaction/start` 已到、summary/检查点未到):渲染不可展开的「正在压缩上下文(观察/反思)…」提示行,按 start 载荷的 `phase` 区分文案(旧会话无 phase 时回落通用文案);压缩失败收到 `compaction/end` 时以 hidden 可见性撤回提示行
103
- - summary 载荷带 `attemptCount`(重试次数)时,重试次数 > 0 在标题统计行追加「重试 N 次」(无重试不显示;旧载荷无 attemptCount 时不显示)
104
- - 平台模块(react / cordis / ui-primitives / ui-slots 等)走宿主冻结模块表(保持 external),其余依赖内联进 bundle
105
-
106
- ### 注意
107
-
108
- - 未压缩消息的 token 统计排除系统消息(user_message 中 source.kind 非 user 的部分,如宿主注入的上下文;宿主注入的提醒不计入观察阈值的触发量)
109
- - recall 不截断,建议保留 `tool-result-pruner`
110
- - recall-semantic 使用本地多语言嵌入模型(paraphrase-multilingual-MiniLM-L12-v2),
111
-
112
- ### 依赖策略
113
-
114
- - dsh宿主提供的依赖,直接复用即可,如 cordis / dsh-tools / zod 等
115
- - `@xmldom/xmldom` 用于 <history> 块的 XML 构建(输入转义)与解析校验(输出结构合法性),经 tsdown `deps.alwaysBundle` 打包进 dist 产物
116
- - 浏览器客户端 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(类型与构建期使用)
117
- - 向量模型模型二进制:量化 ONNX 约 113MB,启用语义召回时下载,位置`$DSH_HOME/plugin-data/dsh-plugin-om/models/<id>/onnx/model_quantized.onnx`。下载失败可以设置`HF_ENDPOINT=https://hf-mirror.com`
50
+ preset-agent 自带 `compaction-basic` 压缩,也会压缩上下文,其压缩阈值为 80% 上下文窗口,一般会先用om进行压缩。
118
51
 
119
52
  ## 插件配置项
120
53
 
121
- | 键 | 默认 | 含义 |
122
- | ----------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
123
- | `observeThresholdTokens` | `100000` | 观察阈值(tokens):未压缩消息 token 估算 ≥ 该值时触发观察压缩 |
124
- | `reflectThresholdTokens` | `30000` | 反思阈值(tokens):全部 <history> 块 token 估算合计该值时触发精简合并 |
125
- | `compressMaxTokens` | `10000` | 反思(合并调用)生成上限;观察分块用 `observeChunkMaxTokens` |
126
- | `observeChunkTokens` | `30000` | 观察分块 token 边界:未压缩消息按该边界拆分为多块并行压缩(完整消息不跨块) |
127
- | `observeChunkMaxTokens` | `5000` | 观察分块单块摘要的生成上限(每块独立调用) |
128
- | `observeChunkParallelism` | `2` | 观察分块压缩的最大并行数:同时进行的单块摘要调用上限,其余块排队(`1` 即串行) |
129
- | `rateLimitWaitMs` | `60000` | 429 限流后,下一次摘要请求发出前至少等待的毫秒数(插件全局共享冷却期:任一请求遇 429 后,所有后续摘要请求——含并行中的其他块——都等满该时长;`0` 视为不限流) |
130
- | `tailMessageCount` | `10` | 尾部保留的不压缩消息条数(不压缩、不被替换、不进摘要日志) |
131
- | `compressRetryCount` | `10` | 摘要调用失败后的最大重试次数(不含首次;总尝试次数 = 该值 + 1) |
132
- | `modelDir` | 共享目录 | recall-semantic 嵌入模型目录(默认 `$DSH_HOME/plugin-data/dsh-plugin-om/models/<id>`,跨插件版本共享;小文件随包分发并在缺失时自动补齐,onnx 缺失且启用语义召回时运行时自动下载到该目录;可指向自定义目录) |
133
- | `omEnabled` | `true` | 是否启用 OM 自动压缩(观察/反思);`false` 时关闭自动压缩,recall/recall-semantic 不受影响。`omEnabled` 替代原 `summaryMode`(见[摘要方式](#摘要方式)) |
134
- | `debug` | dev | 压缩流程步骤级(debug)日志开关:`true` 强制开启、`false` 强制关闭;缺省按 `NODE_ENV !== 'production'` 判定(dev/test 输出,生产隐藏)。**失败日志不受此开关影响,始终输出** |
135
- | `recallEnabled` | `true` | 是否注册 `recall` 工具(`false` 时禁用,不注册) |
136
- | `semanticRecallEnabled` | `true` | 是否注册 `recall-semantic` 工具(`false` 时禁用,不注册、不触发模型下载) |
137
-
138
- > 不建议将观察阈值设置得过高:越早 OM 收益越高,且当前的机制需要模型对消息计数,过多的消息会导致历史混乱
139
-
140
- ### 关于配置项变更的说明
141
-
142
- 配置键 `omEnabled` 替代了原 `summaryMode`:现在只能通过 `omEnabled` 开启或关闭 OM。
143
-
144
- 现在消息调用会固定新开会话,而取消了fork主会话的链路。fork 方式虽然能复用前缀缓存,但需要模型自行对消息计数,会导致严重的索引异常。
54
+ | 键 | 默认 | 含义 |
55
+ | --- | --- | --- |
56
+ | `observeThresholdTokens` | `35000` | 观察阈值(tokens):净压力 ≥ 该值时触发观察压缩 |
57
+ | `reflectThresholdTokens` | `40000` | 反思阈值(tokens):全部 `<history>` 块 token 合计该值时触发合并 |
58
+ | `compressMaxTokens` | `5000` | 单次摘要生成上限 |
59
+ | `rateLimitWaitMs` | `60000` | 429 限流后下一次摘要请求前的等待毫秒数(全局冷却期;`0` 不限流) |
60
+ | `tailMessageCount` | `5` | 尾部保留的不压缩消息条数 |
61
+ | `compressRetryCount` | `5` | 摘要失败后的最大重试次数(不含首次) |
62
+ | `modelDir` | 共享目录 | recall-semantic 嵌入模型目录(默认 `$DSH_HOME/plugin-data/dsh-plugin-om/models/<id>`,onnx 缺失且启用语义召回时运行时自动下载) |
63
+ | `omEnabled` | `true` | 是否启用自动压缩(`false` 时关闭,recall 工具不受影响) |
64
+ | `debug` | dev | 步骤级日志开关(缺省按 `NODE_ENV !== 'production'` 判定;失败日志始终输出) |
65
+ | `recallEnabled` | `true` | 是否注册 `recall` 工具 |
66
+ | `semanticRecallEnabled` | `true` | 是否注册 `recall-semantic` 工具(`false` 时不注册、不触发模型下载) |
67
+
68
+ > 不建议把观察阈值设置得过高:越早压缩收益越高,且机制依赖模型对消息计数,过多消息会导致历史混乱。
145
69
 
146
70
  ## npm 命令
147
71
 
148
- | 命令 | 作用 |
149
- | --------------------------- | --------------------------------------------------------------------------------- |
150
- | `pnpm check` | typecheck + lint + test + build |
151
- | `pnpm typecheck` | TypeScript 类型检查 |
152
- | `pnpm lint` / `pnpm format` | 代码检查 / 格式化 |
153
- | `pnpm test` | vitest 单元测试 |
154
- | `pnpm run download:model` | 手动预下载本地嵌入模型 ONNX 到共享目录(默认 `$DSH_HOME/plugin-data/dsh-plugin-om/models/<id>`;已存在跳过,`--force` 重下;运行时也会按需自动下载) |
155
- | `pnpm build` | |
156
- | `pnpm dev` | 自动打包 |
157
- | `pnpm run release` | 先跑 check(typecheck+lint+test+build),再 CHANGELOG 归档 + 版本号更新 + 打 tag 推送 |
72
+ | 命令 | 作用 |
73
+ | --- | --- |
74
+ | `pnpm check` | typecheck + lint + test + build |
75
+ | `pnpm typecheck` | TypeScript 类型检查 |
76
+ | `pnpm lint` / `pnpm format` | 代码检查 / 格式化 |
77
+ | `pnpm test` | vitest 单元测试 |
78
+ | `pnpm run download:model` | 手动预下载嵌入模型(已存在跳过,`--force` 重下) |
79
+ | `pnpm build` / `pnpm dev` | 构建 / 自动打包 |
80
+ | `pnpm run release` | check → CHANGELOG 归档 → 版本号更新 → 打 tag 推送 |
158
81
 
159
- ## 调用链和文件地图
82
+ ## 文件地图
160
83
 
161
84
  ```
162
- cordis.patch.yml # bundle patch:dsh plugin add 后作为组合层插入插件行(id = dsh-plugin-om)
85
+ cordis.patch.yml # bundle patch:dsh plugin add 后作为组合层插入插件行
163
86
  src/
164
- ├── index.ts # 打包入口(tsdown entry),导出 name / inject / apply
165
- │ apply(ctx, config) 三条主线(标注对应实现文件):
166
- │ ├─ ① resolveConfig(config) ──▶ config.ts # 配置默认值合并 + 宽松校验(未知键忽略、非法值回退默认,冻结返回)
167
- │ ├─ recallEnabled ctx.tools.register(buildRecallTool(() => ctx.get('toolResultPruner')))
168
- │ │ └─▶ recall.ts # recall 工具:按完整消息 index 回看区间(超大结果由 pruner 裁剪)
169
- │ ├─ ③ semanticRecallEnabled 时 ctx.tools.register(buildSemanticRecallTool({ getPruner, modelStatus, embedder }))
170
- │ │ └─▶ semantic-recall.ts # recall-semantic 工具:本地嵌入按语义检索全部完整消息(含被压缩/遮蔽;区间越界回退全量)
171
- │ │ └─▶ embedding.ts # 本地 ONNX 嵌入:ensureModelReady 运行时按需下载(不阻塞/单飞)+ 懒加载 + 批量 embed + cosine
172
- │ │ └─▶ model-download.ts # 模型下载原语(URL/跳过判定/原子落盘;dev CLI 复用)
173
- │ └─ 事件接线(仅主会话生效)
174
- │ └─ ctx.on('agent/pre-step') → compress.ts # maybeCompress:两级压缩阻塞串行(先反思后观察;turn 中间即可触发)
175
- │ ├─ reflectPass → summarize.ts # 全部 <history> token 估算 reflectThresholdTokens:多块拼接 + 共享提示词合并整个块区段
176
- │ ├─ observePass → summarize.ts # 未压缩消息 token 估算 observeThresholdTokens:渲染 <history> 输入 → 观察日志 → 追加 + 替换
177
- │ └─ 提交 → compress.ts # compaction/start(摘要调用前,载荷 phase) summary(attemptCount) → 替换消息(source 插件标识 + compactionId) → end;失败补 end(error);usage 归入主会话
178
- ├── constants.ts # 共享常量(PLUGIN_LABEL / HISTORY_TAG / HISTORY_TIP / COMPLETE_MESSAGE_DEFINITION / COMPACT_CHECKPOINT_PLUGIN)
179
- ├── types.ts # type-only:宿主类型再导出 + 领域类型(MessageNode / MessageIndex)
180
- ├── config.ts # 配置默认值 / 宽松合并(缺省、null、空串回退默认值;未知键忽略、非法值回退默认;数值键/布尔键/omEnabled/modelDir)
181
- ├── utils.ts # 零依赖工具函数(配置校验 / 文本渲染 / 主会话判定 / 路由解析)
182
- ├── log-index.ts # 完整消息索引(index 定位 user/sys/assistant/具有result的toolcall;user_message 按 source.kind 分类:kind:user 为用户消息、其余为系统消息;本插件自产压缩日志消息不占位;未闭合 tool-call 不占位;recall 与摘要共用)
183
- ├── embedding.ts # 本地 ONNX 嵌入(@huggingface/transformers + 本地模型;共享目录解析 / 小文件补齐 / 运行时按需下载编排 / 懒加载 / 批量 / cosine
184
- ├── model-download.ts # 模型下载原语(modelSourceUrl / needsDownload / 原子落盘 / 开始结束日志与失败镜像建议;运行时与 dev CLI 共用)
185
- ├── summarize.ts # 共享提示词 buildHistoryPrompt(观察/反思同一套;mode 控制摘要粒度:summary 简单摘要 / detailed 越往后越细)+ renderMessages(@xmldom/xmldom 构建 <history> 块输入:用户消息原样、系统消息渲染为 <sys> 空块、自动转义)+ 直连 ctx.llm.stream() 摘要(new 方式:指令作 system、输入为渲染消息;extractSummaryLog 提取校验:XML 结构合法 / 无 reasoning / index 连续 / 覆盖区间;重试与流式 usage 归入主会话;每次请求前过全局限流等待门 rate-limit.ts;成功返回 attemptCount(尝试次数,载荷层换算为重试次数))
186
- ├── rate-limit.ts # 全局限流门(插件进程级共享状态):429 识别(isRateLimitError)/ 冷却期记录(noteRateLimit)/ 等待门(gateRateLimit:最近一次 429 + rateLimitWaitMs 之前不放行,等待期间中止立即放弃,新 429 顺延冷却期)
187
- ├── recall.ts # recall 工具
188
- ├── semantic-recall.ts # recall-semantic 工具(query 语义检索 + 区间限定 + 回退全量 + 匹配说明)
189
- └── compress.ts # 两级自动压缩(测量 / mid-turn 区间计算 / 配对平衡回退 / source 标记判定摘要消息 / 观察分块经 runWithConcurrency 有界并发池逐块压缩 + 合并 mergeChunkReports / compaction/* 生命周期事件:start 在摘要调用前追加并带 phase,失败补 end(error) + 替换消息 source 插件标识)
190
- src/client/
191
- ├── index.ts # 浏览器客户端入口(exports["./client"] → dist/client.js):注入 slots/conversationEvents/locale,注册卡片定义与渲染器
192
- ├── definition.ts # 压缩卡片业务定义:认领插件生命周期事件与替换检查点(source.plugin = dsh-plugin-om),聚合摘要卡片节点;start→压缩中提示行(running+phase)、end→hidden 撤回、summary→卡片(retryCount)
193
- ├── OmCompactionCard.tsx # 与宿主「上下文注入」同款的折叠卡片渲染器(统计标题 + 代码块样式 summary 展开)
194
- └── locales.ts # om-compaction 命名空间字典(zh/en)与 LocaleNamespaceMap 声明合并
195
- models/
196
- └── paraphrase-multilingual-MiniLM-L12-v2/ # 嵌入模型目录(小文件随包分发;onnx 二进制不随包分发、由运行时按需下载到跨版本共享目录,不进 git)
197
- scripts/ # release-archive.mjs(CHANGELOG 归档)/ download-model.mjs(开发手动预下载 CLI)
198
- tests/ # vitest 单元测试(服务端 src 各模块 + tests/client/ 客户端卡片定义)
199
- .dsh/skills/ # 项目级 skill(feature-defect-workflow:需求/缺陷完成工作流)
87
+ ├── index.ts # 打包入口:注册 recall 工具 + 接线 pre-step 自动压缩
88
+ ├── config.ts # 配置默认值与宽松合并(未知键忽略、非法值回退默认)
89
+ ├── constants.ts # 共享常量(插件标识 / history 标签 / 完整消息定义)
90
+ ├── types.ts # type-only:宿主类型再导出 + 领域类型
91
+ ├── utils.ts # 零依赖工具函数(文本渲染 / 主会话判定 / 路由解析)
92
+ ├── logger.ts # 插件日志门面(step debug 开关过滤)
93
+ ├── rate-limit.ts # 全局 429 限流冷却门(进程级共享状态)
94
+ ├── log-index.ts # 完整消息索引与渲染(recall 与摘要共用同一套编号)
95
+ ├── recall.ts # recall 工具:按完整消息 index 区间回看
96
+ ├── recall-output.ts # recall 输出契约:{ text, images } 与 render 投影
97
+ ├── semantic-recall.ts # recall-semantic 工具:本地嵌入语义检索
98
+ ├── embedding.ts # 本地 ONNX 嵌入(懒加载 / 批量 / 运行时按需下载编排)
99
+ ├── model-download.ts # 模型下载原语(URL / 跳过判定 / 原子落盘)
100
+ ├── summarize.ts # 共享压缩提示词 + <history> 块渲染与输出校验 + 摘要调用
101
+ ├── compress.ts # 两级自动压缩(观察/反思)与 compaction 生命周期事件
102
+ └── client/ # 浏览器客户端 bundle(压缩卡片)
103
+ ├── index.ts # 客户端入口:注册卡片定义与渲染器
104
+ ├── definition.ts # 压缩卡片业务定义(认领生命周期事件与替换检查点)
105
+ ├── OmCompactionCard.tsx # 折叠卡片渲染器(统计标题 + summary 展开)
106
+ ├── format.ts # 统计数字紧凑格式化(k/w/M
107
+ └── locales.ts # om-compaction 文案字典(zh/en)
108
+ models/ # 嵌入模型目录(小文件随包分发;onnx 运行时按需下载,不进 git)
109
+ scripts/ # release-archive.mjs(CHANGELOG 归档)/ download-model.mjs(预下载 CLI)
110
+ tests/ # vitest 单元测试(服务端各模块 + tests/client/ 客户端卡片)
200
111
  ```
201
112
 
202
- ## TODO
@@ -1,14 +1,8 @@
1
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
- * 事件;窗口裁剪把该事件留在窗外时,行不可展开而不是显示空内容。
2
+ * 压缩卡片渲染器:与宿主「上下文注入」卡片同款的折叠行。
3
+ * 复用平台原语 DisclosureRow;行内统计与展开体样式按宿主 ContextInjectionRow 的规则
4
+ * 注入 <style>(宿主该卡片样式是编译期哈希的 CSS Module,插件 bundle 无法引用其类名)。
5
+ * 卡片报告模型从何处起不再看到那段历史;summary 留在加载窗口外时行不可展开。
12
6
  */
13
7
  import type { ChatNode } from '@deepseek-ai/dsh-client-ui-conversation/client';
14
8
  import type { TranslateNS } from '@deepseek-ai/dsh-client-ui-slots';
@@ -17,6 +11,6 @@ export interface OmCompactionCardProps {
17
11
  readonly node: ChatNode<'om-compaction'>;
18
12
  readonly t: TranslateNS<'om-compaction'>;
19
13
  }
20
- /** 折叠式压缩卡片(统计标题行 + 代码块样式 summary 展开,同「上下文注入」卡片)。 */
14
+ /** 折叠式压缩卡片(统计标题行 + 代码块样式 summary 展开)。 */
21
15
  export declare const OmCompactionCard: import("react").MemoExoticComponent<({ node, t }: OmCompactionCardProps) => import("react").JSX.Element>;
22
16
  //# sourceMappingURL=OmCompactionCard.d.ts.map
@@ -1 +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;AAKpE,0EAA0E;AAC1E,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAC;IACzC,QAAQ,CAAC,CAAC,EAAE,WAAW,CAAC,eAAe,CAAC,CAAC;CAC1C;AAgCD,oDAAoD;AACpD,eAAO,MAAM,gBAAgB,oDAA+C,qBAAqB,iCAuF/F,CAAC"}
1
+ {"version":3,"file":"OmCompactionCard.d.ts","sourceRoot":"","sources":["../../src/client/OmCompactionCard.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gDAAgD,CAAC;AAE/E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAKpE,0EAA0E;AAC1E,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAC;IACzC,QAAQ,CAAC,CAAC,EAAE,WAAW,CAAC,eAAe,CAAC,CAAC;CAC1C;AAgCD,yCAAyC;AACzC,eAAO,MAAM,gBAAgB,oDAA+C,qBAAqB,iCAsF/F,CAAC"}
@@ -1,12 +1,9 @@
1
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),因此双方共存无视觉冲突。
2
+ * 压缩卡片业务定义:认领插件自产的压缩生命周期事件(compaction/start|summary|end)
3
+ * 与替换检查点(source.plugin = 'dsh-plugin-om'),聚合出可渲染的摘要卡片节点。
4
+ * 导出 COMPACTION_CARD_KIND / OmCompactionChatData / checkpointCompactionId /
5
+ * omCompactionDefinition。宿主的 'compact' 检查点由宿主自己渲染,本定义不认领
6
+ * (双方共存无视觉冲突:宿主无检查点证据时不产出节点)。
10
7
  */
11
8
  import type { ConversationMatch, ConversationNodeDefinition } from '@deepseek-ai/dsh-client-runtime/client';
12
9
  import type { SessionEvent } from '@deepseek-ai/dsh-session/types';
@@ -18,11 +15,11 @@ declare module '@deepseek-ai/dsh-client-ui-conversation/client' {
18
15
  'om-compaction': OmCompactionChatData;
19
16
  }
20
17
  }
21
- /** 压缩卡片载荷:摘要文本与遮蔽统计(seq/time 由节点本体提供,不重复存放)。 */
18
+ /** 压缩卡片载荷:摘要文本与遮蔽统计。 */
22
19
  export interface OmCompactionChatData {
23
- /** 压缩进行中(compaction/start 已到、checkpoint/end 未到):渲染为「正在压缩上下文…」提示行。 */
20
+ /** 压缩进行中(start 已到、checkpoint/end 未到):渲染为「正在压缩上下文…」提示行。 */
24
21
  readonly running: boolean;
25
- /** 压缩 pass(观察/反思;来自 start 事件载荷的插件扩展,缺失或非运行态为 null)。 */
22
+ /** 压缩 pass(观察/反思;来自 start 事件载荷扩展,缺失或非运行态为 null)。 */
26
23
  readonly phase: 'observe' | 'reflect' | null;
27
24
  /** compaction/summary 的文本摘要;窗口裁剪把该事件留在窗外时为 null(卡片不可展开)。 */
28
25
  readonly summary: string | null;
@@ -32,13 +29,13 @@ export interface OmCompactionChatData {
32
29
  readonly shadowedItemCount: number | null;
33
30
  /** 遮蔽的 token 数,summary 事件缺失或载荷非法时为 null。 */
34
31
  readonly shadowedTokenCount: number | null;
35
- /** 压缩前的字符数(被压缩内容文本长度合计),载荷缺失或非法时为 null。 */
32
+ /** 压缩前的字符数,载荷缺失或非法时为 null。 */
36
33
  readonly shadowedCharCount: number | null;
37
34
  /** 压缩后的字符数(摘要文本长度),summary 不可用或非法时为 null。 */
38
35
  readonly summaryCharCount: number | null;
39
- /** 压缩后的估算 token 数(4 字符 ≈ 1 token,与服务端 estimateTextTokens 同一启发式),summary 不可用或非法时为 null。 */
36
+ /** 压缩后的估算 token 数(4 字符 ≈ 1 token),summary 不可用或非法时为 null。 */
40
37
  readonly summaryTokenCount: number | null;
41
- /** 摘要调用重试次数(载荷 attemptCount 即重试次数;缺失或非法时为 null)。 */
38
+ /** 摘要调用重试次数,载荷缺失或非法时为 null */
42
39
  readonly retryCount: number | null;
43
40
  }
44
41
  /** 压缩生命周期关联状态:summary / checkpoint / end 事件证据。 */
@@ -49,14 +46,15 @@ interface OmCompactionState {
49
46
  readonly end?: ConversationMatch;
50
47
  }
51
48
  /**
52
- * 从压缩替换检查点(user/message + replace surface + source.plugin 为本插件)
53
- * 读取关联 identity。宿主的 'compact' 检查点由宿主自己渲染,本插件不认领,
54
- * 避免同一压缩出现两张卡片。
49
+ * 从压缩替换检查点(user/message + replace surface + source.plugin 为本插件)读取
50
+ * 关联 compactionId;其余事件返回 undefined。
55
51
  */
56
52
  export declare function checkpointCompactionId(event: SessionEvent): string | undefined;
57
53
  /**
58
- * 插件压缩生命周期定义:compaction/start 开启上下文,summary / 替换检查点 /
59
- * end 作为 update 折叠证据;仅在存在替换检查点时产出卡片节点。
54
+ * 插件压缩生命周期定义:compaction/start 开启上下文,summary / 替换检查点 / end
55
+ * 作为 update 折叠证据。有检查点时产出摘要卡片;无检查点的 end 以 hidden 撤回
56
+ * 进行中提示行(已物化节点以 hidden visibility 保留同一 key);仅 start 时渲染
57
+ * 「正在压缩上下文…」提示行。
60
58
  */
61
59
  export declare const omCompactionDefinition: ConversationNodeDefinition<OmCompactionState>;
62
60
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/client/definition.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EACV,iBAAiB,EAEjB,0BAA0B,EAC3B,MAAM,wCAAwC,CAAC;AAGhD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;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,qEAAqE;IACrE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,uDAAuD;IACvD,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,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;IAC1C,oDAAoD;IACpD,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAED,kDAAkD;AAClD,UAAU,iBAAiB;IACzB,QAAQ,CAAC,OAAO,CAAC,EAAE,iBAAiB,CAAC;IACrC,QAAQ,CAAC,UAAU,CAAC,EAAE,iBAAiB,CAAC;IACxC,oEAAoE;IACpE,QAAQ,CAAC,GAAG,CAAC,EAAE,iBAAiB,CAAC;CAClC;AAgBD;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,GAAG,SAAS,CAe9E;AA0GD;;;GAGG;AACH,eAAO,MAAM,sBAAsB,EAAE,0BAA0B,CAAC,iBAAiB,CAuDhF,CAAC"}
1
+ {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/client/definition.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;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,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;CACpC;AAED,kDAAkD;AAClD,UAAU,iBAAiB;IACzB,QAAQ,CAAC,OAAO,CAAC,EAAE,iBAAiB,CAAC;IACrC,QAAQ,CAAC,UAAU,CAAC,EAAE,iBAAiB,CAAC;IACxC,oEAAoE;IACpE,QAAQ,CAAC,GAAG,CAAC,EAAE,iBAAiB,CAAC;CAClC;AAgBD;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,GAAG,SAAS,CAe9E;AAwGD;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,EAAE,0BAA0B,CAAC,iBAAiB,CAsDhF,CAAC"}
@@ -1,6 +1,6 @@
1
1
  /**
2
- * 压缩卡片统计行的紧凑数字格式:<1k 原样;≥1k 用 k;≥1w(万)用 w;≥1M 用 M
3
- * 保留 1 位小数并去掉末尾的 .0(如 8642 8.6k、34567 3.5w、1234567 → 1.2M)。
2
+ * 压缩卡片统计行的紧凑数字格式化。导出 formatCompactCount
3
+ * <1k 原样;≥1k k;≥1w(万)用 w;≥1M M;保留 1 位小数并去掉末尾 .0。
4
4
  */
5
5
  export declare function formatCompactCount(value: number): string;
6
6
  //# sourceMappingURL=format.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/client/format.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAUxD"}
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/client/format.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CASxD"}
@@ -1,18 +1,12 @@
1
1
  /**
2
- * dsh-plugin-om 浏览器客户端贡献:压缩卡片。
3
- *
4
- * 服务端压缩替换消息继续使用插件自身的检查点标记(source.plugin =
5
- * 'dsh-plugin-om');宿主 conversation UI 只识别内置的 'compact' 标记,因此本
6
- * bundle 自行注册一条 conversation 业务定义 + keyed 渲染器,认领插件的压缩
7
- * 生命周期事件与替换检查点,在消息列表渲染「已压缩」卡片。
2
+ * 浏览器客户端入口(exports["./client"] → dist/client.js):注册压缩卡片的
3
+ * locale 字典、conversation 业务定义与 keyed 渲染器。宿主 conversation UI 只识别
4
+ * 内置 'compact' 检查点,插件自产的压缩检查点(source.plugin = 'dsh-plugin-om')
5
+ * 由本 bundle 认领并在消息列表渲染「已压缩」卡片。
8
6
  */
9
7
  import type { Context } from '@deepseek-ai/cordis';
10
8
  /** Required services: 聊天节点槽、会话事件注册表与 locale 服务。 */
11
9
  export declare const inject: string[];
12
- /**
13
- * Client plugin body: 注册压缩卡片的业务定义与 keyed 渲染器。
14
- * 注册挂在 effect 包装器上,插件卸载时随之移除。
15
- * @param ctx - client root context.
16
- */
10
+ /** Client plugin body: 注册压缩卡片的业务定义与 keyed 渲染器(随插件卸载移除)。 */
17
11
  export declare function apply(ctx: Context): void;
18
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAWnD,mDAAmD;AACnD,eAAO,MAAM,MAAM,UAA4C,CAAC;AAEhE,2DAA2D;AAC3D,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAexC"}
@@ -1,8 +1,6 @@
1
1
  /**
2
- * `om-compaction` namespace dictionaries: 插件压缩卡片的界面文案。
3
- *
4
- * 与宿主 conversation 命名空间分离(独立 NS),插件卡片走自己的 keyed 渲染器,
5
- * 文案键不与对话插件的键冲突。
2
+ * `om-compaction` namespace 字典:插件压缩卡片的界面文案(zh/en)。
3
+ * 导出 NS / zh / en;zh 为键集事实源,en 键集与 zh 一致。
6
4
  */
7
5
  /** Dictionary namespace owned by this plugin. */
8
6
  export declare const NS = "om-compaction";
@@ -1 +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;;;;;;;;;;CAWL,CAAC;AAEX,qCAAqC;AACrC,eAAO,MAAM,EAAE,EAAE,MAAM,CAAC,MAAM,OAAO,EAAE,EAAE,MAAM,CAW9C,CAAC;AAEF,OAAO,QAAQ,kCAAkC,CAAC;IAChD,UAAU,kBAAkB;QAC1B,mDAAmD;QACnD,eAAe,EAAE,MAAM,OAAO,EAAE,CAAC;KAClC;CACF"}
1
+ {"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../src/client/locales.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,iDAAiD;AACjD,eAAO,MAAM,EAAE,kBAAkB,CAAC;AAElC,mEAAmE;AACnE,eAAO,MAAM,EAAE;;;;;;;;;;CAWL,CAAC;AAEX,qCAAqC;AACrC,eAAO,MAAM,EAAE,EAAE,MAAM,CAAC,MAAM,OAAO,EAAE,EAAE,MAAM,CAW9C,CAAC;AAEF,OAAO,QAAQ,kCAAkC,CAAC;IAChD,UAAU,kBAAkB;QAC1B,mDAAmD;QACnD,eAAe,EAAE,MAAM,OAAO,EAAE,CAAC;KAClC;CACF"}
package/dist/client.js CHANGED
@@ -13,17 +13,16 @@ window.__ModuleLoader__.load({
13
13
  const COMPACTION_CARD_KIND = "om-compaction";
14
14
  /**
15
15
  * replace-surface 判定:surfaceOp 为 { op: 'replace' } 对象(与宿主 runtime 的
16
- * isReplacementSurfaceEvent 同义)。宿主该助手位于浏览器 bundle
17
- * (window.__ModuleLoader__ 闭包),node 端测试无法求值,故本地实现同一形状检查。
16
+ * isReplacementSurfaceEvent 同义;宿主该助手位于浏览器 bundle,node 端测试无法求值,
17
+ * 故本地实现同一形状检查)。
18
18
  */
19
19
  function isReplacementSurface(event) {
20
20
  const surfaceOp = event.surfaceOp;
21
21
  return typeof surfaceOp === "object" && surfaceOp !== null && surfaceOp.op === "replace";
22
22
  }
23
23
  /**
24
- * 从压缩替换检查点(user/message + replace surface + source.plugin 为本插件)
25
- * 读取关联 identity。宿主的 'compact' 检查点由宿主自己渲染,本插件不认领,
26
- * 避免同一压缩出现两张卡片。
24
+ * 从压缩替换检查点(user/message + replace surface + source.plugin 为本插件)读取
25
+ * 关联 compactionId;其余事件返回 undefined。
27
26
  */
28
27
  function checkpointCompactionId(event) {
29
28
  if (event.type !== "user/message" || !isReplacementSurface(event)) return void 0;
@@ -62,9 +61,8 @@ window.__ModuleLoader__.load({
62
61
  retryCount
63
62
  };
64
63
  }
65
- /** 压缩进行中提示行的载荷(统计未就绪,全部为 null;phase 取自 start 事件载荷扩展,缺失回退 null)。 */
64
+ /** 压缩进行中提示行的载荷(统计未就绪,全部为 null)。 */
66
65
  function runningData(start) {
67
- /** start 事件载荷(phase 为插件扩展;非法值回退 null)。 */
68
66
  const data = start?.event.data;
69
67
  return {
70
68
  running: true,
@@ -104,8 +102,10 @@ window.__ModuleLoader__.load({
104
102
  };
105
103
  }
106
104
  /**
107
- * 插件压缩生命周期定义:compaction/start 开启上下文,summary / 替换检查点 /
108
- * end 作为 update 折叠证据;仅在存在替换检查点时产出卡片节点。
105
+ * 插件压缩生命周期定义:compaction/start 开启上下文,summary / 替换检查点 / end
106
+ * 作为 update 折叠证据。有检查点时产出摘要卡片;无检查点的 end 以 hidden 撤回
107
+ * 进行中提示行(已物化节点以 hidden visibility 保留同一 key);仅 start 时渲染
108
+ * 「正在压缩上下文…」提示行。
109
109
  */
110
110
  const omCompactionDefinition = {
111
111
  kind: COMPACTION_CARD_KIND,
@@ -159,10 +159,8 @@ window.__ModuleLoader__.load({
159
159
  //#endregion
160
160
  //#region src/client/locales.ts
161
161
  /**
162
- * `om-compaction` namespace dictionaries: 插件压缩卡片的界面文案。
163
- *
164
- * 与宿主 conversation 命名空间分离(独立 NS),插件卡片走自己的 keyed 渲染器,
165
- * 文案键不与对话插件的键冲突。
162
+ * `om-compaction` namespace 字典:插件压缩卡片的界面文案(zh/en)。
163
+ * 导出 NS / zh / en;zh 为键集事实源,en 键集与 zh 一致。
166
164
  */
167
165
  /** Dictionary namespace owned by this plugin. */
168
166
  const NS = "om-compaction";
@@ -193,11 +191,10 @@ window.__ModuleLoader__.load({
193
191
  //#endregion
194
192
  //#region src/client/format.ts
195
193
  /**
196
- * 压缩卡片统计行的紧凑数字格式:<1k 原样;≥1k 用 k;≥1w(万)用 w;≥1M 用 M
197
- * 保留 1 位小数并去掉末尾的 .0(如 8642 8.6k、34567 3.5w、1234567 → 1.2M)。
194
+ * 压缩卡片统计行的紧凑数字格式化。导出 formatCompactCount
195
+ * <1k 原样;≥1k k;≥1w(万)用 w;≥1M M;保留 1 位小数并去掉末尾 .0。
198
196
  */
199
197
  function formatCompactCount(value) {
200
- /** 保留 1 位小数并去掉末尾 .0。 */
201
198
  const trim = (n) => {
202
199
  const text = String(Math.round(n * 10) / 10);
203
200
  return text.endsWith(".0") ? text.slice(0, -2) : text;
@@ -226,19 +223,18 @@ window.__ModuleLoader__.load({
226
223
  .${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}
227
224
  .${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}
228
225
  `;
229
- /** 注册卡片样式(与宿主 client bundle 同机制;无 document 的环境如 node 测试直接跳过)。 */
226
+ /** 注册卡片样式(无 document 的环境如 node 测试直接跳过)。 */
230
227
  if (typeof document !== "undefined" && document.querySelector("style[data-dsh-plugin-om-card]") === null) {
231
228
  const tag = document.createElement("style");
232
229
  tag.dataset.dshPluginOmCard = "true";
233
230
  tag.textContent = cardCss;
234
231
  document.head.appendChild(tag);
235
232
  }
236
- /** 折叠式压缩卡片(统计标题行 + 代码块样式 summary 展开,同「上下文注入」卡片)。 */
233
+ /** 折叠式压缩卡片(统计标题行 + 代码块样式 summary 展开)。 */
237
234
  const OmCompactionCard = (0, react.memo)(function OmCompactionCard({ node, t }) {
238
235
  const [expanded, setExpanded] = (0, react.useState)(false);
239
236
  const { data } = node;
240
237
  if (data.running) {
241
- /** 提示行文案(按 phase 区分观察/反思;缺失回退通用文案)。 */
242
238
  const runningLabel = data.phase === "observe" ? t("compaction.running.observe") : data.phase === "reflect" ? t("compaction.running.reflect") : t("compaction.running");
243
239
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
244
240
  style: styles.row,
@@ -254,7 +250,6 @@ window.__ModuleLoader__.load({
254
250
  }
255
251
  const expandable = data.summary !== null;
256
252
  const open = expandable && expanded;
257
- /** 统计行文案(数字按 k/w/M 单位化;重试次数仅在有重试时追加;retryCount 缺失视为未重试)。 */
258
253
  const stats = data.shadowedItemCount !== null && data.shadowedCharCount !== null && data.shadowedTokenCount !== null && data.summaryCharCount !== null && data.summaryTokenCount !== null ? t("compaction.stats", {
259
254
  items: formatCompactCount(data.shadowedItemCount),
260
255
  beforeChars: formatCompactCount(data.shadowedCharCount),
@@ -298,7 +293,7 @@ window.__ModuleLoader__.load({
298
293
  });
299
294
  const styles = {
300
295
  row: {},
301
- /** 摘要为 <history> 文本,保留换行(宿主 body 的白色空间由内容形态各自处理)。 */
296
+ /** 摘要为 <history> 文本,保留换行。 */
302
297
  body: { whiteSpace: "pre-wrap" }
303
298
  };
304
299
  //#endregion
@@ -309,11 +304,7 @@ window.__ModuleLoader__.load({
309
304
  "conversationEvents",
310
305
  "locale"
311
306
  ];
312
- /**
313
- * Client plugin body: 注册压缩卡片的业务定义与 keyed 渲染器。
314
- * 注册挂在 effect 包装器上,插件卸载时随之移除。
315
- * @param ctx - client root context.
316
- */
307
+ /** Client plugin body: 注册压缩卡片的业务定义与 keyed 渲染器(随插件卸载移除)。 */
317
308
  function apply(ctx) {
318
309
  ctx.effect(() => ctx.locale.register(NS, {
319
310
  zh,