dsh-plugin-om 0.0.25 → 0.0.26
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 +12 -4
- package/dist/compaction-log.d.ts +43 -0
- package/dist/compaction-log.d.ts.map +1 -0
- package/dist/compress.d.ts +30 -10
- package/dist/compress.d.ts.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +298 -72
- package/dist/summarize.d.ts +12 -5
- package/dist/summarize.d.ts.map +1 -1
- package/dist/types.d.ts +30 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,10 +7,11 @@
|
|
|
7
7
|
## 功能
|
|
8
8
|
|
|
9
9
|
- **自动压缩**(仅主会话,`agent/pre-step` 时阻塞串行执行):
|
|
10
|
-
- **观察**:净压力(上下文压力 − 已压缩 `<history>` 块 token 估算合计 − 系统提示词 token 估算 − 工具定义 token
|
|
10
|
+
- **观察**:净压力(上下文压力 − 已压缩 `<history>` 块 token 估算合计 − 系统提示词 token 估算 − 工具定义 token 估算)首次 ≥ `observeThresholdTokens` 时记录待定标记(触发点 = 当时的最后一条完整消息),本次不压缩;待定后新增完整消息数达到 `tailMessageCount` 时,摘要压缩边界至触发点的全部消息并追加为新 `<history>` 块,精确替换被压缩的消息区间(旧块保留,等待期消息成为新的未压缩尾部)。待定标记以 log-only `om/observe-pending` / `om/observe-invalidate` 会话事件持久化(重启后从日志恢复),摘要失败保留待定、下个 pre-step 直接重试;`tailMessageCount=0` 时触发当轮立即执行
|
|
11
11
|
- **反思**:全部 `<history>` 块 token 合计 ≥ `reflectThresholdTokens` 时,把多个摘要块合并为一条更紧凑的摘要
|
|
12
12
|
- **输出容错**:摘要输出按首个 `<history>` 开标签到最后一个 `</history>` 定位;整块 XML 非法时按条目标签模糊提取并重建为合法块,再校验无 reasoning 与 index 连续
|
|
13
|
-
- **失败中断**:摘要尝试全部耗尽后拒绝当前 step(当前 turn 以 blocked 结束,不再继续 AI 会话;signal
|
|
13
|
+
- **失败中断**:摘要尝试全部耗尽后拒绝当前 step(当前 turn 以 blocked 结束,不再继续 AI 会话;signal 中止除外),最后一次尝试的实际报错与诊断子会话 sessionId 写入日志与 `compaction/end` error
|
|
14
|
+
- **失败诊断落盘**:摘要最终失败(含 signal 中止)时,把每次尝试的完整提示词与模型原始输出原样落盘为一个 one-shot 诊断子会话(`subagent/descriptor` 标记、以 subagent 形式出现在宿主子代理列表中;内容零加工、无额外消息),sessionId 随失败结果进主会话日志与 `compaction/end` error 载荷
|
|
14
15
|
- **降级容错**:挂载失败类问题(systemPrompt 服务缺失、tokenMeter 服务异常)不阻塞压缩——systemPrompt 按 0 计、tokenMeter 计价按 0 计或跳过观察;问题始终 `console.warn` 输出到宿主进程外部,并写入 log-only `om/warning` 会话事件(同会话同一问题至多一条)。系统提示词/工具定义估算的普通运行时报错仅记日志,同样按 0 计
|
|
15
16
|
- **recall 工具**:按完整消息 index 区间回看原始会话(含被压缩内容;命中消息中的图片附件随结果保留)
|
|
16
17
|
- **recall-semantic 工具**:本地嵌入模型(paraphrase-multilingual-MiniLM-L12-v2)按语义检索全部完整消息(只匹配文本,纯图片消息不进候选池)
|
|
@@ -60,7 +61,7 @@ preset-agent 自带 `compaction-basic` 压缩,也会压缩上下文,其压
|
|
|
60
61
|
| `reflectThresholdTokens` | `120000` | 反思阈值(tokens):全部 `<history>` 块 token 合计 ≥ 该值时触发合并 |
|
|
61
62
|
| `compressMaxTokens` | 不设置 | 单次摘要生成上限(不设置时由模型适配器默认值决定) |
|
|
62
63
|
| `rateLimitWaitMs` | `60000` | 遇 429 限流后下一次摘要请求前的等待毫秒数(全局冷却期;`0` 不限流) |
|
|
63
|
-
| `tailMessageCount` | `5` |
|
|
64
|
+
| `tailMessageCount` | `5` | 观察触发后延迟执行的等待完整消息条数(新增完整消息数达到该值才执行压缩;`0` 表示触发当轮立即执行) |
|
|
64
65
|
| `compressRetryCount` | `5` | 摘要失败后的最大重试次数(不含首次) |
|
|
65
66
|
| `modelDir` | 共享目录 | recall-semantic 嵌入模型目录(默认 `$DSH_HOME/plugin-data/dsh-plugin-om/models/<id>`,onnx 缺失且启用语义召回时运行时自动下载) |
|
|
66
67
|
| `omEnabled` | `true` | 是否启用自动压缩(`false` 时关闭,recall 工具不受影响) |
|
|
@@ -70,6 +71,8 @@ preset-agent 自带 `compaction-basic` 压缩,也会压缩上下文,其压
|
|
|
70
71
|
|
|
71
72
|
> 不建议把观察阈值设置得过高:越早压缩收益越高,且机制依赖模型对消息计数,过多消息会导致历史混乱。
|
|
72
73
|
|
|
74
|
+
> 想直观理解机制并估算不同参数下的 token 成本,可打开交互式[机制说明与成本计算器](https://fanethedivine.github.io/dsh-plugin-om/)(部署在 GitHub Pages,不随插件包分发):右侧参数侧边栏(滑块 + 数字输入联动)+ 居中的合并单元格成本表(每格显示 om 关闭红 / om 开启绿),可调节系统提示词、dsh 注入消息、阈值、压缩比与三类 token 价格,对比 20k–250k 原始会话规模下启用 om 的 token 消耗量与费用。
|
|
75
|
+
|
|
73
76
|
## npm 命令
|
|
74
77
|
|
|
75
78
|
| 命令 | 作用 |
|
|
@@ -102,6 +105,7 @@ src/
|
|
|
102
105
|
├── embedding.ts # 本地 ONNX 嵌入(懒加载 / 批量 / 运行时按需下载编排)
|
|
103
106
|
├── model-download.ts # 模型下载原语(URL / 跳过判定 / 原子落盘)
|
|
104
107
|
├── summarize.ts # 共享压缩提示词 + <history> 块渲染与输出校验 + 摘要调用
|
|
108
|
+
├── compaction-log.ts # 压缩失败诊断落盘(诊断子会话创建 + descriptor + 逐尝试原样消息组)
|
|
105
109
|
├── compress.ts # 两级自动压缩(观察/反思)、失败中断传播与 compaction 生命周期事件
|
|
106
110
|
└── client/ # 浏览器客户端 bundle(压缩卡片)
|
|
107
111
|
├── index.ts # 客户端入口:注册卡片定义与渲染器
|
|
@@ -112,6 +116,10 @@ src/
|
|
|
112
116
|
└── locales.ts # om-compaction 文案字典(zh/en)
|
|
113
117
|
models/ # 嵌入模型目录(小文件随包分发;onnx 运行时按需下载,不进 git)
|
|
114
118
|
scripts/ # release-archive.mjs(CHANGELOG 归档)/ download-model.mjs(预下载 CLI)
|
|
115
|
-
tests/ # vitest 测试(服务端各模块 + tests/client/ 客户端卡片 + 整条链路集成测试)
|
|
119
|
+
tests/ # vitest 测试(服务端各模块 + tests/client/ 客户端卡片 + tests/web/ 成本模型 + 整条链路集成测试)
|
|
120
|
+
web/ # 机制说明与成本计算器站点(独立 Vite + React + Tailwind CSS + shadcn/ui 工程,发布到 GitHub Pages,不随插件包分发)
|
|
121
|
+
├── src/model.ts # 成本模型纯函数(om 开/关全会话模拟与三类 token 计价)
|
|
122
|
+
└── src/components/ # 机制简述(观察/反思/dsh注入) / 侧边栏参数面板(滑块+input) / 合并单元格成本表 / shadcn/ui 原语
|
|
123
|
+
.github/workflows/web-deploy.yml # web/ 变更合入 main 时构建并部署 GitHub Pages
|
|
116
124
|
```
|
|
117
125
|
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 压缩失败诊断落盘:摘要 run 最终失败时,把每次尝试的完整提示词与模型原始输出
|
|
3
|
+
* 原样落盘为一个 one-shot 诊断子会话(header origin 'subagent' + 首事件
|
|
4
|
+
* subagent/descriptor),使其以 subagent 形式出现在宿主子代理列表中,便于查看
|
|
5
|
+
* 失败调用的完整会话。导出 recordCompactionFailure / SummaryAttemptRecord /
|
|
6
|
+
* compactionLogLabel / COMPACTION_LOG_PROVIDER。
|
|
7
|
+
*
|
|
8
|
+
* - 子会话内容零加工:每次尝试一对 user/message(实际提示词全文,含 <history> 块)
|
|
9
|
+
* + assistant/message(模型原始输出全文,异常/中止时为已收集的部分输出),
|
|
10
|
+
* 不插入任何额外消息;失败原因不进子会话,走主会话日志与 compaction/end error 载荷
|
|
11
|
+
* - 失败原因与诊断子会话 sessionId 由调用方写入主会话日志(compress.ts / index.ts)
|
|
12
|
+
* - 落盘自身绝不抛错:任何失败仅 logger.warn 并返回 undefined,不影响压缩失败流程
|
|
13
|
+
*/
|
|
14
|
+
import type { Context, Session } from './types.ts';
|
|
15
|
+
import { type RoutedTarget } from './utils.ts';
|
|
16
|
+
/** 诊断子会话的 descriptor provider(宿主子代理列表识别用)。 */
|
|
17
|
+
export declare const COMPACTION_LOG_PROVIDER = "om-compaction-log";
|
|
18
|
+
/** 一次失败摘要尝试的完整记录:prompt=实际提示词全文(含 <history> 块),rawOutput=模型原始输出全文。 */
|
|
19
|
+
export type SummaryAttemptRecord = {
|
|
20
|
+
prompt: string;
|
|
21
|
+
rawOutput: string;
|
|
22
|
+
};
|
|
23
|
+
/** 诊断子会话 label:含压缩阶段与尝试次数。 */
|
|
24
|
+
export declare function compactionLogLabel(phase: 'observe' | 'reflect' | undefined, attemptCount: number): string;
|
|
25
|
+
/**
|
|
26
|
+
* 把一次最终失败的摘要 run 落盘为诊断子会话:ctx.sessions.create 创建子会话
|
|
27
|
+
* (header origin 'subagent'、parentSession 指向主会话、delegationDepth = 父 + 1、
|
|
28
|
+
* cwd 继承主会话),追加 one-shot descriptor(provider om-compaction-log,label 含
|
|
29
|
+
* 压缩阶段与尝试次数),逐尝试原样追加「提示词 + 原始输出」消息组,flush 持久化
|
|
30
|
+
* 检查点,返回子会话 id。落盘自身绝不抛错:任何失败仅 logger.warn 并返回
|
|
31
|
+
* undefined(不影响压缩失败流程)。
|
|
32
|
+
*/
|
|
33
|
+
export declare function recordCompactionFailure(ctx: Context, parentSession: Session, options: {
|
|
34
|
+
/** 压缩 pass(诊断子会话 label 用)。 */
|
|
35
|
+
phase: 'observe' | 'reflect' | undefined;
|
|
36
|
+
/** 摘要调用的路由目标(assistant/message 的 model 来源标记)。 */
|
|
37
|
+
target: RoutedTarget;
|
|
38
|
+
/** 逐尝试的完整记录(提示词 + 原始输出;中止在首次请求前时为空)。 */
|
|
39
|
+
attempts: readonly SummaryAttemptRecord[];
|
|
40
|
+
/** 插件 debug 开关(落盘失败的 warn 是否带步骤细节)。 */
|
|
41
|
+
debug: boolean;
|
|
42
|
+
}): Promise<string | undefined>;
|
|
43
|
+
//# sourceMappingURL=compaction-log.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compaction-log.d.ts","sourceRoot":"","sources":["../src/compaction-log.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAOH,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,sEAAsE;AACtE,MAAM,MAAM,oBAAoB,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AASzE,8BAA8B;AAC9B,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,EACxC,YAAY,EAAE,MAAM,GACnB,MAAM,CAER;AA8BD;;;;;;;GAOG;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,wCAAwC;IACxC,QAAQ,EAAE,SAAS,oBAAoB,EAAE,CAAC;IAC1C,uCAAuC;IACvC,KAAK,EAAE,OAAO,CAAC;CAChB,GACA,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAmC7B"}
|
package/dist/compress.d.ts
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import type { Agent, Context, PluginConfig, Session } from './types.ts';
|
|
2
2
|
import { type RoutedTarget } from './utils.ts';
|
|
3
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* 压缩 pass 结果:failed=false 表示无需中断(成功、跳过或非摘要耗尽的局部失败);
|
|
5
|
+
* failed=true 携带最后一次尝试的实际报错、是否因 signal 中止与诊断子会话 id
|
|
6
|
+
* (最终失败时每次尝试的完整提示词与模型原始输出落盘为诊断子会话;落盘失败时缺失)。
|
|
7
|
+
*/
|
|
4
8
|
export type CompressPassResult = {
|
|
5
9
|
failed: false;
|
|
6
10
|
} | {
|
|
7
11
|
failed: true;
|
|
8
12
|
error: string;
|
|
9
13
|
aborted: boolean;
|
|
14
|
+
diagnosticSessionId?: string;
|
|
10
15
|
};
|
|
11
16
|
/** 历史文本 token 估算:4 字符 ≈ 1 token(与宿主 dsh-token-meter 启发式一致)。 */
|
|
12
17
|
export declare function estimateTextTokens(text: string): number;
|
|
@@ -16,11 +21,12 @@ export declare function estimateTextTokens(text: string): number;
|
|
|
16
21
|
*/
|
|
17
22
|
export declare function isPairBalancedAfter(session: Session, seq: number): boolean;
|
|
18
23
|
/**
|
|
19
|
-
* 观察压缩区间:压缩边界后的首个表层节点 →
|
|
20
|
-
*
|
|
21
|
-
*
|
|
24
|
+
* 观察压缩区间:压缩边界后的首个表层节点 → 触发点完整消息(endMessageIndex)对应的
|
|
25
|
+
* 表层终点(取该完整消息最后一个事件 seq 在表层中的位置);区间终点回退到
|
|
26
|
+
* tool-call/result 配对平衡点(不切段)。触发点完整消息不存在或其事件已不在表层
|
|
27
|
+
* (被后续压缩遮蔽)时返回 undefined。返回区间起止表层 seq 与被遮蔽 seq 列表。
|
|
22
28
|
*/
|
|
23
|
-
export declare function computeCompressRange(session: Session,
|
|
29
|
+
export declare function computeCompressRange(session: Session, endMessageIndex: number): {
|
|
24
30
|
start: number;
|
|
25
31
|
end: number;
|
|
26
32
|
shadowedSeqs: number[];
|
|
@@ -38,6 +44,16 @@ export declare function historySection(session: Session): {
|
|
|
38
44
|
}>;
|
|
39
45
|
boundarySeq: number | undefined;
|
|
40
46
|
};
|
|
47
|
+
/**
|
|
48
|
+
* 查找当前活跃的观察压缩待定标记:按日志顺序取最后一条 om/observe-pending,其后须无
|
|
49
|
+
* 引用它的 om/observe-invalidate(已失效),且其后的压缩边界 seq 不大于标记 seq(边界
|
|
50
|
+
* 后移说明标记期间已发生过压缩,标记过期——兜底「执行成功但失效标记未写出」的崩溃
|
|
51
|
+
* 窗口)。无活跃标记返回 undefined。
|
|
52
|
+
*/
|
|
53
|
+
export declare function findObservePending(session: Session): {
|
|
54
|
+
seq: number;
|
|
55
|
+
triggerMessageIndex: number;
|
|
56
|
+
} | undefined;
|
|
41
57
|
/**
|
|
42
58
|
* 反思:全部 <history> 块 token 合计 ≥ reflectThresholdTokens 时,摘要调用把整个块
|
|
43
59
|
* 区段合并替换为一条更紧凑的摘要。失败不产生部分替换;摘要尝试全部耗尽返回
|
|
@@ -45,12 +61,16 @@ export declare function historySection(session: Session): {
|
|
|
45
61
|
*/
|
|
46
62
|
export declare function reflectPass(ctx: Context, agent: Agent, config: Readonly<PluginConfig>, target: RoutedTarget, signal?: AbortSignal): Promise<CompressPassResult>;
|
|
47
63
|
/**
|
|
48
|
-
*
|
|
49
|
-
* token 估算 − 工具定义 token
|
|
50
|
-
*
|
|
51
|
-
*
|
|
64
|
+
* 观察(触发 → 待定 → 延迟执行):无活跃待定标记时测净压力 tokens(上下文压力 − 已压缩
|
|
65
|
+
* <history> 块 token 合计 − 系统提示词 token 估算 − 工具定义 token 估算),首次 ≥
|
|
66
|
+
* observeThresholdTokens 时记录待定标记(触发点 = 当时的最后一条完整消息 index),本次
|
|
67
|
+
* 不压缩(tailMessageCount=0 当轮直接执行,不落待定标记);已有待定标记时按新增完整
|
|
68
|
+
* 消息数 ≥ tailMessageCount 决定执行,压缩区间截至触发点(新增消息成为新未压缩尾部,
|
|
69
|
+
* 延迟窗口内压力允许短暂超阈值)。执行成功(或无可行区间)后写待定失效标记;摘要
|
|
70
|
+
* 失败保留待定,下个 pre-step 直接重试执行。摘要尝试全部耗尽返回失败结果
|
|
71
|
+
* (error = 最后一次尝试的实际报错/具体问题)。
|
|
52
72
|
*/
|
|
53
|
-
export declare function observePass(ctx: Context, agent: Agent, config: Readonly<PluginConfig>,
|
|
73
|
+
export declare function observePass(ctx: Context, agent: Agent, config: Readonly<PluginConfig>, waitCount: number, target: RoutedTarget, signal?: AbortSignal): Promise<CompressPassResult>;
|
|
54
74
|
/**
|
|
55
75
|
* 压力检查 + 两级压缩入口:先反思后观察,pre-step 阻塞串行执行;仅主会话生效。
|
|
56
76
|
* 反思摘要耗尽失败时直接返回失败结果(观察无需继续,本轮将被拒绝);观察失败同样
|
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":"AAuCA,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;AA4CD;;;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,CAmB1D;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/config.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export type PluginConfig = {
|
|
|
8
8
|
compressMaxTokens: number | undefined;
|
|
9
9
|
/** 遇 429 限流后下一次摘要请求前的等待毫秒数(全局冷却期)。 */
|
|
10
10
|
rateLimitWaitMs: number;
|
|
11
|
-
/**
|
|
11
|
+
/** 观察触发后延迟执行的等待完整消息条数(新增完整消息数达到该值才执行压缩;0 表示触发当轮立即执行)。 */
|
|
12
12
|
tailMessageCount: number;
|
|
13
13
|
/** 摘要失败后的最大重试次数(不含首次)。 */
|
|
14
14
|
compressRetryCount: number;
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAQA,kCAAkC;AAClC,MAAM,MAAM,YAAY,GAAG;IACzB,oCAAoC;IACpC,sBAAsB,EAAE,MAAM,CAAC;IAC/B,wDAAwD;IACxD,sBAAsB,EAAE,MAAM,CAAC;IAC/B,2DAA2D;IAC3D,iBAAiB,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,sCAAsC;IACtC,eAAe,EAAE,MAAM,CAAC;IACxB,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAQA,kCAAkC;AAClC,MAAM,MAAM,YAAY,GAAG;IACzB,oCAAoC;IACpC,sBAAsB,EAAE,MAAM,CAAC;IAC/B,wDAAwD;IACxD,sBAAsB,EAAE,MAAM,CAAC;IAC/B,2DAA2D;IAC3D,iBAAiB,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,sCAAsC;IACtC,eAAe,EAAE,MAAM,CAAC;IACxB,yDAAyD;IACzD,gBAAgB,EAAE,MAAM,CAAC;IACzB,0BAA0B;IAC1B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,uBAAuB;IACvB,SAAS,EAAE,OAAO,CAAC;IACnB,iDAAiD;IACjD,KAAK,EAAE,OAAO,CAAC;IACf,sBAAsB;IACtB,aAAa,EAAE,OAAO,CAAC;IACvB,+CAA+C;IAC/C,qBAAqB,EAAE,OAAO,CAAC;IAC/B,kBAAkB;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,iEAAiE;AACjE,eAAO,MAAM,cAAc,EAAE,QAAQ,CAAC,YAAY,CAYhD,CAAC;AAqCH,wCAAwC;AACxC,wBAAgB,aAAa,CAAC,GAAG,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC,YAAY,CAAC,CAoBnE"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAG1C,6BAA6B;AAC7B,eAAO,MAAM,IAAI,kBAAkB,CAAC;AAEpC,wDAAwD;AACxD,eAAO,MAAM,MAAM,UAA6C,CAAC;AAEjE,yCAAyC;AACzC,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,CAwD1D"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { scopeOf } from "@deepseek-ai/dsh-scope";
|
|
2
2
|
import { renderPrompt } from "@deepseek-ai/dsh-system-prompt";
|
|
3
|
+
import { SessionId } from "@deepseek-ai/dsh-session";
|
|
4
|
+
import { SUBAGENT_DESCRIPTOR_VERSION } from "@deepseek-ai/dsh-subagent";
|
|
3
5
|
import { copyFileSync, existsSync, mkdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
4
6
|
import { homedir } from "node:os";
|
|
5
7
|
import path from "node:path";
|
|
@@ -155,6 +157,11 @@ function routedTarget(session) {
|
|
|
155
157
|
* assistant(模型输出文本)、toolcall(单个工具调用及其结果,result 按 callId 匹配并入)。
|
|
156
158
|
* index 从 0 起、按日志顺序递增、只追加不重排(压缩后旧摘要条目引用的 index 仍然有效)。
|
|
157
159
|
*/
|
|
160
|
+
/** 查找 seq 在表层节点序列中的下标(不在则返回 -1)。 */
|
|
161
|
+
function surfaceIndexOf(nodes, seq) {
|
|
162
|
+
for (let i = 0; i < nodes.length; i += 1) if (nodes[i] === seq) return i;
|
|
163
|
+
return -1;
|
|
164
|
+
}
|
|
158
165
|
/**
|
|
159
166
|
* 完整消息索引:按日志顺序把消息事件折叠为完整消息序列(四类,见文件头)。
|
|
160
167
|
* 工具调用结果按 source.callId 匹配其 tool-call 并入该条;未匹配的 result 独立成条(防御)。
|
|
@@ -7427,7 +7434,7 @@ var require_dom_parser = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
7427
7434
|
exports.onWarningStopParsing = onWarningStopParsing;
|
|
7428
7435
|
}));
|
|
7429
7436
|
//#endregion
|
|
7430
|
-
//#region src/
|
|
7437
|
+
//#region src/compaction-log.ts
|
|
7431
7438
|
var import_lib = (/* @__PURE__ */ __commonJSMin(((exports) => {
|
|
7432
7439
|
var conventions = require_conventions();
|
|
7433
7440
|
exports.assign = conventions.assign;
|
|
@@ -7467,6 +7474,96 @@ var import_lib = (/* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
7467
7474
|
exports.onErrorStopParsing = domParser.onErrorStopParsing;
|
|
7468
7475
|
exports.onWarningStopParsing = domParser.onWarningStopParsing;
|
|
7469
7476
|
})))();
|
|
7477
|
+
/** 诊断子会话的 descriptor provider(宿主子代理列表识别用)。 */
|
|
7478
|
+
const COMPACTION_LOG_PROVIDER = "om-compaction-log";
|
|
7479
|
+
/** 压缩 pass 的中文标签(诊断子会话 label 用;未知阶段回落「压缩」)。 */
|
|
7480
|
+
function phaseLabel(phase) {
|
|
7481
|
+
if (phase === "observe") return "观察";
|
|
7482
|
+
if (phase === "reflect") return "反思";
|
|
7483
|
+
return "压缩";
|
|
7484
|
+
}
|
|
7485
|
+
/** 诊断子会话 label:含压缩阶段与尝试次数。 */
|
|
7486
|
+
function compactionLogLabel(phase, attemptCount) {
|
|
7487
|
+
return `OM 压缩失败日志(${phaseLabel(phase)} · ${attemptCount} 次尝试)`;
|
|
7488
|
+
}
|
|
7489
|
+
/** 追加一次尝试的「提示词 → 原始输出」消息组(surfaceOp append;id 为品牌类型,session.append 运行时校验)。 */
|
|
7490
|
+
function appendAttemptMessages(child, attempt, step, target) {
|
|
7491
|
+
const userMessage = {
|
|
7492
|
+
id: uuid(),
|
|
7493
|
+
role: "user",
|
|
7494
|
+
content: [{
|
|
7495
|
+
type: "text",
|
|
7496
|
+
text: attempt.prompt
|
|
7497
|
+
}],
|
|
7498
|
+
source: {
|
|
7499
|
+
kind: "plugin",
|
|
7500
|
+
plugin: PLUGIN_LABEL
|
|
7501
|
+
}
|
|
7502
|
+
};
|
|
7503
|
+
child.append("user/message", userMessage, { surfaceOp: "append" });
|
|
7504
|
+
const assistantMessage = {
|
|
7505
|
+
id: uuid(),
|
|
7506
|
+
role: "assistant",
|
|
7507
|
+
content: [{
|
|
7508
|
+
type: "text",
|
|
7509
|
+
text: attempt.rawOutput
|
|
7510
|
+
}],
|
|
7511
|
+
source: {
|
|
7512
|
+
kind: "model",
|
|
7513
|
+
provider: target.provider,
|
|
7514
|
+
model: target.model
|
|
7515
|
+
}
|
|
7516
|
+
};
|
|
7517
|
+
child.append("assistant/message", {
|
|
7518
|
+
turn: 0,
|
|
7519
|
+
step,
|
|
7520
|
+
message: assistantMessage
|
|
7521
|
+
}, { surfaceOp: "append" });
|
|
7522
|
+
}
|
|
7523
|
+
/**
|
|
7524
|
+
* 把一次最终失败的摘要 run 落盘为诊断子会话:ctx.sessions.create 创建子会话
|
|
7525
|
+
* (header origin 'subagent'、parentSession 指向主会话、delegationDepth = 父 + 1、
|
|
7526
|
+
* cwd 继承主会话),追加 one-shot descriptor(provider om-compaction-log,label 含
|
|
7527
|
+
* 压缩阶段与尝试次数),逐尝试原样追加「提示词 + 原始输出」消息组,flush 持久化
|
|
7528
|
+
* 检查点,返回子会话 id。落盘自身绝不抛错:任何失败仅 logger.warn 并返回
|
|
7529
|
+
* undefined(不影响压缩失败流程)。
|
|
7530
|
+
*/
|
|
7531
|
+
async function recordCompactionFailure(ctx, parentSession, options) {
|
|
7532
|
+
const logger = makeLogger(ctx, options.debug);
|
|
7533
|
+
try {
|
|
7534
|
+
const header = parentSession.header;
|
|
7535
|
+
const child = ctx.sessions.create(SessionId(`om-compaction-log-${uuid()}`), { meta: {
|
|
7536
|
+
...header.cwd === void 0 ? {} : { cwd: header.cwd },
|
|
7537
|
+
parentSession: parentSession.id,
|
|
7538
|
+
origin: "subagent",
|
|
7539
|
+
delegationDepth: (header.delegationDepth ?? 0) + 1
|
|
7540
|
+
} });
|
|
7541
|
+
child.append("subagent/descriptor", {
|
|
7542
|
+
version: SUBAGENT_DESCRIPTOR_VERSION,
|
|
7543
|
+
mode: "one-shot",
|
|
7544
|
+
provider: COMPACTION_LOG_PROVIDER,
|
|
7545
|
+
label: compactionLogLabel(options.phase, options.attempts.length)
|
|
7546
|
+
});
|
|
7547
|
+
for (let i = 0; i < options.attempts.length; i += 1) {
|
|
7548
|
+
const attempt = options.attempts[i];
|
|
7549
|
+
if (attempt === void 0) continue;
|
|
7550
|
+
appendAttemptMessages(child, attempt, i + 1, options.target);
|
|
7551
|
+
}
|
|
7552
|
+
try {
|
|
7553
|
+
await ctx.sessions.flush(child);
|
|
7554
|
+
} catch (error) {
|
|
7555
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
7556
|
+
logger.warn(`压缩失败诊断子会话 flush 失败(子会话 ${child.id} 已创建): ${message}`);
|
|
7557
|
+
}
|
|
7558
|
+
return child.id;
|
|
7559
|
+
} catch (error) {
|
|
7560
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
7561
|
+
logger.warn(`压缩失败诊断子会话落盘失败: ${message}`);
|
|
7562
|
+
return;
|
|
7563
|
+
}
|
|
7564
|
+
}
|
|
7565
|
+
//#endregion
|
|
7566
|
+
//#region src/rate-limit.ts
|
|
7470
7567
|
/**
|
|
7471
7568
|
* 全局限流门(插件进程级共享状态):任一摘要请求遇 429 后进入冷却期,
|
|
7472
7569
|
* 此后所有摘要请求发出前先等待到「最近一次 429 + rateLimitWaitMs」之后。
|
|
@@ -7542,7 +7639,7 @@ function buildHistoryPrompt() {
|
|
|
7542
7639
|
"- <reasoning> 只作参考,输出产物中不包含 <reasoning> 块。",
|
|
7543
7640
|
"- 将具有关联性的 <assistant> 消息按内在逻辑连贯性划分为连续模块,聚合为 <assistant start=\"\" end=\"\"> 块:块内描述模块的目的、行为与结果;涉及的具体文件保留在模块内容中,多个前缀相同的路径合并简写。",
|
|
7544
7641
|
"- 单条重要的完整消息以 <assistant index=\"\"> 单独呈现,内容不受限制。",
|
|
7545
|
-
"- 加载的 skill
|
|
7642
|
+
"- 加载的 skill 属于**关键信息**:应当产出独立块且不过多省略。",
|
|
7546
7643
|
"- 条目按 index 顺序覆盖本次压缩的全部完整消息:index/start/end 必须连续(区间内 index 连续、相邻条目相接),不跳号、不重叠、不遗漏。",
|
|
7547
7644
|
"",
|
|
7548
7645
|
"【摘要粒度】",
|
|
@@ -7936,38 +8033,55 @@ function extractSummaryDetailed(raw, expected) {
|
|
|
7936
8033
|
* 直连 LLM 执行一次摘要(观察或反思),返回文本与可选 token usage。
|
|
7937
8034
|
* 失败(抛异常 / 空输出 / 非 stop 结束 / 校验不通过)均记录日志并重试,每次尝试的
|
|
7938
8035
|
* 结果或报错始终写入日志(成功 info / 失败 warn,不受 debug 影响);全部尝试耗尽
|
|
7939
|
-
*
|
|
7940
|
-
*
|
|
7941
|
-
*
|
|
8036
|
+
* 返回失败结果(携带最后一次尝试的实际报错/具体问题)。最终失败(耗尽或 signal
|
|
8037
|
+
* 中止)时把每次尝试的完整提示词与模型原始输出原样落盘为诊断子会话(phase 标注
|
|
8038
|
+
* 观察或反思),诊断子会话 id 随失败结果返回。signal 中止(含限流等待被中止)
|
|
8039
|
+
* 立即放弃并标记 aborted。每次请求发出前先过全局限流等待门。
|
|
7942
8040
|
*/
|
|
7943
8041
|
async function runSummarySubagent(ctx, agent, instruction, contextText, maxTokens, target, debug, signal, options) {
|
|
7944
8042
|
const session = agent.session;
|
|
7945
8043
|
const logger = makeLogger(ctx, debug);
|
|
7946
8044
|
const maxAttempts = options?.maxAttempts ?? 11;
|
|
7947
8045
|
let lastFailure = {};
|
|
8046
|
+
/** 逐尝试的完整记录(提示词 + 原始输出原样收集,仅最终失败时落盘)。 */
|
|
8047
|
+
const attempts = [];
|
|
8048
|
+
/** 最终失败的统一出口:落盘诊断子会话并携带其 id 返回。 */
|
|
8049
|
+
const finishFailure = async (error, aborted) => {
|
|
8050
|
+
const diagnosticSessionId = await recordCompactionFailure(ctx, session, {
|
|
8051
|
+
phase: options?.phase,
|
|
8052
|
+
target,
|
|
8053
|
+
attempts,
|
|
8054
|
+
debug
|
|
8055
|
+
});
|
|
8056
|
+
return {
|
|
8057
|
+
ok: false,
|
|
8058
|
+
error,
|
|
8059
|
+
aborted,
|
|
8060
|
+
...diagnosticSessionId === void 0 ? {} : { diagnosticSessionId }
|
|
8061
|
+
};
|
|
8062
|
+
};
|
|
7948
8063
|
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
7949
8064
|
if (signal?.aborted) {
|
|
7950
8065
|
logger.warn(`摘要调用中止(第 ${attempt}/${maxAttempts} 次尝试前 signal 已中止),放弃本次压缩`);
|
|
7951
|
-
return
|
|
7952
|
-
ok: false,
|
|
7953
|
-
error: COMPACTION_ABORTED_ERROR,
|
|
7954
|
-
aborted: true
|
|
7955
|
-
};
|
|
8066
|
+
return await finishFailure(COMPACTION_ABORTED_ERROR, true);
|
|
7956
8067
|
}
|
|
7957
8068
|
const rateLimitWaitMs = options?.rateLimitWaitMs ?? 6e4;
|
|
7958
8069
|
if (!await gateRateLimit(rateLimitWaitMs, signal)) {
|
|
7959
8070
|
logger.warn(`摘要调用中止(第 ${attempt}/${maxAttempts} 次尝试前限流等待被 signal 中止),放弃本次压缩`);
|
|
7960
|
-
return
|
|
7961
|
-
ok: false,
|
|
7962
|
-
error: COMPACTION_ABORTED_ERROR,
|
|
7963
|
-
aborted: true
|
|
7964
|
-
};
|
|
8071
|
+
return await finishFailure(COMPACTION_ABORTED_ERROR, true);
|
|
7965
8072
|
}
|
|
7966
8073
|
logger.step(`摘要调用开始(第 ${attempt}/${maxAttempts} 次,provider ${target.provider},model ${target.model},maxTokens ${maxTokens === void 0 ? "未设置" : String(maxTokens)})`);
|
|
8074
|
+
const prompt = `${instruction}\n\n${contextText ?? ""}`;
|
|
8075
|
+
const collector = new StreamCollector();
|
|
8076
|
+
let streamCompleted = false;
|
|
7967
8077
|
try {
|
|
7968
8078
|
const requestOptions = buildSummaryOptions(session, instruction, contextText, maxTokens, target, signal);
|
|
7969
|
-
const collector = new StreamCollector();
|
|
7970
8079
|
for await (const chunk of ctx.llm.stream(requestOptions)) collector.push(chunk);
|
|
8080
|
+
streamCompleted = true;
|
|
8081
|
+
attempts.push({
|
|
8082
|
+
prompt,
|
|
8083
|
+
rawOutput: collector.text
|
|
8084
|
+
});
|
|
7971
8085
|
const extracted = extractSummaryDetailed(collector.text, options?.expected);
|
|
7972
8086
|
const finish = collector.finish;
|
|
7973
8087
|
if (finish.kind !== "stop") {
|
|
@@ -7990,6 +8104,10 @@ async function runSummarySubagent(ctx, agent, instruction, contextText, maxToken
|
|
|
7990
8104
|
...usage === void 0 ? {} : { usage }
|
|
7991
8105
|
};
|
|
7992
8106
|
} catch (error) {
|
|
8107
|
+
if (!streamCompleted) attempts.push({
|
|
8108
|
+
prompt,
|
|
8109
|
+
rawOutput: collector.text
|
|
8110
|
+
});
|
|
7993
8111
|
const message = error instanceof Error ? error.message : String(error);
|
|
7994
8112
|
if (isRateLimitError(message)) {
|
|
7995
8113
|
noteRateLimit();
|
|
@@ -8001,29 +8119,30 @@ async function runSummarySubagent(ctx, agent, instruction, contextText, maxToken
|
|
|
8001
8119
|
}
|
|
8002
8120
|
const lastError = lastFailure.error ?? lastFailure.reason ?? "未知原因";
|
|
8003
8121
|
logger.warn(`摘要调用最终失败(已尝试 ${maxAttempts} 次,最后错误:${lastError}),拒绝放行本轮 step`);
|
|
8004
|
-
return
|
|
8005
|
-
ok: false,
|
|
8006
|
-
error: lastError,
|
|
8007
|
-
aborted: false
|
|
8008
|
-
};
|
|
8122
|
+
return await finishFailure(lastError, false);
|
|
8009
8123
|
}
|
|
8010
8124
|
//#endregion
|
|
8011
8125
|
//#region src/compress.ts
|
|
8012
8126
|
/**
|
|
8013
8127
|
* 两级自动压缩(观察/反思)与 compaction 生命周期提交。
|
|
8014
8128
|
* 导出 estimateTextTokens / isPairBalancedAfter / computeCompressRange / historySection /
|
|
8015
|
-
* reflectPass / observePass / maybeCompress。
|
|
8129
|
+
* findObservePending / reflectPass / observePass / maybeCompress。
|
|
8016
8130
|
*
|
|
8017
8131
|
* - 反思:全部 <history> 块 token 合计 ≥ reflectThresholdTokens 时,摘要合并为一条
|
|
8018
|
-
* -
|
|
8019
|
-
* token
|
|
8020
|
-
*
|
|
8132
|
+
* - 观察(触发 → 待定 → 延迟执行):净压力(上下文压力 − 已压缩块 token 合计 − 系统提示词
|
|
8133
|
+
* token 估算 − 工具定义 token 估算)首次 ≥ observeThresholdTokens 时记录待定标记
|
|
8134
|
+
* (触发点 = 当时的最后一条完整消息 index),本次不压缩;待定后新增完整消息数 ≥
|
|
8135
|
+
* tailMessageCount 时,把压缩边界至触发点的全部消息摘要为新 <history> 块并精确替换
|
|
8136
|
+
* 被压缩区间(旧块保留),等待期间的新消息成为下一轮未压缩尾部(延迟窗口内压力允许
|
|
8137
|
+
* 短暂超阈值);tailMessageCount=0 时触发当轮直接执行(不落待定标记)
|
|
8138
|
+
* - 待定标记以 log-only om/observe-pending / om/observe-invalidate 事件持久化在会话
|
|
8139
|
+
* 日志中(重启后从日志恢复);摘要失败保留待定,下个 pre-step 直接重试执行
|
|
8021
8140
|
* - 两级在 pre-step 阻塞串行执行(先反思后观察);仅主会话生效;omEnabled=false 关闭
|
|
8022
8141
|
* - 压缩边界:最后一个合法 <history> 块之后的消息视为未压缩,其前不重复压缩
|
|
8023
8142
|
* - 摘要尝试全部耗尽时 pass 返回失败结果(携带最后一次尝试的实际报错),压缩流程
|
|
8024
8143
|
* 向上传播,pre-step 据此拒绝本 step 中断当前 turn;signal 中止标记 aborted(不中断)
|
|
8025
8144
|
* - 提交走宿主 compaction/* 生命周期事件(start 带 phase → summary → 替换消息 → end),
|
|
8026
|
-
* 失败补 end(error,实际报错);替换消息 source 标记插件标识供 UI 认领
|
|
8145
|
+
* 失败补 end(error,实际报错 + 诊断子会话 sessionId);替换消息 source 标记插件标识供 UI 认领
|
|
8027
8146
|
* - 挂载失败类问题(systemPrompt/tokenMeter 服务异常)始终 console 到外部进程,并追加
|
|
8028
8147
|
* log-only om/warning 事件(客户端渲染功能降级警告行,每会话同一问题至多一次);
|
|
8029
8148
|
* 辅助估算的普通运行时报错仅记日志。降级与报错都不阻塞压缩(tokenMeter 压力数据
|
|
@@ -8087,17 +8206,26 @@ function isPairBalancedAfter(session, seq) {
|
|
|
8087
8206
|
return false;
|
|
8088
8207
|
}
|
|
8089
8208
|
/**
|
|
8090
|
-
* 观察压缩区间:压缩边界后的首个表层节点 →
|
|
8091
|
-
*
|
|
8092
|
-
*
|
|
8209
|
+
* 观察压缩区间:压缩边界后的首个表层节点 → 触发点完整消息(endMessageIndex)对应的
|
|
8210
|
+
* 表层终点(取该完整消息最后一个事件 seq 在表层中的位置);区间终点回退到
|
|
8211
|
+
* tool-call/result 配对平衡点(不切段)。触发点完整消息不存在或其事件已不在表层
|
|
8212
|
+
* (被后续压缩遮蔽)时返回 undefined。返回区间起止表层 seq 与被遮蔽 seq 列表。
|
|
8093
8213
|
*/
|
|
8094
|
-
function computeCompressRange(session,
|
|
8214
|
+
function computeCompressRange(session, endMessageIndex) {
|
|
8095
8215
|
const surface = [...session.surface.nodes];
|
|
8096
8216
|
if (surface.length === 0) return void 0;
|
|
8097
8217
|
const { boundarySeq } = historySection(session);
|
|
8098
8218
|
const startIdx = boundarySeq === void 0 ? 0 : surface.indexOf(boundarySeq) + 1;
|
|
8099
8219
|
if (startIdx >= surface.length) return void 0;
|
|
8100
|
-
|
|
8220
|
+
const target = indexCompleteMessages(session).find((cm) => cm.index === endMessageIndex);
|
|
8221
|
+
if (target === void 0) return void 0;
|
|
8222
|
+
let endIdx = -1;
|
|
8223
|
+
for (let i = target.seqs.length - 1; i >= 0; i -= 1) {
|
|
8224
|
+
const seq = target.seqs[i];
|
|
8225
|
+
if (seq === void 0) continue;
|
|
8226
|
+
endIdx = surfaceIndexOf(surface, seq);
|
|
8227
|
+
if (endIdx !== -1) break;
|
|
8228
|
+
}
|
|
8101
8229
|
if (endIdx < startIdx) return void 0;
|
|
8102
8230
|
while (endIdx >= startIdx) {
|
|
8103
8231
|
const node = surface[endIdx];
|
|
@@ -8137,6 +8265,42 @@ function historySection(session) {
|
|
|
8137
8265
|
boundarySeq
|
|
8138
8266
|
};
|
|
8139
8267
|
}
|
|
8268
|
+
/**
|
|
8269
|
+
* 查找当前活跃的观察压缩待定标记:按日志顺序取最后一条 om/observe-pending,其后须无
|
|
8270
|
+
* 引用它的 om/observe-invalidate(已失效),且其后的压缩边界 seq 不大于标记 seq(边界
|
|
8271
|
+
* 后移说明标记期间已发生过压缩,标记过期——兜底「执行成功但失效标记未写出」的崩溃
|
|
8272
|
+
* 窗口)。无活跃标记返回 undefined。
|
|
8273
|
+
*/
|
|
8274
|
+
function findObservePending(session) {
|
|
8275
|
+
let pending;
|
|
8276
|
+
for (let seq = 0; seq < session.events.length; seq += 1) {
|
|
8277
|
+
const event = session.events[seq];
|
|
8278
|
+
if (!event) continue;
|
|
8279
|
+
if (event.type === "om/observe-pending") pending = {
|
|
8280
|
+
seq,
|
|
8281
|
+
triggerMessageIndex: event.data.triggerMessageIndex
|
|
8282
|
+
};
|
|
8283
|
+
else if (event.type === "om/observe-invalidate" && pending !== void 0 && event.data.pendingSeq === pending.seq) pending = void 0;
|
|
8284
|
+
}
|
|
8285
|
+
if (pending === void 0) return void 0;
|
|
8286
|
+
const { boundarySeq } = historySection(session);
|
|
8287
|
+
if (boundarySeq !== void 0 && boundarySeq > pending.seq) return void 0;
|
|
8288
|
+
return pending;
|
|
8289
|
+
}
|
|
8290
|
+
/** 追加观察压缩待定标记(log-only):记录触发点完整消息 index,返回事件 seq。 */
|
|
8291
|
+
function appendObservePending(session, triggerMessageIndex) {
|
|
8292
|
+
return session.append("om/observe-pending", {
|
|
8293
|
+
key: "observe",
|
|
8294
|
+
triggerMessageIndex
|
|
8295
|
+
}).seq;
|
|
8296
|
+
}
|
|
8297
|
+
/** 追加观察压缩待定失效标记(log-only):声明指定 pending 已失效,返回事件 seq。 */
|
|
8298
|
+
function appendObserveInvalidate(session, pendingSeq) {
|
|
8299
|
+
return session.append("om/observe-invalidate", {
|
|
8300
|
+
key: "observe",
|
|
8301
|
+
pendingSeq
|
|
8302
|
+
}).seq;
|
|
8303
|
+
}
|
|
8140
8304
|
/** 当前打开中的 turn 号(最近 turn/start 且未被 turn/end 关闭);无则 null。 */
|
|
8141
8305
|
function openTurnOf(session) {
|
|
8142
8306
|
let turn = null;
|
|
@@ -8180,13 +8344,18 @@ function appendCompactionSummary(session, data) {
|
|
|
8180
8344
|
};
|
|
8181
8345
|
return session.append("compaction/summary", payload).seq;
|
|
8182
8346
|
}
|
|
8183
|
-
/**
|
|
8184
|
-
|
|
8185
|
-
|
|
8347
|
+
/**
|
|
8348
|
+
* 追加 compaction/end(log-only,结束生命周期;error 记录失败原因,
|
|
8349
|
+
* diagnosticSessionId 记录最终失败时的诊断子会话 id)。
|
|
8350
|
+
*/
|
|
8351
|
+
function appendCompactionEnd(session, lifecycle, error, diagnosticSessionId) {
|
|
8352
|
+
const payload = {
|
|
8186
8353
|
compactionId: lifecycle.compactionId,
|
|
8187
8354
|
turn: lifecycle.turn,
|
|
8188
|
-
...error === void 0 ? {} : { error }
|
|
8189
|
-
|
|
8355
|
+
...error === void 0 ? {} : { error },
|
|
8356
|
+
...diagnosticSessionId === void 0 ? {} : { diagnosticSessionId }
|
|
8357
|
+
};
|
|
8358
|
+
return session.append("compaction/end", payload).seq;
|
|
8190
8359
|
}
|
|
8191
8360
|
/** 追加 <history> 压缩日志消息(surfaceOp 替换遮蔽区间,source 标记插件自产 + compactionId)。 */
|
|
8192
8361
|
function appendHistoryMessage(session, content, sourceEventSeqs, surfaceOp, compactionId) {
|
|
@@ -8258,17 +8427,19 @@ async function reflectPass(ctx, agent, config, target, signal) {
|
|
|
8258
8427
|
start: 0,
|
|
8259
8428
|
end: expectedEnd
|
|
8260
8429
|
},
|
|
8261
|
-
rateLimitWaitMs: config.rateLimitWaitMs
|
|
8430
|
+
rateLimitWaitMs: config.rateLimitWaitMs,
|
|
8431
|
+
phase: "reflect"
|
|
8262
8432
|
});
|
|
8263
8433
|
if (!summaryResult.ok) {
|
|
8264
|
-
logger.warn(`反思:摘要调用失败(${summaryResult.error}
|
|
8434
|
+
logger.warn(`反思:摘要调用失败(${summaryResult.error}),诊断子会话 ${summaryResult.diagnosticSessionId ?? "未落盘"},追加 compaction/end(error)`);
|
|
8265
8435
|
try {
|
|
8266
|
-
appendCompactionEnd(session, lifecycle, summaryResult.error);
|
|
8436
|
+
appendCompactionEnd(session, lifecycle, summaryResult.error, summaryResult.diagnosticSessionId);
|
|
8267
8437
|
} catch {}
|
|
8268
8438
|
return {
|
|
8269
8439
|
failed: true,
|
|
8270
8440
|
error: summaryResult.error,
|
|
8271
|
-
aborted: summaryResult.aborted
|
|
8441
|
+
aborted: summaryResult.aborted,
|
|
8442
|
+
...summaryResult.diagnosticSessionId === void 0 ? {} : { diagnosticSessionId: summaryResult.diagnosticSessionId }
|
|
8272
8443
|
};
|
|
8273
8444
|
}
|
|
8274
8445
|
const report = summaryResult.text;
|
|
@@ -8367,49 +8538,99 @@ function measurePressureTokens(ctx, session, logger) {
|
|
|
8367
8538
|
}
|
|
8368
8539
|
}
|
|
8369
8540
|
/**
|
|
8370
|
-
*
|
|
8371
|
-
* token 估算 − 工具定义 token
|
|
8372
|
-
*
|
|
8373
|
-
*
|
|
8541
|
+
* 观察(触发 → 待定 → 延迟执行):无活跃待定标记时测净压力 tokens(上下文压力 − 已压缩
|
|
8542
|
+
* <history> 块 token 合计 − 系统提示词 token 估算 − 工具定义 token 估算),首次 ≥
|
|
8543
|
+
* observeThresholdTokens 时记录待定标记(触发点 = 当时的最后一条完整消息 index),本次
|
|
8544
|
+
* 不压缩(tailMessageCount=0 当轮直接执行,不落待定标记);已有待定标记时按新增完整
|
|
8545
|
+
* 消息数 ≥ tailMessageCount 决定执行,压缩区间截至触发点(新增消息成为新未压缩尾部,
|
|
8546
|
+
* 延迟窗口内压力允许短暂超阈值)。执行成功(或无可行区间)后写待定失效标记;摘要
|
|
8547
|
+
* 失败保留待定,下个 pre-step 直接重试执行。摘要尝试全部耗尽返回失败结果
|
|
8548
|
+
* (error = 最后一次尝试的实际报错/具体问题)。
|
|
8374
8549
|
*/
|
|
8375
|
-
async function observePass(ctx, agent, config,
|
|
8550
|
+
async function observePass(ctx, agent, config, waitCount, target, signal) {
|
|
8376
8551
|
const session = agent.session;
|
|
8377
8552
|
const logger = makeLogger(ctx, config.debug);
|
|
8378
|
-
logger.step(`观察检查(观察阈值 ${config.observeThresholdTokens} tokens
|
|
8379
|
-
const threshold = config.observeThresholdTokens;
|
|
8380
|
-
const pressureTokens = measurePressureTokens(ctx, session, logger);
|
|
8381
|
-
if (pressureTokens === void 0) return { failed: false };
|
|
8553
|
+
logger.step(`观察检查(观察阈值 ${config.observeThresholdTokens} tokens,延迟等待 ${waitCount} 条完整消息)`);
|
|
8382
8554
|
const { blocks } = historySection(session);
|
|
8383
|
-
const
|
|
8384
|
-
|
|
8385
|
-
|
|
8386
|
-
|
|
8387
|
-
if (
|
|
8388
|
-
|
|
8389
|
-
|
|
8555
|
+
const pending = findObservePending(session);
|
|
8556
|
+
let triggerMessageIndex;
|
|
8557
|
+
let pendingSeq;
|
|
8558
|
+
let triggerNote;
|
|
8559
|
+
if (pending === void 0) {
|
|
8560
|
+
const threshold = config.observeThresholdTokens;
|
|
8561
|
+
const pressureTokens = measurePressureTokens(ctx, session, logger);
|
|
8562
|
+
if (pressureTokens === void 0) return { failed: false };
|
|
8563
|
+
const historyTokens = blocks.reduce((total, block) => total + estimateTextTokens(block.text), 0);
|
|
8564
|
+
const systemTokens = await estimateSystemPromptTokens(ctx, agent, logger, signal);
|
|
8565
|
+
const toolsTokens = estimateToolsTokens(session, logger);
|
|
8566
|
+
const netTokens = pressureTokens - historyTokens - systemTokens - toolsTokens;
|
|
8567
|
+
if (netTokens < threshold) {
|
|
8568
|
+
logger.step(`观察:净压力 ${netTokens} tokens(上下文压力 ${pressureTokens} − 已压缩块 ${historyTokens} − 系统提示词 ${systemTokens} − 工具定义 ${toolsTokens})< 阈值 ${threshold},跳过`);
|
|
8569
|
+
return { failed: false };
|
|
8570
|
+
}
|
|
8571
|
+
logger.step(`观察:净压力 ${netTokens} tokens(上下文压力 ${pressureTokens} − 已压缩块 ${historyTokens} − 系统提示词 ${systemTokens} − 工具定义 ${toolsTokens})≥ 阈值 ${threshold},触发压缩`);
|
|
8572
|
+
const lastMessageIndex = indexCompleteMessages(session).length - 1;
|
|
8573
|
+
if (lastMessageIndex < 0) {
|
|
8574
|
+
logger.step("观察:会话尚无完整消息,跳过");
|
|
8575
|
+
return { failed: false };
|
|
8576
|
+
}
|
|
8577
|
+
triggerMessageIndex = lastMessageIndex;
|
|
8578
|
+
if (waitCount > 0) {
|
|
8579
|
+
try {
|
|
8580
|
+
pendingSeq = appendObservePending(session, triggerMessageIndex);
|
|
8581
|
+
} catch (error) {
|
|
8582
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
8583
|
+
logger.warn(`观察:待定标记追加失败,本轮跳过(下轮重新评估): ${message}`);
|
|
8584
|
+
return { failed: false };
|
|
8585
|
+
}
|
|
8586
|
+
logger.step(`观察:记录待定标记(触发点完整消息 index ${triggerMessageIndex}),等待 ${waitCount} 条新完整消息后压缩`);
|
|
8587
|
+
return { failed: false };
|
|
8588
|
+
}
|
|
8589
|
+
triggerNote = `触发点完整消息 index ${triggerMessageIndex}`;
|
|
8590
|
+
} else {
|
|
8591
|
+
const arrived = indexCompleteMessages(session).length - 1 - pending.triggerMessageIndex;
|
|
8592
|
+
if (arrived < waitCount) {
|
|
8593
|
+
logger.step(`观察:待定标记等待中(触发点完整消息 index ${pending.triggerMessageIndex},新增 ${arrived}/${waitCount} 条),跳过`);
|
|
8594
|
+
return { failed: false };
|
|
8595
|
+
}
|
|
8596
|
+
logger.step(`观察:待定标记延迟到期(触发点完整消息 index ${pending.triggerMessageIndex},新增 ${arrived} ≥ ${waitCount} 条),执行压缩`);
|
|
8597
|
+
triggerMessageIndex = pending.triggerMessageIndex;
|
|
8598
|
+
pendingSeq = pending.seq;
|
|
8599
|
+
triggerNote = `待定标记触发点完整消息 index ${pending.triggerMessageIndex}`;
|
|
8390
8600
|
}
|
|
8391
|
-
|
|
8392
|
-
|
|
8601
|
+
const clearPending = () => {
|
|
8602
|
+
if (pendingSeq === void 0) return;
|
|
8603
|
+
try {
|
|
8604
|
+
appendObserveInvalidate(session, pendingSeq);
|
|
8605
|
+
} catch (error) {
|
|
8606
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
8607
|
+
logger.warn(`观察:待定失效标记追加失败: ${message}`);
|
|
8608
|
+
}
|
|
8609
|
+
};
|
|
8610
|
+
const range = computeCompressRange(session, triggerMessageIndex);
|
|
8393
8611
|
if (!range) {
|
|
8394
|
-
logger.step("
|
|
8612
|
+
logger.step("观察:无可行压缩区间(边界后无消息、触发点已被压缩或配对无法平衡),清除待定标记视为完成");
|
|
8613
|
+
clearPending();
|
|
8395
8614
|
return { failed: false };
|
|
8396
8615
|
}
|
|
8397
8616
|
logger.step(`观察:压缩区间 [${range.start}..${range.end}],遮蔽 ${range.shadowedSeqs.length} 个表层节点`);
|
|
8398
8617
|
const replaceSeqs = range.shadowedSeqs;
|
|
8399
8618
|
const replaceStart = replaceSeqs[0];
|
|
8400
8619
|
if (replaceStart === void 0) {
|
|
8401
|
-
logger.step("
|
|
8620
|
+
logger.step("观察:区间内无新消息(全部为压缩日志块),清除待定标记视为完成");
|
|
8621
|
+
clearPending();
|
|
8402
8622
|
return { failed: false };
|
|
8403
8623
|
}
|
|
8404
8624
|
const shadowedSet = new Set(replaceSeqs);
|
|
8405
8625
|
const inRangeCms = indexCompleteMessages(session).filter((cm) => cm.seqs.every((seq) => shadowedSet.has(seq)));
|
|
8406
8626
|
if (inRangeCms.length === 0) {
|
|
8407
|
-
logger.step("
|
|
8627
|
+
logger.step("观察:区间内无完整消息,清除待定标记视为完成");
|
|
8628
|
+
clearPending();
|
|
8408
8629
|
return { failed: false };
|
|
8409
8630
|
}
|
|
8410
8631
|
const startIndex = inRangeCms[0]?.index ?? 0;
|
|
8411
8632
|
const endIndex = inRangeCms[inRangeCms.length - 1]?.index ?? startIndex;
|
|
8412
|
-
logger.step(`观察:保留旧块 ${blocks.length}
|
|
8633
|
+
logger.step(`观察:保留旧块 ${blocks.length} 条,替换 [${replaceStart}..${range.end}](${replaceSeqs.length} 个表层节点,压缩至${triggerNote}),新消息 index ${startIndex}..${endIndex}`);
|
|
8413
8634
|
const instruction = buildHistoryPrompt();
|
|
8414
8635
|
const contextText = renderMessages(session, replaceSeqs);
|
|
8415
8636
|
const lifecycle = {
|
|
@@ -8430,17 +8651,19 @@ async function observePass(ctx, agent, config, tailCount, target, signal) {
|
|
|
8430
8651
|
start: startIndex,
|
|
8431
8652
|
end: endIndex
|
|
8432
8653
|
},
|
|
8433
|
-
rateLimitWaitMs: config.rateLimitWaitMs
|
|
8654
|
+
rateLimitWaitMs: config.rateLimitWaitMs,
|
|
8655
|
+
phase: "observe"
|
|
8434
8656
|
});
|
|
8435
8657
|
if (!summaryResult.ok) {
|
|
8436
|
-
logger.warn(`观察:摘要调用失败(${summaryResult.error}
|
|
8658
|
+
logger.warn(`观察:摘要调用失败(${summaryResult.error}),诊断子会话 ${summaryResult.diagnosticSessionId ?? "未落盘"},追加 compaction/end(error)`);
|
|
8437
8659
|
try {
|
|
8438
|
-
appendCompactionEnd(session, lifecycle, summaryResult.error);
|
|
8660
|
+
appendCompactionEnd(session, lifecycle, summaryResult.error, summaryResult.diagnosticSessionId);
|
|
8439
8661
|
} catch {}
|
|
8440
8662
|
return {
|
|
8441
8663
|
failed: true,
|
|
8442
8664
|
error: summaryResult.error,
|
|
8443
|
-
aborted: summaryResult.aborted
|
|
8665
|
+
aborted: summaryResult.aborted,
|
|
8666
|
+
...summaryResult.diagnosticSessionId === void 0 ? {} : { diagnosticSessionId: summaryResult.diagnosticSessionId }
|
|
8444
8667
|
};
|
|
8445
8668
|
}
|
|
8446
8669
|
const report = summaryResult.text;
|
|
@@ -8488,7 +8711,8 @@ async function observePass(ctx, agent, config, tailCount, target, signal) {
|
|
|
8488
8711
|
}, lifecycle.compactionId);
|
|
8489
8712
|
logger.step("观察提交:追加 compaction/end");
|
|
8490
8713
|
appendCompactionEnd(session, lifecycle);
|
|
8491
|
-
|
|
8714
|
+
clearPending();
|
|
8715
|
+
logger.info(`观察压缩完成(替换 ${replaceSeqs.length} 个表层节点,约 ${shadowedTokenCount} tokens,压缩至${triggerNote})`);
|
|
8492
8716
|
return { failed: false };
|
|
8493
8717
|
} catch (error) {
|
|
8494
8718
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -8517,7 +8741,7 @@ async function maybeCompress(ctx, agent, config, signal) {
|
|
|
8517
8741
|
return { failed: false };
|
|
8518
8742
|
}
|
|
8519
8743
|
logger.step(`会话路由:provider ${target.provider},model ${target.model}`);
|
|
8520
|
-
const
|
|
8744
|
+
const waitCount = config.tailMessageCount;
|
|
8521
8745
|
logger.step("反思 pass 开始");
|
|
8522
8746
|
const reflect = await reflectPass(ctx, agent, config, target, signal);
|
|
8523
8747
|
if (reflect.failed) {
|
|
@@ -8525,7 +8749,7 @@ async function maybeCompress(ctx, agent, config, signal) {
|
|
|
8525
8749
|
return reflect;
|
|
8526
8750
|
}
|
|
8527
8751
|
logger.step("反思 pass 结束,观察 pass 开始");
|
|
8528
|
-
const observe = await observePass(ctx, agent, config,
|
|
8752
|
+
const observe = await observePass(ctx, agent, config, waitCount, target, signal);
|
|
8529
8753
|
logger.step("观察 pass 结束,压缩流程完成");
|
|
8530
8754
|
return observe;
|
|
8531
8755
|
}
|
|
@@ -9146,8 +9370,9 @@ function buildSemanticRecallTool(options) {
|
|
|
9146
9370
|
* dsh-plugin-om 入口(tsdown 打包入口):导出 name / inject / apply。
|
|
9147
9371
|
* apply 注册 recall / recall-semantic 工具,并接线 agent/pre-step 自动压缩
|
|
9148
9372
|
* (先反思后观察,仅主会话生效)。压缩摘要尝试全部耗尽时拒绝本 step 中断当前
|
|
9149
|
-
* turn(signal
|
|
9150
|
-
*
|
|
9373
|
+
* turn(signal 中止除外),主会话日志记录失败原因与诊断子会话 sessionId(每次
|
|
9374
|
+
* 尝试的完整提示词与模型原始输出由 compaction-log.ts 落盘为诊断子会话)。压缩与
|
|
9375
|
+
* 检索的实现见 compress.ts / compaction-log.ts / recall.ts / semantic-recall.ts。
|
|
9151
9376
|
*/
|
|
9152
9377
|
/** 插件名(Loader 识别入口的稳定标识)。 */
|
|
9153
9378
|
const name = "dsh-plugin-om";
|
|
@@ -9187,7 +9412,8 @@ function apply(ctx, config) {
|
|
|
9187
9412
|
logger.warn(`pre-step 处理失败: ${error instanceof Error ? error.message : String(error)}`);
|
|
9188
9413
|
}
|
|
9189
9414
|
if (outcome.failed && !outcome.aborted) {
|
|
9190
|
-
|
|
9415
|
+
const diagnostic = outcome.diagnosticSessionId === void 0 ? "" : `(诊断子会话 ${outcome.diagnosticSessionId})`;
|
|
9416
|
+
logger.warn(`上下文压缩失败,拒绝本 step 中断当前 turn:${outcome.error}${diagnostic}`);
|
|
9191
9417
|
return { kind: "reject" };
|
|
9192
9418
|
}
|
|
9193
9419
|
return next();
|
package/dist/summarize.d.ts
CHANGED
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
* 定位与校验(首个 <history> 开标签到最后一个 </history>;整块 XML 非法时按条目标签
|
|
8
8
|
* 模糊提取重建 / 无 reasoning / index 连续),失败按 maxAttempts 重试;每次尝试的
|
|
9
9
|
* 结果或报错始终写入日志(成功 info / 失败 warn,失败原因说明具体问题而非解析器
|
|
10
|
-
*
|
|
10
|
+
* 原始报错);全部耗尽返回失败结果(携带最后一次尝试的实际报错)。最终失败
|
|
11
|
+
* (含 signal 中止)时把每次尝试的完整提示词与模型原始输出经 compaction-log.ts
|
|
12
|
+
* 原样落盘为诊断子会话,sessionId 随失败结果向上传播进主会话日志。每次请求前
|
|
11
13
|
* 过全局限流等待门;token usage 归入主会话记录。
|
|
12
14
|
*/
|
|
13
15
|
import type { Agent, Context, Session, TokenUsage } from './types.ts';
|
|
@@ -32,13 +34,15 @@ export type SummarySuccess = {
|
|
|
32
34
|
/** 成功时的尝试次数(1 起;载荷层换算为重试次数 = 该值 - 1)。 */
|
|
33
35
|
attemptCount: number;
|
|
34
36
|
};
|
|
35
|
-
/** 摘要调用失败结果:最后一次尝试的实际报错/具体问题 + 是否因 signal
|
|
37
|
+
/** 摘要调用失败结果:最后一次尝试的实际报错/具体问题 + 是否因 signal 中止 + 诊断子会话 id。 */
|
|
36
38
|
export type SummaryFailure = {
|
|
37
39
|
ok: false;
|
|
38
40
|
/** 最后一次尝试的实际报错(异常消息)或未通过校验的具体问题说明。 */
|
|
39
41
|
error: string;
|
|
40
42
|
/** 因 signal 中止(含限流等待被中止)而放弃;此时 error 为 COMPACTION_ABORTED_ERROR。 */
|
|
41
43
|
aborted: boolean;
|
|
44
|
+
/** 诊断子会话 id(最终失败时每次尝试的完整提示词与模型原始输出落盘处;落盘失败时缺失)。 */
|
|
45
|
+
diagnosticSessionId?: string;
|
|
42
46
|
};
|
|
43
47
|
/** 摘要调用结果(成功/失败二选一)。 */
|
|
44
48
|
export type SummaryOutcome = SummarySuccess | SummaryFailure;
|
|
@@ -95,13 +99,16 @@ export declare const SUMMARY_DEFAULT_MAX_ATTEMPTS = 11;
|
|
|
95
99
|
* 直连 LLM 执行一次摘要(观察或反思),返回文本与可选 token usage。
|
|
96
100
|
* 失败(抛异常 / 空输出 / 非 stop 结束 / 校验不通过)均记录日志并重试,每次尝试的
|
|
97
101
|
* 结果或报错始终写入日志(成功 info / 失败 warn,不受 debug 影响);全部尝试耗尽
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
102
|
+
* 返回失败结果(携带最后一次尝试的实际报错/具体问题)。最终失败(耗尽或 signal
|
|
103
|
+
* 中止)时把每次尝试的完整提示词与模型原始输出原样落盘为诊断子会话(phase 标注
|
|
104
|
+
* 观察或反思),诊断子会话 id 随失败结果返回。signal 中止(含限流等待被中止)
|
|
105
|
+
* 立即放弃并标记 aborted。每次请求发出前先过全局限流等待门。
|
|
101
106
|
*/
|
|
102
107
|
export declare function runSummarySubagent(ctx: Context, agent: Agent, instruction: string, contextText: string | undefined, maxTokens: number | undefined, target: RoutedTarget, debug: boolean, signal?: AbortSignal, options?: {
|
|
103
108
|
maxAttempts?: number;
|
|
104
109
|
expected?: SummaryValidationRange;
|
|
105
110
|
rateLimitWaitMs?: number;
|
|
111
|
+
/** 压缩 pass(诊断子会话 label 标注观察/反思;未提供时 label 回落「压缩」)。 */
|
|
112
|
+
phase?: 'observe' | 'reflect';
|
|
106
113
|
}): Promise<SummaryOutcome>;
|
|
107
114
|
//# sourceMappingURL=summarize.d.ts.map
|
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":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -29,6 +29,27 @@ declare module '@deepseek-ai/dsh-session/types' {
|
|
|
29
29
|
/** 面向用户的简短说明。 */
|
|
30
30
|
message: string;
|
|
31
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;
|
|
52
|
+
};
|
|
32
53
|
}
|
|
33
54
|
}
|
|
34
55
|
/** 官方包宿主类型再导出:插件 API 与工具签名统一从这里取型。 */
|
|
@@ -79,6 +100,15 @@ export type CompactionSummaryPayload = SessionEventMap['compaction/summary'] & {
|
|
|
79
100
|
/** 摘要重试次数(观察分块为各块重试之和,反思为尝试次数 - 1)。 */
|
|
80
101
|
attemptCount?: number;
|
|
81
102
|
};
|
|
103
|
+
/**
|
|
104
|
+
* 插件扩展的 compaction/end 载荷:宿主类型 + diagnosticSessionId(压缩最终失败时
|
|
105
|
+
* 落盘的诊断子会话 id)。宿主 append 不做 schema 剥离,扩展字段原样持久化;
|
|
106
|
+
* 客户端读取时按可选处理(UI 渲染行为不变)。
|
|
107
|
+
*/
|
|
108
|
+
export type CompactionEndPayload = SessionEventMap['compaction/end'] & {
|
|
109
|
+
/** 压缩最终失败时的诊断子会话 id(落盘失败时缺失)。 */
|
|
110
|
+
diagnosticSessionId?: string;
|
|
111
|
+
};
|
|
82
112
|
/**
|
|
83
113
|
* 插件扩展的 compaction/start 载荷:宿主类型 + phase(压缩 pass)。
|
|
84
114
|
* 客户端读取时按可选处理,缺失回落通用压缩中文案。
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|