dsh-plugin-om 0.0.15 → 0.0.16
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 +4 -4
- package/dist/compress.d.ts +1 -1
- package/dist/compress.d.ts.map +1 -1
- package/dist/constants.d.ts +8 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/index.mjs +76 -107
- package/dist/log-index.d.ts +2 -15
- package/dist/log-index.d.ts.map +1 -1
- package/dist/recall.d.ts +2 -1
- package/dist/recall.d.ts.map +1 -1
- package/dist/semantic-recall.d.ts +2 -1
- package/dist/semantic-recall.d.ts.map +1 -1
- package/dist/summarize.d.ts +9 -12
- package/dist/summarize.d.ts.map +1 -1
- package/dist/types.d.ts +13 -6
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -84,13 +84,13 @@ dsh的"预设"分为两层,`dsh web`等同于`dsh --profile web`,调用的
|
|
|
84
84
|
|
|
85
85
|
- 观察压缩只精确替换被压缩的新消息区间:旧 <history> 块保留为独立消息,新观察日志作为新块追加在其后(多块并存按序排列),历史不会随压缩次数膨胀;反思合并时才把多个块合并为一条更紧凑的摘要
|
|
86
86
|
- 压缩边界:消息列表中最后一个合法的 <history> 块(source 为插件,plugin 为插件标识 `dsh-plugin-om`;兼容旧日志的宿主 checkpoint 标记 `compact`)之后的消息视为未压缩;其前(含自身)视为已压缩,不重复压缩、不计入观察阈值
|
|
87
|
-
- 观察输入经 `@xmldom/xmldom` 构建为合法 <history> 块(用户消息文本/assistant 文本/reasoning 特殊字符自动转义,图片/文件以注释补充;assistant 文本与 toolcall&result
|
|
87
|
+
- 观察输入经 `@xmldom/xmldom` 构建为合法 <history> 块(用户消息文本/assistant 文本/reasoning 特殊字符自动转义,图片/文件以注释补充;assistant 文本与 toolcall&result 原样;系统消息——user_message 中 source.kind 非 user 的部分,如宿主注入的上下文——渲染为 <sys type="KIND" index="N"></sys> 空块,内容不进入压缩输入)
|
|
88
88
|
- 输出经 `@xmldom/xmldom` 解析校验:结构合法(标签匹配/闭合/单块)、不含 <reasoning>、index/start/end 连续(与预期覆盖区间一致),失败按 `compressRetryCount` 重试
|
|
89
89
|
- 块开标签带 `tip` 属性(对 AI 的提醒:"当前块是历史消息的压缩产物,不要复述");块顶为构成逻辑注释(完整消息定义串 + 条目标签语义),消息正文不再附加前缀句
|
|
90
90
|
|
|
91
91
|
### 注意
|
|
92
92
|
|
|
93
|
-
- 未压缩消息的 token
|
|
93
|
+
- 未压缩消息的 token 统计排除系统消息(user_message 中 source.kind 非 user 的部分,如宿主注入的上下文;宿主注入的提醒不计入观察阈值的触发量)
|
|
94
94
|
- recall 不截断,建议保留 `tool-result-pruner`
|
|
95
95
|
- recall-semantic 使用本地多语言嵌入模型(paraphrase-multilingual-MiniLM-L12-v2),
|
|
96
96
|
|
|
@@ -159,10 +159,10 @@ src/
|
|
|
159
159
|
├── types.ts # type-only:宿主类型再导出 + 领域类型(MessageNode / MessageIndex)
|
|
160
160
|
├── config.ts # 配置默认值 / 宽松合并(缺省、null、空串回退默认值;未知键忽略、非法值回退默认;数值键/布尔键/omEnabled/modelDir)
|
|
161
161
|
├── utils.ts # 零依赖工具函数(配置校验 / 文本渲染 / 主会话判定 / 路由解析)
|
|
162
|
-
├── log-index.ts # 完整消息索引(index 定位 user/assistant/具有result的toolcall
|
|
162
|
+
├── log-index.ts # 完整消息索引(index 定位 user/sys/assistant/具有result的toolcall;user_message 按 source.kind 分类:kind:user 为用户消息、其余为系统消息;本插件自产压缩日志消息不占位;未闭合 tool-call 不占位;recall 与摘要共用)
|
|
163
163
|
├── embedding.ts # 本地 ONNX 嵌入(@huggingface/transformers + 本地模型;共享目录解析 / 小文件补齐 / 运行时按需下载编排 / 懒加载 / 批量 / cosine)
|
|
164
164
|
├── model-download.ts # 模型下载原语(modelSourceUrl / needsDownload / 原子落盘 / 开始结束日志与失败镜像建议;运行时与 dev CLI 共用)
|
|
165
|
-
├── summarize.ts # 共享提示词 buildHistoryPrompt(观察/反思同一套)+ renderMessages(@xmldom/xmldom 构建 <history>
|
|
165
|
+
├── summarize.ts # 共享提示词 buildHistoryPrompt(观察/反思同一套)+ renderMessages(@xmldom/xmldom 构建 <history> 块输入:用户消息原样、系统消息渲染为 <sys> 空块、自动转义)+ 直连 ctx.llm.stream() 摘要(new 方式:指令作 system、输入为渲染消息;extractSummaryLog 提取校验:XML 结构合法 / 无 reasoning / index 连续 / 覆盖区间;重试与流式 usage 归入主会话)
|
|
166
166
|
├── recall.ts # recall 工具
|
|
167
167
|
├── semantic-recall.ts # recall-semantic 工具(query 语义检索 + 区间限定 + 回退全量 + 匹配说明)
|
|
168
168
|
└── compress.ts # 两级自动压缩(测量 / mid-turn 区间计算 / 配对平衡回退 / source 标记判定摘要消息 / compaction/* 生命周期事件 + 替换消息 source 插件标识)
|
package/dist/compress.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export type TokenEstimator = {
|
|
|
9
9
|
/**
|
|
10
10
|
* 未压缩消息 token 估算:最后一个 <history> 块之后的表层节点合计
|
|
11
11
|
* (其前含自身视为已压缩,不计入观察阈值衡量对象;无压缩日志时计全部)。
|
|
12
|
-
*
|
|
12
|
+
* 系统消息(user/message 中非 kind:user 的部分,如宿主注入的上下文)不计入阈值。
|
|
13
13
|
*/
|
|
14
14
|
export declare function measureUncompressedTokens(session: Session, meter: TokenEstimator): number;
|
|
15
15
|
/**
|
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":"AAoCA,OAAO,KAAK,EACV,KAAK,EAEL,OAAO,EACP,YAAY,EACZ,OAAO,EAIR,MAAM,YAAY,CAAC;AACpB,OAAO,EAAgB,KAAK,YAAY,EAAsB,MAAM,YAAY,CAAC;AAEjF,+DAA+D;AAC/D,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvD;AAwCD,+DAA+D;AAC/D,MAAM,MAAM,cAAc,GAAG;IAAE,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAA;CAAE,CAAC;AAE3E;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,cAAc,GAAG,MAAM,CAyBzF;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAc1E;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,MAAM,GAChB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,SAAS,CA8BpE;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG;IAChD,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC7C,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;CACjC,CAaA;AA4FD;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,QAAQ,CAAC,YAAY,CAAC,EAC9B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,YAAY,EACpB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CA2Gf;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,QAAQ,CAAC,YAAY,CAAC,EAC9B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,YAAY,EACpB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAkIf;AAED;;;GAGG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,QAAQ,CAAC,YAAY,CAAC,EAC9B,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAwCf"}
|
package/dist/constants.d.ts
CHANGED
|
@@ -10,8 +10,15 @@ export declare const HISTORY_TIP = "\u5F53\u524D\u5757\u662F\u5386\u53F2\u6D88\u
|
|
|
10
10
|
/**
|
|
11
11
|
* 「完整消息」定义(提示词 / recall 工具描述 / 块顶注释共用同一字符串)。
|
|
12
12
|
* 完整消息是摘要日志与 recall 共用的定位单位;首条 index 为 0,按会话顺序递增、全局稳定。
|
|
13
|
+
* 用户消息指 user_message 中 source.kind 为 user 的部分;其余部分(宿主注入的上下文等)
|
|
14
|
+
* 为系统消息,同样是一条完整消息。
|
|
13
15
|
*/
|
|
14
|
-
export declare const COMPLETE_MESSAGE_DEFINITION = "`\u7528\u6237\u6D88\u606F`\uFF0C`\u6A21\u578B\u8F93\u51FA\u6587\u672C`\u548C`\u5177\u6709result\u7684toolcall`\u88AB\u89C6\u4F5C`\u5B8C\u6574\u6D88\u606F`\u3002\u9996\u6761`\u5B8C\u6574\u6D88\u606F`\u7684index\u662F0\uFF0C\u540E\u7EED\u7684index\u9012\u589E\u3002";
|
|
16
|
+
export declare const COMPLETE_MESSAGE_DEFINITION = "`\u7528\u6237\u6D88\u606F`\uFF08user_message \u4E2D kind \u4E3A user \u7684\u90E8\u5206\uFF09\uFF0C`\u7CFB\u7EDF\u6D88\u606F`\uFF08user_message \u4E2D\u5176\u4F59 kind \u7684\u90E8\u5206\uFF09\uFF0C`\u6A21\u578B\u8F93\u51FA\u6587\u672C`\u548C`\u5177\u6709result\u7684toolcall`\u88AB\u89C6\u4F5C`\u5B8C\u6574\u6D88\u606F`\u3002\u9996\u6761`\u5B8C\u6574\u6D88\u606F`\u7684index\u662F0\uFF0C\u540E\u7EED\u7684index\u9012\u589E\u3002";
|
|
17
|
+
/** 判定 user/message 的 source 是否为本插件自产(压缩日志机制消息;含兼容旧宿主 checkpoint 标记 'compact')。这类消息不占完整消息 index。 */
|
|
18
|
+
export declare function isPluginOwnedSource(source: {
|
|
19
|
+
kind?: string;
|
|
20
|
+
plugin?: string;
|
|
21
|
+
} | undefined): boolean;
|
|
15
22
|
/** 旧日志压缩消息的宿主 checkpoint 标记 plugin 名(dsh-compaction-basic 的 COMPACT_CHECKPOINT_MARKER.plugin;历史兼容识别用)。 */
|
|
16
23
|
export declare const COMPACT_CHECKPOINT_PLUGIN = "compact";
|
|
17
24
|
//# sourceMappingURL=constants.d.ts.map
|
package/dist/constants.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,oDAAoD;AACpD,eAAO,MAAM,YAAY,kBAAkB,CAAC;AAE5C,sEAAsE;AACtE,eAAO,MAAM,WAAW,YAAY,CAAC;AAErC,kDAAkD;AAClD,eAAO,MAAM,WAAW,iHAAuB,CAAC;AAEhD
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,oDAAoD;AACpD,eAAO,MAAM,YAAY,kBAAkB,CAAC;AAE5C,sEAAsE;AACtE,eAAO,MAAM,WAAW,YAAY,CAAC;AAErC,kDAAkD;AAClD,eAAO,MAAM,WAAW,iHAAuB,CAAC;AAEhD;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,kbACuG,CAAC;AAEhJ,mGAAmG;AACnG,wBAAgB,mBAAmB,CACjC,MAAM,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,GACrD,OAAO,CAGT;AAED,0GAA0G;AAC1G,eAAO,MAAM,yBAAyB,YAAY,CAAC"}
|
package/dist/index.mjs
CHANGED
|
@@ -19,8 +19,15 @@ const HISTORY_TIP = "当前块是历史消息的压缩产物,不要复述";
|
|
|
19
19
|
/**
|
|
20
20
|
* 「完整消息」定义(提示词 / recall 工具描述 / 块顶注释共用同一字符串)。
|
|
21
21
|
* 完整消息是摘要日志与 recall 共用的定位单位;首条 index 为 0,按会话顺序递增、全局稳定。
|
|
22
|
+
* 用户消息指 user_message 中 source.kind 为 user 的部分;其余部分(宿主注入的上下文等)
|
|
23
|
+
* 为系统消息,同样是一条完整消息。
|
|
22
24
|
*/
|
|
23
|
-
const COMPLETE_MESSAGE_DEFINITION = "
|
|
25
|
+
const COMPLETE_MESSAGE_DEFINITION = "`用户消息`(user_message 中 kind 为 user 的部分),`系统消息`(user_message 中其余 kind 的部分),`模型输出文本`和`具有result的toolcall`被视作`完整消息`。首条`完整消息`的index是0,后续的index递增。";
|
|
26
|
+
/** 判定 user/message 的 source 是否为本插件自产(压缩日志机制消息;含兼容旧宿主 checkpoint 标记 'compact')。这类消息不占完整消息 index。 */
|
|
27
|
+
function isPluginOwnedSource(source) {
|
|
28
|
+
if (source?.kind !== "plugin") return false;
|
|
29
|
+
return source.plugin === "dsh-plugin-om" || source.plugin === "compact";
|
|
30
|
+
}
|
|
24
31
|
//#endregion
|
|
25
32
|
//#region src/utils.ts
|
|
26
33
|
/** 判断值是否为普通对象:typeof object 且非 null 且非数组(类型收窄用)。 */
|
|
@@ -79,7 +86,22 @@ function routedTarget(session) {
|
|
|
79
86
|
//#endregion
|
|
80
87
|
//#region src/log-index.ts
|
|
81
88
|
/**
|
|
82
|
-
*
|
|
89
|
+
* 会话日志索引:完整消息索引(index 定位完整消息,recall 与摘要共用同一套编号),
|
|
90
|
+
* 以及表层节点定位辅助。事件日志仅追加(被遮蔽的事件仍可读,recall 依赖此性质)。
|
|
91
|
+
*
|
|
92
|
+
* 完整消息是摘要日志与 recall 共用的定位单位,分四类:
|
|
93
|
+
* - user:用户消息(user/message 中 source.kind === 'user')占一条;
|
|
94
|
+
* - sys:系统消息(user/message 中其余 source.kind 的部分,如宿主注入的上下文)
|
|
95
|
+
* 占一条;压缩日志中以 <sys type="KIND" index="N"> 空块表示(内容不进入输入);
|
|
96
|
+
* - assistant:模型输出文本(assistant/message 中的文本块)占一条;
|
|
97
|
+
* - toolcall:单个工具调用及其结果占一条(同一条 AI 消息里的文本与工具调用拆开,
|
|
98
|
+
* tool/result 按 source.callId 匹配其 tool-call;未匹配的 result 独立成条,防御)。
|
|
99
|
+
* 本插件自产的压缩日志消息(source.kind === 'plugin' 且 plugin 为本插件标识)不占 index。
|
|
100
|
+
* index 从 0 起、按日志顺序递增、只追加不重排 → 会话内全局稳定,
|
|
101
|
+
* 压缩后旧摘要条目引用的 index 仍然有效。
|
|
102
|
+
*/
|
|
103
|
+
/**
|
|
104
|
+
* 完整消息索引:按日志顺序把消息事件折叠为完整消息序列(四类,见文件头)。
|
|
83
105
|
* 工具调用结果按 source.callId 匹配其 tool-call 并入该条;未匹配的 result 独立成条(防御)。
|
|
84
106
|
* 插件在 agent/pre-step 触发压缩(日志 call-result 完备),因此压缩时不存在未闭合的
|
|
85
107
|
* tool-call;索引对未闭合调用不设特殊处理。
|
|
@@ -96,12 +118,20 @@ function indexCompleteMessages(session) {
|
|
|
96
118
|
const event = events[seq];
|
|
97
119
|
if (!event) continue;
|
|
98
120
|
if (event.type === "user/message") {
|
|
99
|
-
|
|
100
|
-
|
|
121
|
+
/** 事件 source(区分用户消息与宿主注入/插件消息)。 */
|
|
122
|
+
const source = event.data.source;
|
|
123
|
+
if (isPluginOwnedSource(source)) continue;
|
|
124
|
+
if (source?.kind === "user") cms.push({
|
|
101
125
|
index: cms.length,
|
|
102
126
|
type: "user",
|
|
103
127
|
seqs: [seq]
|
|
104
128
|
});
|
|
129
|
+
else cms.push({
|
|
130
|
+
index: cms.length,
|
|
131
|
+
type: "sys",
|
|
132
|
+
seqs: [seq],
|
|
133
|
+
...source?.kind === void 0 ? {} : { kind: source.kind }
|
|
134
|
+
});
|
|
105
135
|
} else if (event.type === "assistant/message") {
|
|
106
136
|
/** 助手消息(含文本与 tool-call 块)。 */
|
|
107
137
|
const message = event.data.message;
|
|
@@ -153,13 +183,13 @@ function indexCompleteMessages(session) {
|
|
|
153
183
|
}
|
|
154
184
|
/**
|
|
155
185
|
* 渲染一条完整消息的文本(recall 输出 / new 模式输入共用):
|
|
156
|
-
* - user:消息原文;
|
|
186
|
+
* - user / sys:消息原文;
|
|
157
187
|
* - assistant:仅文本块;
|
|
158
188
|
* - toolcall:调用块(工具名 + 参数)+ 结果文本(pruner 裁剪超大结果)。
|
|
159
189
|
*/
|
|
160
190
|
function renderCompleteMessage(session, cm, pruner) {
|
|
161
|
-
if (cm.type === "user") {
|
|
162
|
-
/**
|
|
191
|
+
if (cm.type === "user" || cm.type === "sys") {
|
|
192
|
+
/** 用户/系统消息事件(seq 缺失则无法渲染)。 */
|
|
163
193
|
const seq = cm.seqs[0];
|
|
164
194
|
const event = seq === void 0 ? void 0 : session.events[seq];
|
|
165
195
|
/** 派生的消息对象。 */
|
|
@@ -7382,13 +7412,14 @@ function buildHistoryPrompt() {
|
|
|
7382
7412
|
"- <history> 是历史消息的记录块:输入与输出都是合法的 <history> 块,块内条目是「模型消息 + index」的表达形式。",
|
|
7383
7413
|
`- 完整消息:${COMPLETE_MESSAGE_DEFINITION}`,
|
|
7384
7414
|
"- <user_message index=\"N\">:用户消息条目(N 为该条完整消息的 index;文本原样,图片/文件等以注释补充)。",
|
|
7385
|
-
"- <
|
|
7415
|
+
"- <sys type=\"(kind)\" index=\"N\">:系统消息条目(user_message 中非 kind:user 的部分,如宿主注入的上下文),块中为空,内容不进入压缩输入。",
|
|
7386
7416
|
"- <reasoning>:模型的思考过程,仅作压缩参考,产物中不要出现。",
|
|
7387
7417
|
"- <assistant index=\"N\">:单条完整消息(模型输出文本,或 toolcall 及其 result)。",
|
|
7388
7418
|
"- <assistant start=\"A\" end=\"B\">:多条连续完整消息聚合的模块(A/B 为模块首尾完整消息的 index)。",
|
|
7389
7419
|
"",
|
|
7390
7420
|
"【压缩要求】",
|
|
7391
7421
|
"- 完整保留用户消息:<user_message> 条目逐条保留原文,不概括、不省略。",
|
|
7422
|
+
"- 完整保留系统消息:<sys> 条目逐条原样保留(type 与 index 不变),块中为空,不概括、不省略、不填充内容。",
|
|
7392
7423
|
"- <reasoning> 只作参考,输出产物中不包含 <reasoning> 块。",
|
|
7393
7424
|
"- 将具有关联性的 <assistant> 消息按内在逻辑连贯性划分为连续模块,聚合为 <assistant start=\"\" end=\"\"> 块:块内描述模块的目的、行为与结果;涉及的具体文件保留在模块内容中,多个前缀相同的路径合并简写。",
|
|
7394
7425
|
"- 单条重要的完整消息以 <assistant index=\"\"> 单独呈现,内容不受限制。",
|
|
@@ -7400,6 +7431,7 @@ function buildHistoryPrompt() {
|
|
|
7400
7431
|
"<user_message index=\"(index)\">",
|
|
7401
7432
|
"(user 消息原文)",
|
|
7402
7433
|
"</user_message>",
|
|
7434
|
+
"<sys type=\"(kind)\" index=\"(index)\"></sys>",
|
|
7403
7435
|
"<assistant start=\"(起始 index)\" end=\"(结束 index)\">",
|
|
7404
7436
|
"(模块的目的、行为与结果摘要)",
|
|
7405
7437
|
"</assistant>",
|
|
@@ -7411,73 +7443,6 @@ function buildHistoryPrompt() {
|
|
|
7411
7443
|
"【数据源】下方的 <history> 消息记录是本次要压缩的全部消息;压缩结果作为一个新的 <history> 块输出。"
|
|
7412
7444
|
].join("\n");
|
|
7413
7445
|
}
|
|
7414
|
-
/** 合法 <system-reminder> 块匹配:完整开闭标签对(非贪婪最短闭合;不匹配缺闭标签的残缺文本)。 */
|
|
7415
|
-
const SYSTEM_REMINDER_RE = /<system-reminder>[\s\S]*?<\/system-reminder>/g;
|
|
7416
|
-
/**
|
|
7417
|
-
* 解析 system-reminder 块(合法性判定):块可被 XML 解析且根元素为 <system-reminder> 时
|
|
7418
|
-
* 视为合法块并返回其根元素;否则(缺闭标签 / 内容含非法字符等)返回 null,按普通文本处理。
|
|
7419
|
-
*/
|
|
7420
|
-
function parseSystemReminder(block) {
|
|
7421
|
-
try {
|
|
7422
|
-
/** 根元素(必须为 system-reminder)。 */
|
|
7423
|
-
const root = new import_lib.DOMParser().parseFromString(block, "text/xml").documentElement;
|
|
7424
|
-
return root && root.nodeName === "system-reminder" ? root : null;
|
|
7425
|
-
} catch {
|
|
7426
|
-
return null;
|
|
7427
|
-
}
|
|
7428
|
-
}
|
|
7429
|
-
/**
|
|
7430
|
-
* 把解析出的 system-reminder 元素按原样复制进目标文档(标签与内容均不转义):
|
|
7431
|
-
* xmldom 无 importNode,手动递归复制元素 / 文本 / CDATA / 注释节点。
|
|
7432
|
-
*/
|
|
7433
|
-
function copySystemReminder(doc, source) {
|
|
7434
|
-
/** 目标元素(同标签名)。 */
|
|
7435
|
-
const el = doc.createElement(source.nodeName);
|
|
7436
|
-
for (let i = 0; i < source.attributes.length; i += 1) {
|
|
7437
|
-
/** 源属性(名称 + 值原样复制)。 */
|
|
7438
|
-
const attr = source.attributes[i];
|
|
7439
|
-
if (attr) el.setAttribute(attr.name, attr.value);
|
|
7440
|
-
}
|
|
7441
|
-
for (const child of Array.from(source.childNodes)) if (child.nodeType === 1) el.appendChild(copySystemReminder(doc, child));
|
|
7442
|
-
else if (child.nodeType === 3) el.appendChild(doc.createTextNode(child.nodeValue ?? ""));
|
|
7443
|
-
else if (child.nodeType === 4) el.appendChild(doc.createCDATASection(child.nodeValue ?? ""));
|
|
7444
|
-
else if (child.nodeType === 8) el.appendChild(doc.createComment(child.nodeValue ?? ""));
|
|
7445
|
-
return el;
|
|
7446
|
-
}
|
|
7447
|
-
/**
|
|
7448
|
-
* 追加用户文本到 user_message 元素:合法 <system-reminder> 块整块原样插入(不转义),
|
|
7449
|
-
* 其余文本按普通文本 XML 转义(createTextNode)。
|
|
7450
|
-
*/
|
|
7451
|
-
function appendUserText(doc, el, text) {
|
|
7452
|
-
/** 已消费的文本位置。 */
|
|
7453
|
-
let last = 0;
|
|
7454
|
-
for (const m of text.matchAll(SYSTEM_REMINDER_RE)) {
|
|
7455
|
-
/** 匹配起点(缺省 0)。 */
|
|
7456
|
-
const start = m.index ?? 0;
|
|
7457
|
-
/** 块前的普通文本(转义)。 */
|
|
7458
|
-
if (start > last) el.appendChild(doc.createTextNode(text.slice(last, start)));
|
|
7459
|
-
/** 块原文。 */
|
|
7460
|
-
const block = m[0];
|
|
7461
|
-
/** 合法判定(可被 XML 解析)。 */
|
|
7462
|
-
const parsed = parseSystemReminder(block);
|
|
7463
|
-
if (parsed !== null) el.appendChild(copySystemReminder(doc, parsed));
|
|
7464
|
-
else el.appendChild(doc.createTextNode(block));
|
|
7465
|
-
/** 消费位置推进到块尾。 */
|
|
7466
|
-
last = start + block.length;
|
|
7467
|
-
}
|
|
7468
|
-
/** 末尾剩余普通文本(转义)。 */
|
|
7469
|
-
if (last < text.length) el.appendChild(doc.createTextNode(text.slice(last)));
|
|
7470
|
-
}
|
|
7471
|
-
/**
|
|
7472
|
-
* 提取文本中全部合法的 <system-reminder> 块(完整开闭标签对且内容可被 XML 解析);
|
|
7473
|
-
* 供渲染(原样插入)与未压缩消息测量(不计入)共用;不合法部分按普通文本处理。
|
|
7474
|
-
*/
|
|
7475
|
-
function legitimateSystemReminderBlocks(text) {
|
|
7476
|
-
/** 合法块缓冲区。 */
|
|
7477
|
-
const out = [];
|
|
7478
|
-
for (const m of text.matchAll(SYSTEM_REMINDER_RE)) if (parseSystemReminder(m[0]) !== null) out.push(m[0]);
|
|
7479
|
-
return out;
|
|
7480
|
-
}
|
|
7481
7446
|
/** 渲染用户消息条目(DOM 元素):文本块原样;图片/文件等非文本块以注释补充(说明传入了什么)。 */
|
|
7482
7447
|
function renderUserEntry(doc, session, cm) {
|
|
7483
7448
|
/** 用户消息事件(seq 缺失则无法渲染)。 */
|
|
@@ -7492,7 +7457,7 @@ function renderUserEntry(doc, session, cm) {
|
|
|
7492
7457
|
/** 是否存在可输出内容(文本或注释)。 */
|
|
7493
7458
|
let hasContent = false;
|
|
7494
7459
|
for (const block of message.content) if (block.type === "text") {
|
|
7495
|
-
|
|
7460
|
+
el.appendChild(doc.createTextNode(String(block.text)));
|
|
7496
7461
|
hasContent = true;
|
|
7497
7462
|
} else if (block.type === "image") {
|
|
7498
7463
|
/** 图片附件元数据(名称 / 媒体类型 / 尺寸 / 字节数)。 */
|
|
@@ -7512,11 +7477,12 @@ function renderUserEntry(doc, session, cm) {
|
|
|
7512
7477
|
}
|
|
7513
7478
|
/**
|
|
7514
7479
|
* 渲染完整消息记录(观察输入,new 模式):输出一个合法的 <history> 块——
|
|
7515
|
-
* - user → <user_message index="N"
|
|
7480
|
+
* - user → <user_message index="N">(文本原样;图片/文件注释);
|
|
7481
|
+
* - sys → <sys type="KIND" index="N"></sys>(系统消息空块,内容不进入压缩输入);
|
|
7516
7482
|
* - 每条 assistant 消息的 reasoning → <reasoning>(参考条目,产物中没有);
|
|
7517
7483
|
* - assistant / toolcall → <assistant index="N">(模型输出文本 / toolcall&result 原样)。
|
|
7518
7484
|
* 文本经 XML 序列化自动转义(用户输入 / 文本 / reasoning 中的特殊字符不破坏 XML 合法性)。
|
|
7519
|
-
* 仅渲染 seqs
|
|
7485
|
+
* 仅渲染 seqs 全部落在给定集合内的完整消息(本插件自产消息天然不占位)。
|
|
7520
7486
|
*/
|
|
7521
7487
|
function renderMessages(session, seqs) {
|
|
7522
7488
|
/** 遮蔽 seq 集合。 */
|
|
@@ -7542,6 +7508,15 @@ function renderMessages(session, seqs) {
|
|
|
7542
7508
|
const entries = [];
|
|
7543
7509
|
for (const cm of indexCompleteMessages(session)) {
|
|
7544
7510
|
if (!cm.seqs.every((seq) => shadowed.has(seq))) continue;
|
|
7511
|
+
if (cm.type === "sys") {
|
|
7512
|
+
/** sys 元素(type=source.kind,index=完整消息序号)。 */
|
|
7513
|
+
const sysEl = doc.createElement("sys");
|
|
7514
|
+
sysEl.setAttribute("type", cm.kind ?? "");
|
|
7515
|
+
sysEl.setAttribute("index", String(cm.index));
|
|
7516
|
+
sysEl.appendChild(doc.createTextNode(""));
|
|
7517
|
+
entries.push(sysEl);
|
|
7518
|
+
continue;
|
|
7519
|
+
}
|
|
7545
7520
|
if (cm.type === "user") {
|
|
7546
7521
|
/** 用户消息条目(无文本且无注释则跳过)。 */
|
|
7547
7522
|
const rendered = renderUserEntry(doc, session, cm);
|
|
@@ -7640,7 +7615,7 @@ function buildSummaryOptions(session, instruction, contextText, maxTokens, targe
|
|
|
7640
7615
|
};
|
|
7641
7616
|
}
|
|
7642
7617
|
/** 产出日志后插入首个 <history> 后的格式说明(XML 注释,完整消息定义 + 条目标签语义)。 */
|
|
7643
|
-
const HISTORY_FORMAT_NOTE = `<!-- 完整消息:${COMPLETE_MESSAGE_DEFINITION} <user_message index="N"> 与 <assistant index="N"> 表示单条完整消息,<assistant start="A" end="B"> 表示连续模块,start/end 是首尾完整消息的 index -->`;
|
|
7618
|
+
const HISTORY_FORMAT_NOTE = `<!-- 完整消息:${COMPLETE_MESSAGE_DEFINITION} <user_message index="N"> 与 <assistant index="N"> 表示单条完整消息,<assistant start="A" end="B"> 表示连续模块,start/end 是首尾完整消息的 index;<sys type="KIND" index="N"> 表示系统消息,块中为空 -->`;
|
|
7644
7619
|
/** 读取元素整数属性(非负整数;缺失 / 非数字返回 undefined)。 */
|
|
7645
7620
|
function intAttr(el, name) {
|
|
7646
7621
|
/** 属性原始值(缺失为 null)。 */
|
|
@@ -7653,7 +7628,7 @@ function intAttr(el, name) {
|
|
|
7653
7628
|
* 用 XML 解析器解析一个 <history> 块(结构合法性校验):
|
|
7654
7629
|
* - 非法 XML(标签不匹配 / 未闭合 / 多根等)→ null;
|
|
7655
7630
|
* - 根节点必须是 <history>;
|
|
7656
|
-
* - 顶层只允许 user_message / assistant 条目元素(其余元素类型视为不合法);
|
|
7631
|
+
* - 顶层只允许 user_message / assistant / sys 条目元素(其余元素类型视为不合法);
|
|
7657
7632
|
* - 出现 <reasoning> 元素时标记 hasReasoning(产物不允许)。
|
|
7658
7633
|
* 条目按文档顺序提取(index / start / end 属性缺失或不合法 → 不合法)。
|
|
7659
7634
|
*/
|
|
@@ -7694,6 +7669,14 @@ function parseHistoryBlock(xml) {
|
|
|
7694
7669
|
kind: "user",
|
|
7695
7670
|
index
|
|
7696
7671
|
});
|
|
7672
|
+
} else if (tag === "sys") {
|
|
7673
|
+
/** index 属性(缺失/非法 → 不合法)。 */
|
|
7674
|
+
const index = intAttr(el, "index");
|
|
7675
|
+
if (index === void 0) return null;
|
|
7676
|
+
entries.push({
|
|
7677
|
+
kind: "sys",
|
|
7678
|
+
index
|
|
7679
|
+
});
|
|
7697
7680
|
} else if (tag === "assistant") {
|
|
7698
7681
|
/** 单条 index 或模块 start..end(二选一)。 */
|
|
7699
7682
|
const index = intAttr(el, "index");
|
|
@@ -7918,10 +7901,9 @@ function reflectExpectedEnd(contextText) {
|
|
|
7918
7901
|
*/
|
|
7919
7902
|
function historyTextOf(event) {
|
|
7920
7903
|
if (event?.type !== "user/message") return void 0;
|
|
7921
|
-
/** 消息 source
|
|
7904
|
+
/** 消息 source(本插件自产消息的标记;含兼容旧宿主 checkpoint 标记)。 */
|
|
7922
7905
|
const source = event.data.source;
|
|
7923
|
-
if (source
|
|
7924
|
-
if (source.plugin !== "compact" && source.plugin !== "dsh-plugin-om") return void 0;
|
|
7906
|
+
if (!isPluginOwnedSource(source)) return void 0;
|
|
7925
7907
|
/** 消息纯文本。 */
|
|
7926
7908
|
const text = blocksToText(event.data.content);
|
|
7927
7909
|
/** 首个 <history 出现位置(无则非压缩日志)。 */
|
|
@@ -7933,25 +7915,9 @@ function historyTextOf(event) {
|
|
|
7933
7915
|
return text;
|
|
7934
7916
|
}
|
|
7935
7917
|
/**
|
|
7936
|
-
* 消息文本中合法 <system-reminder> 块的 token 估算(4 字符 ≈ 1 token,与 estimateTextTokens
|
|
7937
|
-
* 一致):宿主注入的提醒不计入未压缩消息,避免推高观察阈值触发压缩。
|
|
7938
|
-
*/
|
|
7939
|
-
function systemReminderTokens(message) {
|
|
7940
|
-
/** 消息内容块(非记录或非数组则无文本可计)。 */
|
|
7941
|
-
const content = isRecord(message) && Array.isArray(message.content) ? message.content : null;
|
|
7942
|
-
if (!content) return 0;
|
|
7943
|
-
/** token 合计。 */
|
|
7944
|
-
let total = 0;
|
|
7945
|
-
for (const block of content) {
|
|
7946
|
-
if (!isRecord(block) || block.type !== "text" || typeof block.text !== "string") continue;
|
|
7947
|
-
for (const sr of legitimateSystemReminderBlocks(block.text)) total += estimateTextTokens(sr);
|
|
7948
|
-
}
|
|
7949
|
-
return total;
|
|
7950
|
-
}
|
|
7951
|
-
/**
|
|
7952
7918
|
* 未压缩消息 token 估算:最后一个 <history> 块之后的表层节点合计
|
|
7953
7919
|
* (其前含自身视为已压缩,不计入观察阈值衡量对象;无压缩日志时计全部)。
|
|
7954
|
-
*
|
|
7920
|
+
* 系统消息(user/message 中非 kind:user 的部分,如宿主注入的上下文)不计入阈值。
|
|
7955
7921
|
*/
|
|
7956
7922
|
function measureUncompressedTokens(session, meter) {
|
|
7957
7923
|
/** 压缩边界(最后一个 history 块的 seq;无则 undefined)。 */
|
|
@@ -7969,9 +7935,10 @@ function measureUncompressedTokens(session, meter) {
|
|
|
7969
7935
|
const event = session.events[seq];
|
|
7970
7936
|
const message = event ? session.deriveEventMessage(event) : null;
|
|
7971
7937
|
if (!message) continue;
|
|
7972
|
-
|
|
7973
|
-
|
|
7974
|
-
|
|
7938
|
+
if (event?.type === "user/message") {
|
|
7939
|
+
if (event.data.source?.kind !== "user") continue;
|
|
7940
|
+
}
|
|
7941
|
+
total += meter.estimateMessage(message);
|
|
7975
7942
|
}
|
|
7976
7943
|
return total;
|
|
7977
7944
|
}
|
|
@@ -8684,7 +8651,8 @@ function resolveConfig(raw) {
|
|
|
8684
8651
|
//#region src/recall.ts
|
|
8685
8652
|
/**
|
|
8686
8653
|
* recall 工具:按「完整消息」序号(index)回看原始会话(start/end 为完整消息 index,
|
|
8687
|
-
* offset 为相对 start 的完整消息步数)。完整消息即
|
|
8654
|
+
* offset 为相对 start 的完整消息步数)。完整消息即 `用户消息`(user_message 中 kind 为 user
|
|
8655
|
+
* 的部分)、`系统消息`(user_message 中其余 kind 的部分)、`模型输出文本`和`具有result的
|
|
8688
8656
|
* toolcall`;首条完整消息的 index 为 0,后续递增、会话内全局稳定,与摘要日志条目同一套编号。
|
|
8689
8657
|
* recall 自身不设输出上限:超大的工具结果由 tool-result-pruner 裁剪(pruneContent),
|
|
8690
8658
|
* 输出 token 由 pruner 配置控制。
|
|
@@ -8718,7 +8686,7 @@ function parseRecallArgs(raw) {
|
|
|
8718
8686
|
function buildRecallTool(getPruner) {
|
|
8719
8687
|
return {
|
|
8720
8688
|
name: "recall",
|
|
8721
|
-
description:
|
|
8689
|
+
description: `根据完整消息序号(index),回看指定区间的过往消息。${COMPLETE_MESSAGE_DEFINITION} start 必须传入,是区间的基准;end 和 offset 二选一:end 指定另一个边界(含两端,与 start 的位置关系不影响结果),offset 指定区间包含的完整消息数量(正数向后、负数向前)。`,
|
|
8722
8690
|
parameters: {
|
|
8723
8691
|
start: {
|
|
8724
8692
|
type: "number",
|
|
@@ -8795,7 +8763,8 @@ function buildRecallTool(getPruner) {
|
|
|
8795
8763
|
//#region src/semantic-recall.ts
|
|
8796
8764
|
/**
|
|
8797
8765
|
* recall-semantic 工具:按自然语言 query 对会话全部完整消息(含被压缩/遮蔽的)做语义
|
|
8798
|
-
* 检索,返回最匹配的完整消息与匹配说明。完整消息即
|
|
8766
|
+
* 检索,返回最匹配的完整消息与匹配说明。完整消息即 `用户消息`(user_message 中 kind 为 user
|
|
8767
|
+
* 的部分)、`系统消息`(user_message 中其余 kind 的部分)、`模型输出文本`和`具有result的
|
|
8799
8768
|
* toolcall`;首条完整消息的 index 为 0,后续递增、会话内全局稳定。
|
|
8800
8769
|
*
|
|
8801
8770
|
* - 参数:query 必填;top_k(默认 3,1-10);start/end/offset 限定检索区间
|
|
@@ -8907,7 +8876,7 @@ function buildSemanticRecallTool(options) {
|
|
|
8907
8876
|
const embed = options?.embedder ?? ((texts) => getEmbedder().then((fn) => fn(texts)));
|
|
8908
8877
|
return {
|
|
8909
8878
|
name: "recall-semantic",
|
|
8910
|
-
description:
|
|
8879
|
+
description: `按语义(自然语言含义)在会话全部完整消息中检索:${COMPLETE_MESSAGE_DEFINITION} 用一句话描述你要找的内容(可混用中英文与代码术语)。返回最匹配的若干条完整消息、index 与匹配说明;如需精确定位某个 index 周边的消息,请再用 recall 工具。`,
|
|
8911
8880
|
parameters: {
|
|
8912
8881
|
query: {
|
|
8913
8882
|
type: "string",
|
package/dist/log-index.d.ts
CHANGED
|
@@ -1,16 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 会话日志索引:完整消息索引(index 定位完整消息,recall 与摘要共用同一套编号),
|
|
3
|
-
* 以及表层节点定位辅助。事件日志仅追加(被遮蔽的事件仍可读,recall 依赖此性质)。
|
|
4
|
-
*
|
|
5
|
-
* 完整消息是摘要日志与 recall 共用的定位单位,分三类:
|
|
6
|
-
* - user:用户消息(user/message)占一条;
|
|
7
|
-
* - assistant:模型输出文本(assistant/message 中的文本块)占一条;
|
|
8
|
-
* - toolcall:单个工具调用及其结果占一条(同一条 AI 消息里的文本与工具调用拆开,
|
|
9
|
-
* tool/result 按 source.callId 匹配其 tool-call;未匹配的 result 独立成条,防御)。
|
|
10
|
-
* 插件自产消息(<history>、运行时快照等 source.kind === 'plugin')不占 index。
|
|
11
|
-
* index 从 0 起、按日志顺序递增、只追加不重排 → 会话内全局稳定,
|
|
12
|
-
* 压缩后旧摘要条目引用的 index 仍然有效。
|
|
13
|
-
*/
|
|
14
1
|
import type { CompleteMessage, MessageIndex, Session, SessionEvent } from './types.ts';
|
|
15
2
|
/** 工具结果裁剪器结构(tool-result-pruner;超大结果渲染前裁剪)。 */
|
|
16
3
|
export type PrunerLike = {
|
|
@@ -26,7 +13,7 @@ export declare function messageIdOfEvent(event: SessionEvent | undefined): strin
|
|
|
26
13
|
/** 消息索引:按日志顺序列出全部消息事件,并按 message_id 定位其在消息序列中的下标。 */
|
|
27
14
|
export declare function indexMessages(session: Session): MessageIndex;
|
|
28
15
|
/**
|
|
29
|
-
*
|
|
16
|
+
* 完整消息索引:按日志顺序把消息事件折叠为完整消息序列(四类,见文件头)。
|
|
30
17
|
* 工具调用结果按 source.callId 匹配其 tool-call 并入该条;未匹配的 result 独立成条(防御)。
|
|
31
18
|
* 插件在 agent/pre-step 触发压缩(日志 call-result 完备),因此压缩时不存在未闭合的
|
|
32
19
|
* tool-call;索引对未闭合调用不设特殊处理。
|
|
@@ -34,7 +21,7 @@ export declare function indexMessages(session: Session): MessageIndex;
|
|
|
34
21
|
export declare function indexCompleteMessages(session: Session): CompleteMessage[];
|
|
35
22
|
/**
|
|
36
23
|
* 渲染一条完整消息的文本(recall 输出 / new 模式输入共用):
|
|
37
|
-
* - user:消息原文;
|
|
24
|
+
* - user / sys:消息原文;
|
|
38
25
|
* - assistant:仅文本块;
|
|
39
26
|
* - toolcall:调用块(工具名 + 参数)+ 结果文本(pruner 裁剪超大结果)。
|
|
40
27
|
*/
|
package/dist/log-index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log-index.d.ts","sourceRoot":"","sources":["../src/log-index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"log-index.d.ts","sourceRoot":"","sources":["../src/log-index.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EACV,eAAe,EAEf,YAAY,EAEZ,OAAO,EACP,YAAY,EACb,MAAM,YAAY,CAAC;AAGpB,+CAA+C;AAC/C,MAAM,MAAM,UAAU,GAAG;IAAE,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,KAAK,OAAO,EAAE,GAAG,IAAI,CAAA;CAAE,CAAC;AAE7F;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAG5E;AAED,wEAAwE;AACxE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,YAAY,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAMpF;AAED,qDAAqD;AACrD,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,YAAY,CA0B5D;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,eAAe,EAAE,CA2EzE;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,OAAO,EAChB,EAAE,EAAE,eAAe,EACnB,MAAM,CAAC,EAAE,UAAU,GAClB,MAAM,CAgER"}
|
package/dist/recall.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* recall 工具:按「完整消息」序号(index)回看原始会话(start/end 为完整消息 index,
|
|
3
|
-
* offset 为相对 start 的完整消息步数)。完整消息即
|
|
3
|
+
* offset 为相对 start 的完整消息步数)。完整消息即 `用户消息`(user_message 中 kind 为 user
|
|
4
|
+
* 的部分)、`系统消息`(user_message 中其余 kind 的部分)、`模型输出文本`和`具有result的
|
|
4
5
|
* toolcall`;首条完整消息的 index 为 0,后续递增、会话内全局稳定,与摘要日志条目同一套编号。
|
|
5
6
|
* recall 自身不设输出上限:超大的工具结果由 tool-result-pruner 裁剪(pruneContent),
|
|
6
7
|
* 输出 token 由 pruner 配置控制。
|
package/dist/recall.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recall.d.ts","sourceRoot":"","sources":["../src/recall.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"recall.d.ts","sourceRoot":"","sources":["../src/recall.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EAAE,cAAc,EAAkB,MAAM,YAAY,CAAC;AAGjE;;;GAGG;AACH,eAAO,MAAM,gBAAgB;;;;iBAQzB,CAAC;AAEL,4CAA4C;AAC5C,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE1D;;;GAGG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,UAAU,CAYxD;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,SAAS,CAAC,EAAE,MAAM,OAAO,GAAG,cAAc,CAqFzE"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* recall-semantic 工具:按自然语言 query 对会话全部完整消息(含被压缩/遮蔽的)做语义
|
|
3
|
-
* 检索,返回最匹配的完整消息与匹配说明。完整消息即
|
|
3
|
+
* 检索,返回最匹配的完整消息与匹配说明。完整消息即 `用户消息`(user_message 中 kind 为 user
|
|
4
|
+
* 的部分)、`系统消息`(user_message 中其余 kind 的部分)、`模型输出文本`和`具有result的
|
|
4
5
|
* toolcall`;首条完整消息的 index 为 0,后续递增、会话内全局稳定。
|
|
5
6
|
*
|
|
6
7
|
* - 参数:query 必填;top_k(默认 3,1-10);start/end/offset 限定检索区间
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"semantic-recall.d.ts","sourceRoot":"","sources":["../src/semantic-recall.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"semantic-recall.d.ts","sourceRoot":"","sources":["../src/semantic-recall.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAoB,KAAK,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE/F,OAAO,KAAK,EAAmB,cAAc,EAAkB,MAAM,YAAY,CAAC;AAGlF,qEAAqE;AACrE,eAAO,MAAM,wBAAwB;;;;;;iBAUjC,CAAC;AAEL,6DAA6D;AAC7D,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,+CAA+C;AAC/C,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,OAAO,GAAG,kBAAkB,CAWxE;AAED,6DAA6D;AAC7D,MAAM,MAAM,WAAW,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC;AAExE;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,IAAI,CAAC,kBAAkB,EAAE,OAAO,GAAG,KAAK,GAAG,QAAQ,CAAC,GACzD,WAAW,CA2Bb;AAED,uCAAuC;AACvC,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAOlD;AAED,+CAA+C;AAC/C,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAcnF;AAED,+CAA+C;AAC/C,eAAO,MAAM,gCAAgC,0iBACoE,CAAC;AAElH,uEAAuE;AACvE,wBAAgB,uBAAuB,CAAC,OAAO,CAAC,EAAE;IAChD,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sCAAsC;IACtC,WAAW,CAAC,EAAE,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CACxD,GAAG,cAAc,CAsHjB"}
|
package/dist/summarize.d.ts
CHANGED
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
* 输入与输出都是合法的 <history> 块(模型消息 + index 的表达形式),先定义块、要求压缩、
|
|
6
6
|
* 再给出数据源(下方 <history> 消息记录)。
|
|
7
7
|
*
|
|
8
|
-
* 观察输入由 renderMessages 渲染为 <history>
|
|
9
|
-
*
|
|
10
|
-
* <
|
|
8
|
+
* 观察输入由 renderMessages 渲染为 <history> 块:用户消息文本原样(图片/文件以
|
|
9
|
+
* 注释补充)、系统消息(user_message 中非 kind:user 的部分)渲染为
|
|
10
|
+
* <sys type="KIND" index="N"> 空块(内容不进入输入)、<reasoning> 参考条目
|
|
11
|
+
* (产物中没有)、assistant 文本与 toolcall&result 原样。
|
|
11
12
|
* 输出经 extractSummaryLog 校验:合法 <history> 块、不含 <reasoning>、index/start/end 连续
|
|
12
13
|
* (与预期覆盖区间一致),失败按 config.compressRetryCount 重试。
|
|
13
14
|
* token usage 从流式响应的 usage chunk 提取,归入主会话记录。仅主会话生效(index.ts 守卫)。
|
|
@@ -20,18 +21,14 @@ import { type RoutedTarget } from './utils.ts';
|
|
|
20
21
|
* index/start/end 连续)、输出格式(一个合法 <history> 块,无 reasoning)、数据源说明。
|
|
21
22
|
*/
|
|
22
23
|
export declare function buildHistoryPrompt(): string;
|
|
23
|
-
/**
|
|
24
|
-
* 提取文本中全部合法的 <system-reminder> 块(完整开闭标签对且内容可被 XML 解析);
|
|
25
|
-
* 供渲染(原样插入)与未压缩消息测量(不计入)共用;不合法部分按普通文本处理。
|
|
26
|
-
*/
|
|
27
|
-
export declare function legitimateSystemReminderBlocks(text: string): string[];
|
|
28
24
|
/**
|
|
29
25
|
* 渲染完整消息记录(观察输入,new 模式):输出一个合法的 <history> 块——
|
|
30
|
-
* - user → <user_message index="N"
|
|
26
|
+
* - user → <user_message index="N">(文本原样;图片/文件注释);
|
|
27
|
+
* - sys → <sys type="KIND" index="N"></sys>(系统消息空块,内容不进入压缩输入);
|
|
31
28
|
* - 每条 assistant 消息的 reasoning → <reasoning>(参考条目,产物中没有);
|
|
32
29
|
* - assistant / toolcall → <assistant index="N">(模型输出文本 / toolcall&result 原样)。
|
|
33
30
|
* 文本经 XML 序列化自动转义(用户输入 / 文本 / reasoning 中的特殊字符不破坏 XML 合法性)。
|
|
34
|
-
* 仅渲染 seqs
|
|
31
|
+
* 仅渲染 seqs 全部落在给定集合内的完整消息(本插件自产消息天然不占位)。
|
|
35
32
|
*/
|
|
36
33
|
export declare function renderMessages(session: Session, seqs: readonly number[]): string;
|
|
37
34
|
/** 摘要调用结果:文本 + 可选 token usage(摘要请求自身消耗,随 compaction/summary 归入主会话记录)。 */
|
|
@@ -42,10 +39,10 @@ export type SummarySubagentResult = {
|
|
|
42
39
|
/** 日志最小有效长度:<history> 中间内容小于该长度视为不合法(C 段校验)。 */
|
|
43
40
|
export declare const MIN_HISTORY_LENGTH = 10;
|
|
44
41
|
/** 产出日志后插入首个 <history> 后的格式说明(XML 注释,完整消息定义 + 条目标签语义)。 */
|
|
45
|
-
export declare const HISTORY_FORMAT_NOTE = "<!-- \u5B8C\u6574\u6D88\u606F\uFF1A`\u7528\u6237\u6D88\u606F`\uFF0C`\u6A21\u578B\u8F93\u51FA\u6587\u672C`\u548C`\u5177\u6709result\u7684toolcall`\u88AB\u89C6\u4F5C`\u5B8C\u6574\u6D88\u606F`\u3002\u9996\u6761`\u5B8C\u6574\u6D88\u606F`\u7684index\u662F0\uFF0C\u540E\u7EED\u7684index\u9012\u589E\u3002 <user_message index=\"N\"> \u4E0E <assistant index=\"N\"> \u8868\u793A\u5355\u6761\u5B8C\u6574\u6D88\u606F\uFF0C<assistant start=\"A\" end=\"B\"> \u8868\u793A\u8FDE\u7EED\u6A21\u5757\uFF0Cstart/end \u662F\u9996\u5C3E\u5B8C\u6574\u6D88\u606F\u7684 index -->";
|
|
42
|
+
export declare const HISTORY_FORMAT_NOTE = "<!-- \u5B8C\u6574\u6D88\u606F\uFF1A`\u7528\u6237\u6D88\u606F`\uFF08user_message \u4E2D kind \u4E3A user \u7684\u90E8\u5206\uFF09\uFF0C`\u7CFB\u7EDF\u6D88\u606F`\uFF08user_message \u4E2D\u5176\u4F59 kind \u7684\u90E8\u5206\uFF09\uFF0C`\u6A21\u578B\u8F93\u51FA\u6587\u672C`\u548C`\u5177\u6709result\u7684toolcall`\u88AB\u89C6\u4F5C`\u5B8C\u6574\u6D88\u606F`\u3002\u9996\u6761`\u5B8C\u6574\u6D88\u606F`\u7684index\u662F0\uFF0C\u540E\u7EED\u7684index\u9012\u589E\u3002 <user_message index=\"N\"> \u4E0E <assistant index=\"N\"> \u8868\u793A\u5355\u6761\u5B8C\u6574\u6D88\u606F\uFF0C<assistant start=\"A\" end=\"B\"> \u8868\u793A\u8FDE\u7EED\u6A21\u5757\uFF0Cstart/end \u662F\u9996\u5C3E\u5B8C\u6574\u6D88\u606F\u7684 index\uFF1B<sys type=\"KIND\" index=\"N\"> \u8868\u793A\u7CFB\u7EDF\u6D88\u606F\uFF0C\u5757\u4E2D\u4E3A\u7A7A -->";
|
|
46
43
|
/** history 块内条目(单条 index 或模块 start/end)。 */
|
|
47
44
|
export type HistoryEntryRange = {
|
|
48
|
-
kind: 'user' | 'assistant';
|
|
45
|
+
kind: 'user' | 'assistant' | 'sys';
|
|
49
46
|
index?: number;
|
|
50
47
|
start?: number;
|
|
51
48
|
end?: number;
|
package/dist/summarize.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"summarize.d.ts","sourceRoot":"","sources":["../src/summarize.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"summarize.d.ts","sourceRoot":"","sources":["../src/summarize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAaH,OAAO,KAAK,EAAE,KAAK,EAAmB,OAAO,EAAE,OAAO,EAAE,UAAU,EAAe,MAAM,YAAY,CAAC;AACpG,OAAO,EAAE,KAAK,YAAY,EAAQ,MAAM,YAAY,CAAC;AAErD;;;;GAIG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAsC3C;AA0CD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAqEhF;AAED,yEAAyE;AACzE,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,UAAU,CAAC;CACpB,CAAC;AA8EF,gDAAgD;AAChD,eAAO,MAAM,kBAAkB,KAAK,CAAC;AAErC,0DAA0D;AAC1D,eAAO,MAAM,mBAAmB,8zBAAiN,CAAC;AAElP,4CAA4C;AAC5C,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,KAAK,CAAC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAoFF;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAYrE;AACD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,iBAAiB,EAAE,GAC3B;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAuBvC;AAED,sCAAsC;AACtC,MAAM,MAAM,sBAAsB,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtE;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,sBAAsB,GAAG,MAAM,GAAG,IAAI,CAiC/F;AACD,iFAAiF;AACjF,eAAO,MAAM,4BAA4B,KAAK,CAAC;AAK/C;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,KAAK,EACZ,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,YAAY,EACpB,KAAK,EAAE,OAAO,EACd,MAAM,CAAC,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,sBAAsB,CAAA;CAAE,GACpE,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CA+EvC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -42,17 +42,24 @@ export type MessageIndex = {
|
|
|
42
42
|
byId: Map<string, number>;
|
|
43
43
|
};
|
|
44
44
|
/**
|
|
45
|
-
* 一条完整消息:摘要日志与 recall
|
|
46
|
-
* user
|
|
45
|
+
* 一条完整消息:摘要日志与 recall 共用的定位单位,分四类——
|
|
46
|
+
* user(用户消息,user_message 中 source.kind === 'user')、
|
|
47
|
+
* sys(系统消息,user_message 中其余 source.kind 的部分,如宿主注入的上下文)、
|
|
48
|
+
* assistant(模型输出文本)、toolcall(单个工具调用及其结果)。
|
|
47
49
|
* index 从 0 起、按日志顺序递增、只追加不重排 → 会话内全局稳定
|
|
48
|
-
* (压缩后旧摘要条目引用的 index
|
|
50
|
+
* (压缩后旧摘要条目引用的 index 仍然有效);本插件自产的压缩日志消息不占位。
|
|
49
51
|
*/
|
|
50
52
|
export type CompleteMessage = {
|
|
51
53
|
/** 完整消息序号(0 起,全局稳定)。 */
|
|
52
54
|
index: number;
|
|
53
|
-
/**
|
|
54
|
-
|
|
55
|
-
|
|
55
|
+
/**
|
|
56
|
+
* 类别:user=用户消息;sys=系统消息(压缩日志中以 <sys type="KIND" index="N"> 空块
|
|
57
|
+
* 表示);assistant=模型输出文本;toolcall=单个工具调用及其结果。
|
|
58
|
+
*/
|
|
59
|
+
type: 'user' | 'sys' | 'assistant' | 'toolcall';
|
|
60
|
+
/** 系统消息的 source.kind(仅 sys 类;如 agent-instructions / skill-catalog)。 */
|
|
61
|
+
kind?: string;
|
|
62
|
+
/** 关联的消息事件 seq(user/sys/assistant=1 个;toolcall=assistant 消息 + 结果)。 */
|
|
56
63
|
seqs: number[];
|
|
57
64
|
/** 工具调用 id(仅 toolcall 类;关联 tool/result 用)。 */
|
|
58
65
|
callId?: string;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;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,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC7E,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACtE,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,MAAM,wBAAwB,CAAC;AAE7E,gDAAgD;AAChD,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD;;;GAGG;AACH,YAAY,EACV,KAAK,EACL,YAAY,EACZ,OAAO,EACP,YAAY,EACZ,MAAM,EACN,OAAO,EACP,OAAO,EACP,YAAY,EACZ,cAAc,EACd,WAAW,EACX,oBAAoB,EACpB,YAAY,EACZ,UAAU,EACV,UAAU,EACV,cAAc,EACd,gBAAgB,EAChB,cAAc,EACd,WAAW,GACZ,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,mBAAmB;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,wBAAwB;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,2BAA2B;IAC3B,IAAI,EAAE,cAAc,GAAG,mBAAmB,GAAG,aAAa,CAAC;CAC5D,CAAC;AAEF,yDAAyD;AACzD,MAAM,MAAM,YAAY,GAAG;IACzB,oBAAoB;IACpB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,kCAAkC;IAClC,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC3B,CAAC;AAEF
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;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,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC7E,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACtE,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,MAAM,wBAAwB,CAAC;AAE7E,gDAAgD;AAChD,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD;;;GAGG;AACH,YAAY,EACV,KAAK,EACL,YAAY,EACZ,OAAO,EACP,YAAY,EACZ,MAAM,EACN,OAAO,EACP,OAAO,EACP,YAAY,EACZ,cAAc,EACd,WAAW,EACX,oBAAoB,EACpB,YAAY,EACZ,UAAU,EACV,UAAU,EACV,cAAc,EACd,gBAAgB,EAChB,cAAc,EACd,WAAW,GACZ,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,mBAAmB;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,wBAAwB;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,2BAA2B;IAC3B,IAAI,EAAE,cAAc,GAAG,mBAAmB,GAAG,aAAa,CAAC;CAC5D,CAAC;AAEF,yDAAyD;AACzD,MAAM,MAAM,YAAY,GAAG;IACzB,oBAAoB;IACpB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,kCAAkC;IAClC,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC3B,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,wBAAwB;IACxB,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,WAAW,GAAG,UAAU,CAAC;IAChD,uEAAuE;IACvE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sEAAsE;IACtE,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,8CAA8C;IAC9C,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC"}
|