dsh-plugin-om 0.0.27 → 0.0.29
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 +10 -5
- 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 +12 -8
- package/dist/compaction-log.d.ts.map +1 -1
- package/dist/compress.d.ts +4 -4
- package/dist/compress.d.ts.map +1 -1
- package/dist/degrade.d.ts +3 -3
- package/dist/degrade.d.ts.map +1 -1
- package/dist/index.mjs +142 -45
- package/dist/om-event.d.ts +65 -0
- package/dist/om-event.d.ts.map +1 -0
- package/dist/summarize.d.ts +2 -2
- package/dist/summarize.d.ts.map +1 -1
- package/dist/types.d.ts +7 -29
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,12 +7,16 @@
|
|
|
7
7
|
## 功能
|
|
8
8
|
|
|
9
9
|
- **自动压缩**:仅主会话,在 agent/pre-step 阻塞串行执行。净压力达到 `observeThresholdTokens` 后再累计 `tailMessageCount` 条完整消息时,把触发点前的全部消息摘要为新 `<history>` 块并精确替换对应消息区间;全部 `<history>` 块 token 合计达到 `reflectThresholdTokens` 时把全部块内文拼合为单个 `<history>` 块送入摘要,合并为一条更紧凑的摘要。待定标记以 log-only 会话事件持久化,重启后从日志恢复
|
|
10
|
-
- **输出容错**:摘要输出按 `<history>` 标签定位,整块非法时按条目标签模糊提取并重建为合法块。重试全部耗尽后拒绝当前 step
|
|
11
|
-
- **降级容错**:systemPrompt 或 tokenMeter 服务异常时按 0 计继续压缩,问题通过 console 输出与 log-only
|
|
10
|
+
- **输出容错**:摘要输出按 `<history>` 标签定位,整块非法时按条目标签模糊提取并重建为合法块。重试全部耗尽后拒绝当前 step;每次实际发出的摘要调用无论成功失败都把完整提示词与模型完整输出(thinking、文本、工具调用)即时落盘为 one-shot 诊断子会话
|
|
11
|
+
- **降级容错**:systemPrompt 或 tokenMeter 服务异常时按 0 计继续压缩,问题通过 console 输出与 log-only 会话事件上报,同会话同一问题至多一条
|
|
12
12
|
- **recall 工具**:按完整消息 index 区间回看原始会话,含被压缩内容,图片附件随结果保留
|
|
13
13
|
- **recall-semantic 工具**:本地嵌入模型 paraphrase-multilingual-MiniLM-L12-v2 按语义检索全部完整消息,只匹配文本,纯图片消息不进候选池
|
|
14
14
|
- **压缩卡片**:浏览器客户端渲染折叠式已压缩卡片、压缩中提示行与可展开的失败错误行
|
|
15
|
-
- **降级警告行**:浏览器客户端把
|
|
15
|
+
- **降级警告行**:浏览器客户端把 om 警告会话事件渲染为可展开的警告行
|
|
16
|
+
|
|
17
|
+
## 已知风险
|
|
18
|
+
|
|
19
|
+
- **借用 `feedback/record` 事件**:插件的 log-only 会话事件(警告与观察压缩标记)写入宿主已知类型 `feedback/record` 的 `text` 字段(`om:1:` 前缀 JSON 信封,见 `src/om-event.ts`)。原因是持久化读取路径拒绝目录外未知事件类型而 `Session.append` 不提供 ignorable 写入途径,借用宿主目录内的无配对审计事件是插件写入私有事件的唯一可行通道
|
|
16
20
|
|
|
17
21
|
## 安装与启用
|
|
18
22
|
|
|
@@ -91,7 +95,8 @@ src/
|
|
|
91
95
|
├── index.ts # 打包入口:注册 recall 工具并接线 pre-step 自动压缩
|
|
92
96
|
├── config.ts # 配置默认值与宽松合并,未知键忽略、非法值回退默认
|
|
93
97
|
├── constants.ts # 共享常量:插件标识、history 标签、完整消息定义
|
|
94
|
-
├── degrade.ts # 挂载失败降级上报:console 外部输出与 om
|
|
98
|
+
├── degrade.ts # 挂载失败降级上报:console 外部输出与 om 警告会话事件
|
|
99
|
+
├── om-event.ts # om 事件借用通道:feedback/record 信封的编解码与读写
|
|
95
100
|
├── types.ts # type-only:宿主类型再导出与领域类型
|
|
96
101
|
├── utils.ts # 零依赖工具函数:文本渲染、主会话判定、路由解析
|
|
97
102
|
├── json-schema.ts # zod schema 到工具 wire 参数 JSON Schema 的转换
|
|
@@ -108,7 +113,7 @@ src/
|
|
|
108
113
|
├── compress.ts # 两级自动压缩:观察与反思、失败中断传播、compaction 生命周期事件
|
|
109
114
|
└── client/ # 浏览器客户端 bundle:压缩卡片
|
|
110
115
|
├── index.ts # 客户端入口:注册卡片定义与渲染器
|
|
111
|
-
├── definition.ts # 压缩卡片业务定义:认领生命周期事件、检查点替换与 om
|
|
116
|
+
├── definition.ts # 压缩卡片业务定义:认领生命周期事件、检查点替换与 om 警告事件
|
|
112
117
|
├── OmCompactionCard.tsx # 折叠卡片渲染器:统计标题与 summary、失败报错展开
|
|
113
118
|
├── OmWarningCard.tsx # 功能降级警告行渲染器:折叠摘要与完整说明展开
|
|
114
119
|
├── format.ts # 统计数字紧凑格式化:k、w、M
|
|
@@ -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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"}
|
package/dist/compaction-log.d.ts
CHANGED
|
@@ -1,31 +1,35 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 压缩调用日志落盘:摘要 run 的每次 LLM 调用(每次尝试,无论成功失败)完成后,
|
|
3
|
-
*
|
|
3
|
+
* 把该次尝试的完整提示词与模型完整输出原样落盘为一个 one-shot 诊断子会话
|
|
4
4
|
* (header origin 'subagent' + 首事件 subagent/descriptor),使其以 subagent 形式
|
|
5
5
|
* 出现在宿主子代理列表中,便于查验每次调用的完整会话。导出 recordCompactionAttempt /
|
|
6
6
|
* SummaryAttemptRecord / compactionLogLabel / COMPACTION_LOG_PROVIDER。
|
|
7
7
|
*
|
|
8
8
|
* - 子会话内容零加工:一对 user/message(实际提示词全文,含 <history> 块)
|
|
9
|
-
* + assistant/message
|
|
10
|
-
*
|
|
9
|
+
* + assistant/message(完整内容块:thinking/reasoning、文本输出、工具调用,
|
|
10
|
+
* 异常/中止时为已收集的部分输出),不插入任何额外消息;
|
|
11
|
+
* 成败与原因不进子会话,由调用方写入主会话日志并关联子会话 id
|
|
11
12
|
* - 落盘自身绝不抛错:任何失败仅 logger.warn 并返回 undefined,不影响压缩流程
|
|
12
13
|
*/
|
|
14
|
+
import type { ToolCallBlock } from '@deepseek-ai/dsh-llm';
|
|
13
15
|
import type { Context, Session } from './types.ts';
|
|
14
16
|
import { type RoutedTarget } from './utils.ts';
|
|
15
17
|
/** 诊断子会话的 descriptor provider(宿主子代理列表识别用)。 */
|
|
16
18
|
export declare const COMPACTION_LOG_PROVIDER = "om-compaction-log";
|
|
17
|
-
/** 一次摘要尝试的完整记录:prompt=实际提示词全文(含 <history> 块),rawOutput
|
|
19
|
+
/** 一次摘要尝试的完整记录:prompt=实际提示词全文(含 <history> 块),rawOutput=模型原始文本输出;reasoning=模型 thinking 输出(无则省略),toolCalls=模型请求的工具调用(无则省略)。 */
|
|
18
20
|
export type SummaryAttemptRecord = {
|
|
19
21
|
prompt: string;
|
|
20
22
|
rawOutput: string;
|
|
23
|
+
reasoning?: string;
|
|
24
|
+
toolCalls?: ToolCallBlock[];
|
|
21
25
|
};
|
|
22
|
-
/** 诊断子会话 label
|
|
26
|
+
/** 诊断子会话 label:`OM会话-<阶段>`,有重试时追加 `-重试N`(N = 尝试序号 - 1,首次不写)。 */
|
|
23
27
|
export declare function compactionLogLabel(phase: 'observe' | 'reflect' | undefined, attemptNo: number): string;
|
|
24
28
|
/**
|
|
25
29
|
* 把一次摘要尝试落盘为诊断子会话:ctx.sessions.create 创建子会话(header origin
|
|
26
30
|
* 'subagent'、parentSession 指向主会话、delegationDepth = 父 + 1、cwd 继承主会话),
|
|
27
|
-
* 追加 one-shot descriptor(provider om-compaction-log,label
|
|
28
|
-
* 原样追加「提示词 +
|
|
31
|
+
* 追加 one-shot descriptor(provider om-compaction-log,label 为 `OM会话-<阶段>`,重试时追加 `-重试N`),
|
|
32
|
+
* 原样追加「提示词 + 完整输出内容块(thinking/reasoning、文本、工具调用)」消息组,flush 持久化检查点,返回子会话 id。落盘自身
|
|
29
33
|
* 绝不抛错:任何失败仅 logger.warn 并返回 undefined(不影响压缩流程)。
|
|
30
34
|
*/
|
|
31
35
|
export declare function recordCompactionAttempt(ctx: Context, parentSession: Session, options: {
|
|
@@ -33,7 +37,7 @@ export declare function recordCompactionAttempt(ctx: Context, parentSession: Ses
|
|
|
33
37
|
phase: 'observe' | 'reflect' | undefined;
|
|
34
38
|
/** 摘要调用的路由目标(assistant/message 的 model 来源标记)。 */
|
|
35
39
|
target: RoutedTarget;
|
|
36
|
-
/** 本次尝试的完整记录(提示词 +
|
|
40
|
+
/** 本次尝试的完整记录(提示词 + thinking + 文本输出 + 工具调用)。 */
|
|
37
41
|
attempt: SummaryAttemptRecord;
|
|
38
42
|
/** 尝试序号(1 起,label 与消息 step 标注用)。 */
|
|
39
43
|
attemptNo: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compaction-log.d.ts","sourceRoot":"","sources":["../src/compaction-log.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"compaction-log.d.ts","sourceRoot":"","sources":["../src/compaction-log.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAoB,aAAa,EAAe,MAAM,sBAAsB,CAAC;AAKzF,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,KAAK,YAAY,EAAQ,MAAM,YAAY,CAAC;AAErD,8CAA8C;AAC9C,eAAO,MAAM,uBAAuB,sBAAsB,CAAC;AAE3D,6HAA6H;AAC7H,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,aAAa,EAAE,CAAC;CAC7B,CAAC;AASF,gEAAgE;AAChE,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,EACxC,SAAS,EAAE,MAAM,GAChB,MAAM,CAGR;AAuCD;;;;;;GAMG;AACH,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,OAAO,EACZ,aAAa,EAAE,OAAO,EACtB,OAAO,EAAE;IACP,8BAA8B;IAC9B,KAAK,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;IACzC,iDAAiD;IACjD,MAAM,EAAE,YAAY,CAAC;IACrB,+CAA+C;IAC/C,OAAO,EAAE,oBAAoB,CAAC;IAC9B,oCAAoC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,uCAAuC;IACvC,KAAK,EAAE,OAAO,CAAC;CAChB,GACA,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA+B7B"}
|
package/dist/compress.d.ts
CHANGED
|
@@ -45,10 +45,10 @@ export declare function historySection(session: Session): {
|
|
|
45
45
|
boundarySeq: number | undefined;
|
|
46
46
|
};
|
|
47
47
|
/**
|
|
48
|
-
* 查找当前活跃的观察压缩待定标记:按日志顺序取最后一条 om/observe-pending
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
48
|
+
* 查找当前活跃的观察压缩待定标记:按日志顺序取最后一条 om/observe-pending 信封事件,
|
|
49
|
+
* 其后须无引用它的 om/observe-invalidate(已失效),且其后的压缩边界 seq 不大于标记
|
|
50
|
+
* seq(边界后移说明标记期间已发生过压缩,标记过期——兜底「执行成功但失效标记未写出」
|
|
51
|
+
* 的崩溃窗口)。无活跃标记返回 undefined。
|
|
52
52
|
*/
|
|
53
53
|
export declare function findObservePending(session: Session): {
|
|
54
54
|
seq: number;
|
package/dist/compress.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compress.d.ts","sourceRoot":"","sources":["../src/compress.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"compress.d.ts","sourceRoot":"","sources":["../src/compress.ts"],"names":[],"mappings":"AA4CA,OAAO,KAAK,EACV,KAAK,EAKL,OAAO,EACP,YAAY,EACZ,OAAO,EAIR,MAAM,YAAY,CAAC;AACpB,OAAO,EAAgB,KAAK,YAAY,EAAqC,MAAM,YAAY,CAAC;AAEhG;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAC1B;IAAE,MAAM,EAAE,KAAK,CAAA;CAAE,GACjB;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpF,+DAA+D;AAC/D,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvD;AAuDD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAY1E;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,OAAO,EAChB,eAAe,EAAE,MAAM,GACtB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,SAAS,CA8BpE;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG;IAChD,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC7C,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;CACjC,CAUA;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,OAAO,GACf;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,mBAAmB,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAoB1D;AA0HD;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,QAAQ,CAAC,YAAY,CAAC,EAC9B,MAAM,EAAE,YAAY,EACpB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,kBAAkB,CAAC,CAgI7B;AAwED;;;;;;;;;GASG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,QAAQ,CAAC,YAAY,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,YAAY,EACpB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,kBAAkB,CAAC,CAwO7B;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,QAAQ,CAAC,YAAY,CAAC,EAC9B,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,kBAAkB,CAAC,CAwB7B"}
|
package/dist/degrade.d.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import type { PluginLogger } from './logger.ts';
|
|
2
2
|
import type { Session } from './types.ts';
|
|
3
|
-
/** 降级问题标识(om/warning
|
|
3
|
+
/** 降级问题标识(om/warning 信封载荷 problem;同会话按此去重)。 */
|
|
4
4
|
export type DegradedProblem =
|
|
5
5
|
/** systemPrompt 服务未挂载(ctx.get 返回 undefined):上下文压力不扣系统提示词,观察偏早触发 */
|
|
6
6
|
'systemPrompt-missing'
|
|
7
7
|
/** tokenMeter 服务调用异常(measure/estimateMessage 抛错):压力估算降级,可能跳过观察压缩 */
|
|
8
8
|
| 'tokenMeter-unavailable';
|
|
9
|
-
/** 各降级问题面向用户的简短说明(om/warning
|
|
9
|
+
/** 各降级问题面向用户的简短说明(om/warning 信封载荷 message;客户端警告行直接展示)。 */
|
|
10
10
|
export declare const DEGRADE_PROBLEMS: Record<DegradedProblem, string>;
|
|
11
11
|
/**
|
|
12
12
|
* 报告一次挂载失败类降级:console.warn 始终输出到宿主进程外部;同会话同问题首次
|
|
13
|
-
* 出现时,向会话日志追加 log-only
|
|
13
|
+
* 出现时,向会话日志追加 log-only om 警告事件(客户端渲染警告行,每会话最多
|
|
14
14
|
* 一次)并输出 logger.warn(避免每个 pre-step 重复刷日志)。
|
|
15
15
|
* 日志扫描/事件追加失败只记日志,绝不抛错、不阻塞压缩。
|
|
16
16
|
*/
|
package/dist/degrade.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"degrade.d.ts","sourceRoot":"","sources":["../src/degrade.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"degrade.d.ts","sourceRoot":"","sources":["../src/degrade.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,+CAA+C;AAC/C,MAAM,MAAM,eAAe;AACzB,mEAAmE;AACjE,sBAAsB;AACxB,oEAAoE;GAClE,wBAAwB,CAAC;AAE7B,0DAA0D;AAC1D,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,eAAe,EAAE,MAAM,CAI5D,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,eAAe,GACvB,IAAI,CAiBN"}
|
package/dist/index.mjs
CHANGED
|
@@ -39,30 +39,87 @@ function isPluginOwnedSource(source) {
|
|
|
39
39
|
return source.plugin === "dsh-plugin-om" || source.plugin === "compact";
|
|
40
40
|
}
|
|
41
41
|
//#endregion
|
|
42
|
+
//#region src/om-event.ts
|
|
43
|
+
/** om 信封 text 前缀:标识该 feedback/record 记录由本插件写入。 */
|
|
44
|
+
const OM_EVENT_PREFIX = "om:1:";
|
|
45
|
+
/** 校验载荷字段与类别匹配(运行时守卫,保证返回类型的诚实性)。 */
|
|
46
|
+
function isValidPayload(kind, data) {
|
|
47
|
+
switch (kind) {
|
|
48
|
+
case "om/warning": return typeof data.problem === "string" && typeof data.message === "string";
|
|
49
|
+
case "om/observe-pending": return typeof data.triggerMessageIndex === "number" && Number.isSafeInteger(data.triggerMessageIndex);
|
|
50
|
+
case "om/observe-invalidate": return typeof data.pendingSeq === "number" && Number.isSafeInteger(data.pendingSeq);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* 解码一条会话事件为 om 私有事件:仅识别 feedback/record 中带 om 信封前缀的
|
|
55
|
+
* text;前缀缺失、JSON 非法、kind 未知或载荷字段缺失时返回 undefined。
|
|
56
|
+
*/
|
|
57
|
+
function readOmEvent(event) {
|
|
58
|
+
if (event === void 0 || event === null || event.type !== "feedback/record") return void 0;
|
|
59
|
+
const text = event.data?.text;
|
|
60
|
+
if (typeof text !== "string" || !text.startsWith("om:1:")) return void 0;
|
|
61
|
+
let envelope;
|
|
62
|
+
try {
|
|
63
|
+
envelope = JSON.parse(text.slice(5));
|
|
64
|
+
} catch {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (envelope === null || typeof envelope !== "object" || Array.isArray(envelope)) return void 0;
|
|
68
|
+
const { kind, ...rest } = envelope;
|
|
69
|
+
if (typeof kind !== "string") return void 0;
|
|
70
|
+
if (![
|
|
71
|
+
"om/warning",
|
|
72
|
+
"om/observe-pending",
|
|
73
|
+
"om/observe-invalidate"
|
|
74
|
+
].includes(kind)) return void 0;
|
|
75
|
+
const omKind = kind;
|
|
76
|
+
if (!isValidPayload(omKind, rest)) return void 0;
|
|
77
|
+
return {
|
|
78
|
+
kind: omKind,
|
|
79
|
+
data: rest,
|
|
80
|
+
seq: event.seq
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/** 编码一条 om 私有事件为 feedback/record 的 text 信封。 */
|
|
84
|
+
function encodeOmEvent(kind, data) {
|
|
85
|
+
return `${OM_EVENT_PREFIX}${JSON.stringify({
|
|
86
|
+
kind,
|
|
87
|
+
...data
|
|
88
|
+
})}`;
|
|
89
|
+
}
|
|
90
|
+
/** 追加一条 om 私有事件(借用 feedback/record,log-only,不进 surface),返回事件 seq。 */
|
|
91
|
+
function appendOmEvent(session, kind, data) {
|
|
92
|
+
return session.append("feedback/record", { text: encodeOmEvent(kind, data) }).seq;
|
|
93
|
+
}
|
|
94
|
+
function findOmEvents(session, kind) {
|
|
95
|
+
const result = [];
|
|
96
|
+
for (const event of session.events) {
|
|
97
|
+
const om = readOmEvent(event);
|
|
98
|
+
if (om !== void 0 && (kind === void 0 || om.kind === kind)) result.push(om);
|
|
99
|
+
}
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
//#endregion
|
|
42
103
|
//#region src/degrade.ts
|
|
43
104
|
/**
|
|
44
105
|
* 降级报告:压缩流程中的挂载失败统一出口。
|
|
45
106
|
* 导出 reportDegrade / DEGRADE_PROBLEMS / DegradedProblem。
|
|
46
107
|
*
|
|
47
108
|
* - 挂载失败类问题(服务缺失、服务调用异常)始终 console.warn 到宿主进程外部输出,
|
|
48
|
-
* 并向会话日志追加 log-only 的
|
|
109
|
+
* 并向会话日志追加 log-only 的 om 警告事件(借用 feedback/record 的 om 信封,
|
|
110
|
+
* 见 om-event.ts;客户端渲染为「功能降级」警告行);
|
|
49
111
|
* 同一会话同一问题只报告一次(按日志扫描去重,重启不重复)
|
|
50
112
|
* - 报告动作自身绝不抛错:追加失败只记日志,不阻塞压缩
|
|
51
113
|
* - 辅助函数的普通运行时报错(组装失败、请求头读取失败)不走本模块,仅记日志
|
|
52
114
|
*/
|
|
53
|
-
/** 各降级问题面向用户的简短说明(om/warning
|
|
115
|
+
/** 各降级问题面向用户的简短说明(om/warning 信封载荷 message;客户端警告行直接展示)。 */
|
|
54
116
|
const DEGRADE_PROBLEMS = {
|
|
55
117
|
"systemPrompt-missing": "系统提示词服务未挂载,上下文压力估算不扣除系统提示词 tokens(压缩触发会偏早)",
|
|
56
118
|
"tokenMeter-unavailable": "token 计量服务异常,上下文压力估算降级(可能跳过压缩或按 0 计)"
|
|
57
119
|
};
|
|
58
|
-
/** 判定事件是否为指定 problem 的已有 om/warning 记录(会话内去重依据)。 */
|
|
59
|
-
function isWarningFor(event, problem) {
|
|
60
|
-
if (event.type !== "om/warning") return false;
|
|
61
|
-
return event.data?.problem === problem;
|
|
62
|
-
}
|
|
63
120
|
/**
|
|
64
121
|
* 报告一次挂载失败类降级:console.warn 始终输出到宿主进程外部;同会话同问题首次
|
|
65
|
-
* 出现时,向会话日志追加 log-only
|
|
122
|
+
* 出现时,向会话日志追加 log-only om 警告事件(客户端渲染警告行,每会话最多
|
|
66
123
|
* 一次)并输出 logger.warn(避免每个 pre-step 重复刷日志)。
|
|
67
124
|
* 日志扫描/事件追加失败只记日志,绝不抛错、不阻塞压缩。
|
|
68
125
|
*/
|
|
@@ -70,19 +127,19 @@ function reportDegrade(session, logger, problem) {
|
|
|
70
127
|
const message = DEGRADE_PROBLEMS[problem];
|
|
71
128
|
let first = true;
|
|
72
129
|
try {
|
|
73
|
-
first = !session.
|
|
130
|
+
first = !findOmEvents(session, "om/warning").some((om) => om.data.problem === problem);
|
|
74
131
|
} catch {}
|
|
75
132
|
if (!first) return;
|
|
76
133
|
console.warn(`${PLUGIN_LABEL}: ${message}`);
|
|
77
134
|
logger.warn(message);
|
|
78
135
|
try {
|
|
79
|
-
session
|
|
136
|
+
appendOmEvent(session, "om/warning", {
|
|
80
137
|
problem,
|
|
81
138
|
message
|
|
82
139
|
});
|
|
83
140
|
} catch (error) {
|
|
84
141
|
const text = error instanceof Error ? error.message : String(error);
|
|
85
|
-
logger.warn(`om
|
|
142
|
+
logger.warn(`om 警告事件追加失败: ${text}`);
|
|
86
143
|
}
|
|
87
144
|
}
|
|
88
145
|
//#endregion
|
|
@@ -7482,11 +7539,12 @@ function phaseLabel(phase) {
|
|
|
7482
7539
|
if (phase === "reflect") return "反思";
|
|
7483
7540
|
return "压缩";
|
|
7484
7541
|
}
|
|
7485
|
-
/** 诊断子会话 label
|
|
7542
|
+
/** 诊断子会话 label:`OM会话-<阶段>`,有重试时追加 `-重试N`(N = 尝试序号 - 1,首次不写)。 */
|
|
7486
7543
|
function compactionLogLabel(phase, attemptNo) {
|
|
7487
|
-
|
|
7544
|
+
const retry = attemptNo > 1 ? `-重试${attemptNo - 1}` : "";
|
|
7545
|
+
return `OM会话-${phaseLabel(phase)}${retry}`;
|
|
7488
7546
|
}
|
|
7489
|
-
/** 追加一次尝试的「提示词 →
|
|
7547
|
+
/** 追加一次尝试的「提示词 → 完整输出内容块」消息组(surfaceOp append;id 为品牌类型,session.append 运行时校验)。 */
|
|
7490
7548
|
function appendAttemptMessages(child, attempt, step, target) {
|
|
7491
7549
|
const userMessage = {
|
|
7492
7550
|
id: uuid(),
|
|
@@ -7501,13 +7559,20 @@ function appendAttemptMessages(child, attempt, step, target) {
|
|
|
7501
7559
|
}
|
|
7502
7560
|
};
|
|
7503
7561
|
child.append("user/message", userMessage, { surfaceOp: "append" });
|
|
7562
|
+
const content = [];
|
|
7563
|
+
if (attempt.reasoning !== void 0) content.push({
|
|
7564
|
+
type: "reasoning",
|
|
7565
|
+
text: attempt.reasoning
|
|
7566
|
+
});
|
|
7567
|
+
content.push({
|
|
7568
|
+
type: "text",
|
|
7569
|
+
text: attempt.rawOutput
|
|
7570
|
+
});
|
|
7571
|
+
if (attempt.toolCalls !== void 0) content.push(...attempt.toolCalls);
|
|
7504
7572
|
const assistantMessage = {
|
|
7505
7573
|
id: uuid(),
|
|
7506
7574
|
role: "assistant",
|
|
7507
|
-
content
|
|
7508
|
-
type: "text",
|
|
7509
|
-
text: attempt.rawOutput
|
|
7510
|
-
}],
|
|
7575
|
+
content,
|
|
7511
7576
|
source: {
|
|
7512
7577
|
kind: "model",
|
|
7513
7578
|
provider: target.provider,
|
|
@@ -7523,8 +7588,8 @@ function appendAttemptMessages(child, attempt, step, target) {
|
|
|
7523
7588
|
/**
|
|
7524
7589
|
* 把一次摘要尝试落盘为诊断子会话:ctx.sessions.create 创建子会话(header origin
|
|
7525
7590
|
* 'subagent'、parentSession 指向主会话、delegationDepth = 父 + 1、cwd 继承主会话),
|
|
7526
|
-
* 追加 one-shot descriptor(provider om-compaction-log,label
|
|
7527
|
-
* 原样追加「提示词 +
|
|
7591
|
+
* 追加 one-shot descriptor(provider om-compaction-log,label 为 `OM会话-<阶段>`,重试时追加 `-重试N`),
|
|
7592
|
+
* 原样追加「提示词 + 完整输出内容块(thinking/reasoning、文本、工具调用)」消息组,flush 持久化检查点,返回子会话 id。落盘自身
|
|
7528
7593
|
* 绝不抛错:任何失败仅 logger.warn 并返回 undefined(不影响压缩流程)。
|
|
7529
7594
|
*/
|
|
7530
7595
|
async function recordCompactionAttempt(ctx, parentSession, options) {
|
|
@@ -7751,17 +7816,36 @@ function renderMessages(session, seqs, skipReasoning = true) {
|
|
|
7751
7816
|
const serializer = new import_lib.XMLSerializer();
|
|
7752
7817
|
return `<${HISTORY_TAG}>\n${entries.map((el) => serializer.serializeToString(el)).join("\n")}\n</${HISTORY_TAG}>`;
|
|
7753
7818
|
}
|
|
7754
|
-
/**
|
|
7819
|
+
/** 流收集器:提取 thinking + 文本输出 + 工具调用 + usage + finish(不依赖宿主 BlockAssembler)。 */
|
|
7755
7820
|
var StreamCollector = class {
|
|
7756
7821
|
textBuf = "";
|
|
7822
|
+
reasoningBuf = "";
|
|
7823
|
+
/** tool-call-delta 按 index 聚合(id/name 首次给定后固定,arguments 增量拼接)。 */
|
|
7824
|
+
toolCallParts = /* @__PURE__ */ new Map();
|
|
7757
7825
|
_usage;
|
|
7758
7826
|
_finish;
|
|
7759
|
-
/** 喂入一个流 chunk
|
|
7827
|
+
/** 喂入一个流 chunk(消费 reasoning/文本/工具调用/usage/finish,其余忽略)。 */
|
|
7760
7828
|
push(chunk) {
|
|
7761
7829
|
switch (chunk.type) {
|
|
7762
7830
|
case "text-delta":
|
|
7763
7831
|
this.textBuf += chunk.text;
|
|
7764
7832
|
break;
|
|
7833
|
+
case "reasoning-delta":
|
|
7834
|
+
this.reasoningBuf += chunk.text;
|
|
7835
|
+
break;
|
|
7836
|
+
case "tool-call-delta": {
|
|
7837
|
+
let part = this.toolCallParts.get(chunk.index);
|
|
7838
|
+
if (part === void 0) {
|
|
7839
|
+
part = {
|
|
7840
|
+
id: chunk.id,
|
|
7841
|
+
args: ""
|
|
7842
|
+
};
|
|
7843
|
+
this.toolCallParts.set(chunk.index, part);
|
|
7844
|
+
}
|
|
7845
|
+
if (chunk.name !== void 0) part.name = chunk.name;
|
|
7846
|
+
part.args += chunk.argumentsDelta;
|
|
7847
|
+
break;
|
|
7848
|
+
}
|
|
7765
7849
|
case "usage":
|
|
7766
7850
|
this._usage = chunk.usage;
|
|
7767
7851
|
break;
|
|
@@ -7772,6 +7856,20 @@ var StreamCollector = class {
|
|
|
7772
7856
|
get text() {
|
|
7773
7857
|
return this.textBuf;
|
|
7774
7858
|
}
|
|
7859
|
+
/** thinking 输出(reasoning-delta 拼接;无则 undefined)。 */
|
|
7860
|
+
get reasoning() {
|
|
7861
|
+
return this.reasoningBuf === "" ? void 0 : this.reasoningBuf;
|
|
7862
|
+
}
|
|
7863
|
+
/** 模型请求的工具调用(按 index 流序还原为完整 tool-call 块;无则 undefined)。 */
|
|
7864
|
+
get toolCalls() {
|
|
7865
|
+
if (this.toolCallParts.size === 0) return void 0;
|
|
7866
|
+
return [...this.toolCallParts.entries()].sort(([a], [b]) => a - b).map(([, part]) => ({
|
|
7867
|
+
type: "tool-call",
|
|
7868
|
+
id: part.id,
|
|
7869
|
+
name: part.name ?? "",
|
|
7870
|
+
arguments: part.args
|
|
7871
|
+
}));
|
|
7872
|
+
}
|
|
7775
7873
|
/** 摘要 token usage(无则 undefined)。 */
|
|
7776
7874
|
get usage() {
|
|
7777
7875
|
return this._usage;
|
|
@@ -8081,7 +8179,9 @@ async function runSummarySubagent(ctx, agent, instruction, contextText, maxToken
|
|
|
8081
8179
|
target,
|
|
8082
8180
|
attempt: {
|
|
8083
8181
|
prompt,
|
|
8084
|
-
rawOutput: collector.text
|
|
8182
|
+
rawOutput: collector.text,
|
|
8183
|
+
...collector.reasoning === void 0 ? {} : { reasoning: collector.reasoning },
|
|
8184
|
+
...collector.toolCalls === void 0 ? {} : { toolCalls: collector.toolCalls }
|
|
8085
8185
|
},
|
|
8086
8186
|
attemptNo: attempt,
|
|
8087
8187
|
debug
|
|
@@ -8157,8 +8257,9 @@ async function runSummarySubagent(ctx, agent, instruction, contextText, maxToken
|
|
|
8157
8257
|
* tailMessageCount 时,把压缩边界至触发点的全部消息摘要为新 <history> 块并精确替换
|
|
8158
8258
|
* 被压缩区间(旧块保留),等待期间的新消息成为下一轮未压缩尾部(延迟窗口内压力允许
|
|
8159
8259
|
* 短暂超阈值);tailMessageCount=0 时触发当轮直接执行(不落待定标记)
|
|
8160
|
-
* - 待定标记以 log-only om
|
|
8161
|
-
*
|
|
8260
|
+
* - 待定标记以 log-only om 信封事件(借用 feedback/record,kind 为 om/observe-pending /
|
|
8261
|
+
* om/observe-invalidate,见 om-event.ts)持久化在会话日志中(重启后从日志恢复);
|
|
8262
|
+
* 摘要失败保留待定,下个 pre-step 直接重试执行
|
|
8162
8263
|
* - 两级在 pre-step 阻塞串行执行(先反思后观察);仅主会话生效;omEnabled=false 关闭
|
|
8163
8264
|
* - 压缩边界:最后一个合法 <history> 块之后的消息视为未压缩,其前不重复压缩
|
|
8164
8265
|
* - 摘要尝试全部耗尽时 pass 返回失败结果(携带最后一次尝试的实际报错),压缩流程
|
|
@@ -8166,7 +8267,8 @@ async function runSummarySubagent(ctx, agent, instruction, contextText, maxToken
|
|
|
8166
8267
|
* - 提交走宿主 compaction/* 生命周期事件(start 带 phase → summary → 替换消息 → end),
|
|
8167
8268
|
* 失败补 end(error,实际报错 + 诊断子会话 sessionId);替换消息 source 标记插件标识供 UI 认领
|
|
8168
8269
|
* - 挂载失败类问题(systemPrompt/tokenMeter 服务异常)始终 console 到外部进程,并追加
|
|
8169
|
-
* log-only om/
|
|
8270
|
+
* log-only om 警告事件(借用 feedback/record,客户端渲染功能降级警告行,每会话同一
|
|
8271
|
+
* 问题至多一次);
|
|
8170
8272
|
* 辅助估算的普通运行时报错仅记日志。降级与报错都不阻塞压缩(tokenMeter 压力数据
|
|
8171
8273
|
* 缺失时本轮跳过观察)
|
|
8172
8274
|
*/
|
|
@@ -8296,40 +8398,35 @@ function historySection(session) {
|
|
|
8296
8398
|
};
|
|
8297
8399
|
}
|
|
8298
8400
|
/**
|
|
8299
|
-
* 查找当前活跃的观察压缩待定标记:按日志顺序取最后一条 om/observe-pending
|
|
8300
|
-
*
|
|
8301
|
-
*
|
|
8302
|
-
*
|
|
8401
|
+
* 查找当前活跃的观察压缩待定标记:按日志顺序取最后一条 om/observe-pending 信封事件,
|
|
8402
|
+
* 其后须无引用它的 om/observe-invalidate(已失效),且其后的压缩边界 seq 不大于标记
|
|
8403
|
+
* seq(边界后移说明标记期间已发生过压缩,标记过期——兜底「执行成功但失效标记未写出」
|
|
8404
|
+
* 的崩溃窗口)。无活跃标记返回 undefined。
|
|
8303
8405
|
*/
|
|
8304
8406
|
function findObservePending(session) {
|
|
8305
8407
|
let pending;
|
|
8306
8408
|
for (let seq = 0; seq < session.events.length; seq += 1) {
|
|
8307
8409
|
const event = session.events[seq];
|
|
8308
8410
|
if (!event) continue;
|
|
8309
|
-
|
|
8411
|
+
const om = readOmEvent(event);
|
|
8412
|
+
if (om?.kind === "om/observe-pending") pending = {
|
|
8310
8413
|
seq,
|
|
8311
|
-
triggerMessageIndex:
|
|
8414
|
+
triggerMessageIndex: om.data.triggerMessageIndex
|
|
8312
8415
|
};
|
|
8313
|
-
else if (
|
|
8416
|
+
else if (om?.kind === "om/observe-invalidate" && pending !== void 0 && om.data.pendingSeq === pending.seq) pending = void 0;
|
|
8314
8417
|
}
|
|
8315
8418
|
if (pending === void 0) return void 0;
|
|
8316
8419
|
const { boundarySeq } = historySection(session);
|
|
8317
8420
|
if (boundarySeq !== void 0 && boundarySeq > pending.seq) return void 0;
|
|
8318
8421
|
return pending;
|
|
8319
8422
|
}
|
|
8320
|
-
/** 追加观察压缩待定标记(log-only
|
|
8423
|
+
/** 追加观察压缩待定标记(log-only om 信封事件):记录触发点完整消息 index,返回事件 seq。 */
|
|
8321
8424
|
function appendObservePending(session, triggerMessageIndex) {
|
|
8322
|
-
return session
|
|
8323
|
-
key: "observe",
|
|
8324
|
-
triggerMessageIndex
|
|
8325
|
-
}).seq;
|
|
8425
|
+
return appendOmEvent(session, "om/observe-pending", { triggerMessageIndex });
|
|
8326
8426
|
}
|
|
8327
|
-
/** 追加观察压缩待定失效标记(log-only
|
|
8427
|
+
/** 追加观察压缩待定失效标记(log-only om 信封事件):声明指定 pending 已失效,返回事件 seq。 */
|
|
8328
8428
|
function appendObserveInvalidate(session, pendingSeq) {
|
|
8329
|
-
return session
|
|
8330
|
-
key: "observe",
|
|
8331
|
-
pendingSeq
|
|
8332
|
-
}).seq;
|
|
8429
|
+
return appendOmEvent(session, "om/observe-invalidate", { pendingSeq });
|
|
8333
8430
|
}
|
|
8334
8431
|
/** 当前打开中的 turn 号(最近 turn/start 且未被 turn/end 关闭);无则 null。 */
|
|
8335
8432
|
function openTurnOf(session) {
|
|
@@ -8514,7 +8611,7 @@ async function reflectPass(ctx, agent, config, target, signal) {
|
|
|
8514
8611
|
* 估算系统提示词 tokens:按 agent 作用域组装并渲染系统提示词,按长度/4 启发式计。
|
|
8515
8612
|
* systemPrompt 服务经 ctx.get 容错读取(ctx 属性访问在服务未挂载时抛错);服务缺失
|
|
8516
8613
|
* 或组装/渲染失败时按 0 计——只影响观察触发时机(偏早触发),不阻塞压缩。
|
|
8517
|
-
* 服务缺失属挂载失败:console 外部 + om
|
|
8614
|
+
* 服务缺失属挂载失败:console 外部 + om 警告事件每会话报告一次;组装失败仅记日志。
|
|
8518
8615
|
*/
|
|
8519
8616
|
async function estimateSystemPromptTokens(ctx, agent, logger, signal) {
|
|
8520
8617
|
const systemPrompt = ctx.get("systemPrompt");
|
|
@@ -8554,7 +8651,7 @@ function estimateToolsTokens(session, logger) {
|
|
|
8554
8651
|
}
|
|
8555
8652
|
/**
|
|
8556
8653
|
* 读取上下文压力 tokens(tokenMeter.measure 的 totalTokens)。tokenMeter 调用异常时
|
|
8557
|
-
* 记日志并报告降级(console 外部 + om
|
|
8654
|
+
* 记日志并报告降级(console 外部 + om 警告事件每会话一次),返回 undefined——本轮
|
|
8558
8655
|
* 跳过观察压缩(无压力数据不触发),不阻塞 turn。
|
|
8559
8656
|
*/
|
|
8560
8657
|
function measurePressureTokens(ctx, session, logger) {
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* om 事件借用通道:插件私有事件以宿主已知类型 feedback/record 持久化。
|
|
3
|
+
* 导出 OM_EVENT_PREFIX / OmEventKind / OmEventPayloadMap / OmEvent /
|
|
4
|
+
* appendOmEvent / readOmEvent / findOmEvents。
|
|
5
|
+
*
|
|
6
|
+
* 背景:持久化读取路径拒绝 KNOWN_SESSION_EVENT_TYPES 目录之外的未知类型
|
|
7
|
+
* (dsh-session-persistence 的 assertEventsSupported),而 Session.append 不提供
|
|
8
|
+
* ignorable 标记的写入途径,插件自定义事件类型会使含该事件的会话无法加载。
|
|
9
|
+
* feedback/record(dsh-command-feedback 声明)是目录内 log-only 审计事件,所有者
|
|
10
|
+
* invariant 声明其无跨事件关系、无运行时不变量、永不进入模型上下文,故选为承载
|
|
11
|
+
* 类型:插件数据以 `om:1:` 前缀 + JSON 信封写入其 text 字段,解码失败按非 om
|
|
12
|
+
* 记录处理(含用户自写的真实反馈记录)。
|
|
13
|
+
*/
|
|
14
|
+
import type { Session, SessionEvent } from './types.ts';
|
|
15
|
+
/** om 信封 text 前缀:标识该 feedback/record 记录由本插件写入。 */
|
|
16
|
+
export declare const OM_EVENT_PREFIX = "om:1:";
|
|
17
|
+
/** om 私有事件类别(信封 kind 字段)。 */
|
|
18
|
+
export type OmEventKind =
|
|
19
|
+
/** 功能降级警告(degrade.ts 报告,客户端渲染「功能降级」警告行)。 */
|
|
20
|
+
'om/warning'
|
|
21
|
+
/** 观察压缩待定标记(compress.ts 观察触发时追加)。 */
|
|
22
|
+
| 'om/observe-pending'
|
|
23
|
+
/** 观察压缩待定失效标记(压缩执行完成后追加,声明待定可重新触发)。 */
|
|
24
|
+
| 'om/observe-invalidate';
|
|
25
|
+
/** 各类别信封载荷(kind 之外的 JSON 字段)。 */
|
|
26
|
+
export type OmEventPayloadMap = {
|
|
27
|
+
'om/warning': {
|
|
28
|
+
/** 降级问题标识(会话内去重键,取值见 degrade.ts)。 */
|
|
29
|
+
problem: string;
|
|
30
|
+
/** 面向用户的简短说明。 */
|
|
31
|
+
message: string;
|
|
32
|
+
};
|
|
33
|
+
'om/observe-pending': {
|
|
34
|
+
/** 触发点:追加时的最后一条完整消息 index。 */
|
|
35
|
+
triggerMessageIndex: number;
|
|
36
|
+
};
|
|
37
|
+
'om/observe-invalidate': {
|
|
38
|
+
/** 被失效的 om/observe-pending 事件 seq。 */
|
|
39
|
+
pendingSeq: number;
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
/** 一条解码后的 om 私有事件:类别、载荷与承载事件在日志中的 seq。 */
|
|
43
|
+
export type OmEvent = {
|
|
44
|
+
[K in OmEventKind]: {
|
|
45
|
+
kind: K;
|
|
46
|
+
data: OmEventPayloadMap[K];
|
|
47
|
+
seq: number;
|
|
48
|
+
};
|
|
49
|
+
}[OmEventKind];
|
|
50
|
+
/**
|
|
51
|
+
* 解码一条会话事件为 om 私有事件:仅识别 feedback/record 中带 om 信封前缀的
|
|
52
|
+
* text;前缀缺失、JSON 非法、kind 未知或载荷字段缺失时返回 undefined。
|
|
53
|
+
*/
|
|
54
|
+
export declare function readOmEvent(event: SessionEvent | undefined | null): OmEvent | undefined;
|
|
55
|
+
/** 追加一条 om 私有事件(借用 feedback/record,log-only,不进 surface),返回事件 seq。 */
|
|
56
|
+
export declare function appendOmEvent<K extends OmEventKind>(session: Session, kind: K, data: OmEventPayloadMap[K]): number;
|
|
57
|
+
/** 读取日志中全部 om 私有事件(按日志顺序)。 */
|
|
58
|
+
export declare function findOmEvents(session: Session): OmEvent[];
|
|
59
|
+
/** 读取日志中指定类别的 om 私有事件(按日志顺序,载荷类型按类别收窄)。 */
|
|
60
|
+
export declare function findOmEvents<K extends OmEventKind>(session: Session, kind: K): Array<{
|
|
61
|
+
kind: K;
|
|
62
|
+
data: OmEventPayloadMap[K];
|
|
63
|
+
seq: number;
|
|
64
|
+
}>;
|
|
65
|
+
//# sourceMappingURL=om-event.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"om-event.d.ts","sourceRoot":"","sources":["../src/om-event.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAExD,kDAAkD;AAClD,eAAO,MAAM,eAAe,UAAU,CAAC;AAEvC,6BAA6B;AAC7B,MAAM,MAAM,WAAW;AACrB,4CAA4C;AAC1C,YAAY;AACd,qCAAqC;GACnC,oBAAoB;AACtB,uCAAuC;GACrC,uBAAuB,CAAC;AAE5B,iCAAiC;AACjC,MAAM,MAAM,iBAAiB,GAAG;IAC9B,YAAY,EAAE;QACZ,qCAAqC;QACrC,OAAO,EAAE,MAAM,CAAC;QAChB,iBAAiB;QACjB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,oBAAoB,EAAE;QACpB,8BAA8B;QAC9B,mBAAmB,EAAE,MAAM,CAAC;KAC7B,CAAC;IACF,uBAAuB,EAAE;QACvB,sCAAsC;QACtC,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;CACH,CAAC;AAEF,0CAA0C;AAC1C,MAAM,MAAM,OAAO,GAAG;KACnB,CAAC,IAAI,WAAW,GAAG;QAAE,IAAI,EAAE,CAAC,CAAC;QAAC,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE;CACzE,CAAC,WAAW,CAAC,CAAC;AAiBf;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,YAAY,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO,GAAG,SAAS,CAmBvF;AAOD,qEAAqE;AACrE,wBAAgB,aAAa,CAAC,CAAC,SAAS,WAAW,EACjD,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,CAAC,EACP,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,GACzB,MAAM,CAER;AAED,8BAA8B;AAC9B,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,EAAE,CAAC;AAC1D,2CAA2C;AAC3C,wBAAgB,YAAY,CAAC,CAAC,SAAS,WAAW,EAChD,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,CAAC,GACN,KAAK,CAAC;IAAE,IAAI,EAAE,CAAC,CAAC;IAAC,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC"}
|
package/dist/summarize.d.ts
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
* 模糊提取重建 / 无 reasoning / index 连续),失败按 maxAttempts 重试;每次尝试的
|
|
9
9
|
* 结果或报错始终写入日志(成功 info / 失败 warn,失败原因说明具体问题而非解析器
|
|
10
10
|
* 原始报错);全部耗尽返回失败结果(携带最后一次尝试的实际报错)。最终失败
|
|
11
|
-
* (含 signal
|
|
12
|
-
* 原样落盘为诊断子会话,sessionId 随失败结果向上传播进主会话日志。每次请求前
|
|
11
|
+
* (含 signal 中止)时把每次尝试的完整提示词与模型原始输出(含 thinking 与工具调用块)
|
|
12
|
+
* 经 compaction-log.ts 原样落盘为诊断子会话,sessionId 随失败结果向上传播进主会话日志。每次请求前
|
|
13
13
|
* 过全局限流等待门;token usage 归入主会话记录。
|
|
14
14
|
*/
|
|
15
15
|
import type { Agent, Context, Session, TokenUsage } from './types.ts';
|
package/dist/summarize.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"summarize.d.ts","sourceRoot":"","sources":["../src/summarize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;
|
|
1
|
+
{"version":3,"file":"summarize.d.ts","sourceRoot":"","sources":["../src/summarize.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -19,36 +19,14 @@ export type { PluginConfig } from './config.ts';
|
|
|
19
19
|
declare module '@deepseek-ai/dsh-session/types' {
|
|
20
20
|
interface SessionEventMap {
|
|
21
21
|
/**
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
22
|
+
* 借用通道(log-only,不进 surface):dsh-command-feedback 声明的用户反馈
|
|
23
|
+
* 审计事件({ text: string }),位于宿主 KNOWN_SESSION_EVENT_TYPES 目录内,
|
|
24
|
+
* 历史会话加载不受读取路径的未知类型拒绝影响。本插件以 `om:1:` 前缀 JSON
|
|
25
|
+
* 信封在其 text 字段承载私有事件(编解码见 om-event.ts)。声明与所有者一致,
|
|
26
|
+
* 所有者类型包加入编译依赖后此处移除。
|
|
25
27
|
*/
|
|
26
|
-
'
|
|
27
|
-
|
|
28
|
-
problem: string;
|
|
29
|
-
/** 面向用户的简短说明。 */
|
|
30
|
-
message: string;
|
|
31
|
-
};
|
|
32
|
-
/**
|
|
33
|
-
* 观察压缩待定标记(log-only,不进 surface):净压力首次达到观察阈值时追加,
|
|
34
|
-
* 记录触发点完整消息 index,本次不压缩;延迟等待 tailMessageCount 条新完整消息后
|
|
35
|
-
* 执行压缩(区间截至触发点)。同一会话同时至多一条活跃待定标记(key 固定 'observe')。
|
|
36
|
-
*/
|
|
37
|
-
'om/observe-pending': {
|
|
38
|
-
/** 标记键(固定 'observe',与 om/observe-invalidate 配对)。 */
|
|
39
|
-
key: 'observe';
|
|
40
|
-
/** 触发点:追加时的最后一条完整消息 index。 */
|
|
41
|
-
triggerMessageIndex: number;
|
|
42
|
-
};
|
|
43
|
-
/**
|
|
44
|
-
* 观察压缩待定失效标记(log-only,不进 surface):待定标记对应的压缩执行完成
|
|
45
|
-
* (成功提交或无可行区间)后追加,声明指定 pending 已失效、可重新触发观察。
|
|
46
|
-
*/
|
|
47
|
-
'om/observe-invalidate': {
|
|
48
|
-
/** 标记键(固定 'observe')。 */
|
|
49
|
-
key: 'observe';
|
|
50
|
-
/** 被失效的 om/observe-pending 事件 seq。 */
|
|
51
|
-
pendingSeq: number;
|
|
28
|
+
'feedback/record': {
|
|
29
|
+
text: string;
|
|
52
30
|
};
|
|
53
31
|
}
|
|
54
32
|
}
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AACzE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gDAAgD,CAAC;AACvF,OAAO,KAAK,EACV,YAAY,EACZ,UAAU,EACV,OAAO,EACP,UAAU,EACV,WAAW,EACZ,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AACvF,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACnG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE7F,4BAA4B;AAC5B,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,QAAQ,gCAAgC,CAAC;IAC9C,UAAU,eAAe;QACvB
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|