dsh-plugin-om 0.0.20 → 0.0.21

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 CHANGED
@@ -79,7 +79,7 @@ dsh的"预设"分为两层,`dsh web`等同于`dsh --profile web`,调用的
79
79
  4. 提供recall/recall-semantic两个tool进行检索
80
80
 
81
81
  观察与反思共用同一套系统提示词(buildHistoryPrompt):输入与输出都是合法的 <history> 块(模型消息 + index 的表达形式),先定义块、要求压缩、再给出数据源(下方 <history> 消息记录)。
82
- 观察压缩按 `observeChunkTokens` 边界把未压缩消息分块(完整消息不跨块,thinking/text/toolcall&result 同块)并行摘要,各块合并为一个 <history> 块提交;提示词按块位次分档——前块要求简单摘要,最后一块要求「越往后越细」保留细节。
82
+ 观察压缩按 `observeChunkTokens` 边界把未压缩消息分块(完整消息不跨块,thinking/text/toolcall&result 同块)压缩摘要,最多 `observeChunkParallelism` 块同时进行、其余块排队,各块合并为一个 <history> 块提交;提示词按块位次分档——前块要求简单摘要,最后一块要求「越往后越细」保留细节。任一摘要请求遇 429 限流后,插件全局进入冷却期:后续所有摘要请求在 `rateLimitWaitMs` 内不会发出。
83
83
 
84
84
  ### 压缩日志块结构
85
85
 
@@ -125,6 +125,8 @@ dsh的"预设"分为两层,`dsh web`等同于`dsh --profile web`,调用的
125
125
  | `compressMaxTokens` | `10000` | 反思(合并调用)生成上限;观察分块用 `observeChunkMaxTokens` |
126
126
  | `observeChunkTokens` | `30000` | 观察分块 token 边界:未压缩消息按该边界拆分为多块并行压缩(完整消息不跨块) |
127
127
  | `observeChunkMaxTokens` | `5000` | 观察分块单块摘要的生成上限(每块独立调用) |
128
+ | `observeChunkParallelism` | `2` | 观察分块压缩的最大并行数:同时进行的单块摘要调用上限,其余块排队(`1` 即串行) |
129
+ | `rateLimitWaitMs` | `60000` | 遇 429 限流后,下一次摘要请求发出前至少等待的毫秒数(插件全局共享冷却期:任一请求遇 429 后,所有后续摘要请求——含并行中的其他块——都等满该时长;`0` 视为不限流) |
128
130
  | `tailMessageCount` | `10` | 尾部保留的不压缩消息条数(不压缩、不被替换、不进摘要日志) |
129
131
  | `compressRetryCount` | `10` | 摘要调用失败后的最大重试次数(不含首次;总尝试次数 = 该值 + 1) |
130
132
  | `modelDir` | 共享目录 | recall-semantic 嵌入模型目录(默认 `$DSH_HOME/plugin-data/dsh-plugin-om/models/<id>`,跨插件版本共享;小文件随包分发并在缺失时自动补齐,onnx 缺失且启用语义召回时运行时自动下载到该目录;可指向自定义目录) |
@@ -180,10 +182,11 @@ src/
180
182
  ├── log-index.ts # 完整消息索引(index 定位 user/sys/assistant/具有result的toolcall;user_message 按 source.kind 分类:kind:user 为用户消息、其余为系统消息;本插件自产压缩日志消息不占位;未闭合 tool-call 不占位;recall 与摘要共用)
181
183
  ├── embedding.ts # 本地 ONNX 嵌入(@huggingface/transformers + 本地模型;共享目录解析 / 小文件补齐 / 运行时按需下载编排 / 懒加载 / 批量 / cosine)
182
184
  ├── model-download.ts # 模型下载原语(modelSourceUrl / needsDownload / 原子落盘 / 开始结束日志与失败镜像建议;运行时与 dev CLI 共用)
183
- ├── summarize.ts # 共享提示词 buildHistoryPrompt(观察/反思同一套;mode 控制摘要粒度:summary 简单摘要 / detailed 越往后越细)+ renderMessages(@xmldom/xmldom 构建 <history> 块输入:用户消息原样、系统消息渲染为 <sys> 空块、自动转义)+ 直连 ctx.llm.stream() 摘要(new 方式:指令作 system、输入为渲染消息;extractSummaryLog 提取校验:XML 结构合法 / 无 reasoning / index 连续 / 覆盖区间;重试与流式 usage 归入主会话;成功返回 attemptCount(尝试次数,载荷层换算为重试次数))
185
+ ├── summarize.ts # 共享提示词 buildHistoryPrompt(观察/反思同一套;mode 控制摘要粒度:summary 简单摘要 / detailed 越往后越细)+ renderMessages(@xmldom/xmldom 构建 <history> 块输入:用户消息原样、系统消息渲染为 <sys> 空块、自动转义)+ 直连 ctx.llm.stream() 摘要(new 方式:指令作 system、输入为渲染消息;extractSummaryLog 提取校验:XML 结构合法 / 无 reasoning / index 连续 / 覆盖区间;重试与流式 usage 归入主会话;每次请求前过全局限流等待门 rate-limit.ts;成功返回 attemptCount(尝试次数,载荷层换算为重试次数))
186
+ ├── rate-limit.ts # 全局限流门(插件进程级共享状态):429 识别(isRateLimitError)/ 冷却期记录(noteRateLimit)/ 等待门(gateRateLimit:最近一次 429 + rateLimitWaitMs 之前不放行,等待期间中止立即放弃,新 429 顺延冷却期)
184
187
  ├── recall.ts # recall 工具
185
188
  ├── semantic-recall.ts # recall-semantic 工具(query 语义检索 + 区间限定 + 回退全量 + 匹配说明)
186
- └── compress.ts # 两级自动压缩(测量 / mid-turn 区间计算 / 配对平衡回退 / source 标记判定摘要消息 / 观察分块并行 chunkCompleteMessages + 合并 mergeChunkReports / compaction/* 生命周期事件:start 在摘要调用前追加并带 phase,失败补 end(error) + 替换消息 source 插件标识)
189
+ └── compress.ts # 两级自动压缩(测量 / mid-turn 区间计算 / 配对平衡回退 / source 标记判定摘要消息 / 观察分块经 runWithConcurrency 有界并发池逐块压缩 + 合并 mergeChunkReports / compaction/* 生命周期事件:start 在摘要调用前追加并带 phase,失败补 end(error) + 替换消息 source 插件标识)
187
190
  src/client/
188
191
  ├── index.ts # 浏览器客户端入口(exports["./client"] → dist/client.js):注入 slots/conversationEvents/locale,注册卡片定义与渲染器
189
192
  ├── definition.ts # 压缩卡片业务定义:认领插件生命周期事件与替换检查点(source.plugin = dsh-plugin-om),聚合摘要卡片节点;start→压缩中提示行(running+phase)、end→hidden 撤回、summary→卡片(retryCount)
@@ -2,6 +2,12 @@ import type { Agent, CompleteMessage, Context, PluginConfig, Session } from './t
2
2
  import { type RoutedTarget } from './utils.ts';
3
3
  /** 历史文本 token 估算:4 字符 ≈ 1 token(与宿主 dsh-token-meter 启发式一致)。 */
4
4
  export declare function estimateTextTokens(text: string): number;
5
+ /**
6
+ * 有界并发池:最多 limit 个任务同时运行(limit 非法时按 1 处理),任务按 index 顺序
7
+ * 取用,结果数组与 items 按 index 对齐(任务自身以返回值表达失败,不在此抛出)。
8
+ * items 为空返回空数组。
9
+ */
10
+ export declare function runWithConcurrency<T, R>(items: readonly T[], limit: number, task: (item: T, index: number) => Promise<R>): Promise<R[]>;
5
11
  /**
6
12
  * 按 token 边界把完整消息序列分块(观察并行压缩用):完整消息不跨块——
7
13
  * 一条完整消息(含其 thinking/text/toolcall&result 全部 seqs)必然整体落在同一块,
@@ -1 +1 @@
1
- {"version":3,"file":"compress.d.ts","sourceRoot":"","sources":["../src/compress.ts"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EACV,KAAK,EAIL,eAAe,EACf,OAAO,EACP,YAAY,EACZ,OAAO,EAIR,MAAM,YAAY,CAAC;AACpB,OAAO,EAAgB,KAAK,YAAY,EAAqC,MAAM,YAAY,CAAC;AAEhG,+DAA+D;AAC/D,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EACrC,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,SAAS,eAAe,EAAE,EAC/B,aAAa,EAAE,MAAM,EACrB,eAAe,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,MAAM,GACtC,eAAe,EAAE,EAAE,CA6BrB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAiBlE;AAyED,+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;AA8GD;;;;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,IAAI,CAAC,CA8Hf;AAED;;;GAGG;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,IAAI,CAAC,CA0Lf;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,CAyBf"}
1
+ {"version":3,"file":"compress.d.ts","sourceRoot":"","sources":["../src/compress.ts"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EACV,KAAK,EAIL,eAAe,EACf,OAAO,EACP,YAAY,EACZ,OAAO,EAIR,MAAM,YAAY,CAAC;AACpB,OAAO,EAAgB,KAAK,YAAY,EAAqC,MAAM,YAAY,CAAC;AAEhG,+DAA+D;AAC/D,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EAAE,CAAC,EAC3C,KAAK,EAAE,SAAS,CAAC,EAAE,EACnB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,GAC3C,OAAO,CAAC,CAAC,EAAE,CAAC,CAkBd;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EACrC,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,SAAS,eAAe,EAAE,EAC/B,aAAa,EAAE,MAAM,EACrB,eAAe,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,MAAM,GACtC,eAAe,EAAE,EAAE,CA6BrB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAiBlE;AAyED,+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;AA8GD;;;;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,IAAI,CAAC,CA+Hf;AAED;;;GAGG;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,IAAI,CAAC,CAgMf;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,CAyBf"}
package/dist/config.d.ts CHANGED
@@ -10,6 +10,10 @@ export type PluginConfig = {
10
10
  observeChunkTokens: number;
11
11
  /** 观察分块单块摘要的生成上限(LLM maxTokens;每块独立调用)。 */
12
12
  observeChunkMaxTokens: number;
13
+ /** 观察分块压缩的最大并行数:同时进行的单块摘要调用上限,其余块排队(默认 2)。 */
14
+ observeChunkParallelism: number;
15
+ /** 遇 429 限流后,下一次摘要请求发出前至少等待的毫秒数(全局限流冷却期,默认 60000)。 */
16
+ rateLimitWaitMs: number;
13
17
  /** 压缩边界:其后不压缩消息数下限(正整数,尾部保留)。 */
14
18
  tailMessageCount: number;
15
19
  /** 摘要调用失败后的最大重试次数(不含首次尝试;总尝试次数 = 该值 + 1,默认 11)。 */
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAOA,kCAAkC;AAClC,MAAM,MAAM,YAAY,GAAG;IACzB,6CAA6C;IAC7C,sBAAsB,EAAE,MAAM,CAAC;IAC/B,8DAA8D;IAC9D,sBAAsB,EAAE,MAAM,CAAC;IAC/B,qCAAqC;IACrC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iDAAiD;IACjD,kBAAkB,EAAE,MAAM,CAAC;IAC3B,2CAA2C;IAC3C,qBAAqB,EAAE,MAAM,CAAC;IAC9B,iCAAiC;IACjC,gBAAgB,EAAE,MAAM,CAAC;IACzB,mDAAmD;IACnD,kBAAkB,EAAE,MAAM,CAAC;IAC3B,wDAAwD;IACxD,SAAS,EAAE,OAAO,CAAC;IACnB,4EAA4E;IAC5E,KAAK,EAAE,OAAO,CAAC;IACf,0CAA0C;IAC1C,aAAa,EAAE,OAAO,CAAC;IACvB,2DAA2D;IAC3D,qBAAqB,EAAE,OAAO,CAAC;IAC/B,wCAAwC;IACxC,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,iEAAiE;AACjE,eAAO,MAAM,cAAc,EAAE,QAAQ,CAAC,YAAY,CAahD,CAAC;AAuCH;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC,YAAY,CAAC,CA4BnE"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAOA,kCAAkC;AAClC,MAAM,MAAM,YAAY,GAAG;IACzB,6CAA6C;IAC7C,sBAAsB,EAAE,MAAM,CAAC;IAC/B,8DAA8D;IAC9D,sBAAsB,EAAE,MAAM,CAAC;IAC/B,qCAAqC;IACrC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iDAAiD;IACjD,kBAAkB,EAAE,MAAM,CAAC;IAC3B,2CAA2C;IAC3C,qBAAqB,EAAE,MAAM,CAAC;IAC9B,8CAA8C;IAC9C,uBAAuB,EAAE,MAAM,CAAC;IAChC,sDAAsD;IACtD,eAAe,EAAE,MAAM,CAAC;IACxB,iCAAiC;IACjC,gBAAgB,EAAE,MAAM,CAAC;IACzB,mDAAmD;IACnD,kBAAkB,EAAE,MAAM,CAAC;IAC3B,wDAAwD;IACxD,SAAS,EAAE,OAAO,CAAC;IACnB,4EAA4E;IAC5E,KAAK,EAAE,OAAO,CAAC;IACf,0CAA0C;IAC1C,aAAa,EAAE,OAAO,CAAC;IACvB,2DAA2D;IAC3D,qBAAqB,EAAE,OAAO,CAAC;IAC/B,wCAAwC;IACxC,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,iEAAiE;AACjE,eAAO,MAAM,cAAc,EAAE,QAAQ,CAAC,YAAY,CAehD,CAAC;AA2CH;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC,YAAY,CAAC,CA4BnE"}
package/dist/index.mjs CHANGED
@@ -3,6 +3,7 @@ import { homedir } from "node:os";
3
3
  import path from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { z } from "zod";
6
+ import { toJSONSchema } from "zod/v4/core";
6
7
  //#region \0rolldown/runtime.js
7
8
  var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
8
9
  //#endregion
@@ -7368,7 +7369,7 @@ var require_dom_parser = /* @__PURE__ */ __commonJSMin(((exports) => {
7368
7369
  exports.onWarningStopParsing = onWarningStopParsing;
7369
7370
  }));
7370
7371
  //#endregion
7371
- //#region src/summarize.ts
7372
+ //#region src/rate-limit.ts
7372
7373
  var import_lib = (/* @__PURE__ */ __commonJSMin(((exports) => {
7373
7374
  var conventions = require_conventions();
7374
7375
  exports.assign = conventions.assign;
@@ -7409,6 +7410,69 @@ var import_lib = (/* @__PURE__ */ __commonJSMin(((exports) => {
7409
7410
  exports.onWarningStopParsing = domParser.onWarningStopParsing;
7410
7411
  })))();
7411
7412
  /**
7413
+ * 全局限流门(插件进程级共享状态):任一摘要请求遇 429 限流后记录时间戳,
7414
+ * 此后所有摘要请求在发出前先等待到「最近一次 429 + rateLimitWaitMs」之后——
7415
+ * 并行压缩时其他块的下一次请求同样受限。等待期间 signal 中止则立即放弃。
7416
+ *
7417
+ * 门在进入时与等待结束时都会重读最近限流时间戳:等待期间发生新的 429 会顺延
7418
+ * 冷却期(循环等待直到通过或中止)。
7419
+ */
7420
+ /** 最近一次 429 限流的时间戳(ms;null = 未遇过限流,门直接放行)。 */
7421
+ let lastRateLimitAt = null;
7422
+ /**
7423
+ * 判定错误信息是否为 429 限流:匹配 429(独立数字)或 rate limit(空格/连字符/
7424
+ * 下划线分隔与 camelCase 均可),大小写不敏感。
7425
+ */
7426
+ function isRateLimitError(message) {
7427
+ return /\b429\b|rate[\s_-]?limit/i.test(message);
7428
+ }
7429
+ /** 记录一次 429 限流:把冷却期起点更新为当前时间。 */
7430
+ function noteRateLimit() {
7431
+ lastRateLimitAt = Date.now();
7432
+ }
7433
+ /** 可中止延时:等待满 ms 返回 true;等待期间 signal 中止返回 false。 */
7434
+ function delay(ms, signal) {
7435
+ return new Promise((resolve) => {
7436
+ if (signal?.aborted) {
7437
+ resolve(false);
7438
+ return;
7439
+ }
7440
+ /** 定时器句柄(正常到点或中止清理用)。 */
7441
+ const timer = setTimeout(() => {
7442
+ cleanup();
7443
+ resolve(true);
7444
+ }, ms);
7445
+ /** 中止监听(到点立即返回 false)。 */
7446
+ const onAbort = () => {
7447
+ cleanup();
7448
+ resolve(false);
7449
+ };
7450
+ /** 清理定时器与中止监听。 */
7451
+ const cleanup = () => {
7452
+ clearTimeout(timer);
7453
+ signal?.removeEventListener("abort", onAbort);
7454
+ };
7455
+ signal?.addEventListener("abort", onAbort, { once: true });
7456
+ });
7457
+ }
7458
+ /**
7459
+ * 限流等待门:处于 429 冷却期(最近一次 429 + waitMs 未到)时等待到期限,
7460
+ * 通过后返回 true;等待期间 signal 中止返回 false。未遇过限流或冷却期已过
7461
+ * 立即放行。waitMs ≤ 0 视为不限流。
7462
+ */
7463
+ async function gateRateLimit(waitMs, signal) {
7464
+ if (waitMs <= 0) return true;
7465
+ while (lastRateLimitAt !== null) {
7466
+ /** 距冷却期结束的剩余等待(≤ 0 表示已过冷却期)。 */
7467
+ const remaining = lastRateLimitAt + waitMs - Date.now();
7468
+ if (remaining <= 0) return true;
7469
+ if (!await delay(remaining, signal)) return false;
7470
+ }
7471
+ return true;
7472
+ }
7473
+ //#endregion
7474
+ //#region src/summarize.ts
7475
+ /**
7412
7476
  * 共享压缩提示词(观察/反思同一套):定义 history 块(模型消息 + index 的表达形式)、
7413
7477
  * 完整消息定义、要求压缩(完整保留用户消息 / reasoning 仅参考 / 关联 assistant 合并 /
7414
7478
  * index/start/end 连续)、输出格式(一个合法 <history> 块,无 reasoning)、数据源说明。
@@ -7812,6 +7876,9 @@ function extractSummaryLog(raw, expected) {
7812
7876
  * 失败(抛异常 / 空输出 / 非 stop 结束 / 校验不通过)均记录日志并重试,总共最多尝试
7813
7877
  * options.maxAttempts 次(默认 SUMMARY_DEFAULT_MAX_ATTEMPTS);全部尝试失败返回 null
7814
7878
  * (不产生任何日志变更)。输出长度受 maxTokens 限制。
7879
+ * 每次请求发出前先过全局限流等待门(gateRateLimit):任一请求遇 429 后,后续所有
7880
+ * 摘要请求(含并行中的其他调用方)在「最近一次 429 + options.rateLimitWaitMs」之前
7881
+ * 不会发出(缺省 RATE_LIMIT_WAIT_MS_DEFAULT)。
7815
7882
  */
7816
7883
  async function runSummarySubagent(ctx, agent, instruction, contextText, maxTokens, target, debug, signal, options) {
7817
7884
  /** 当前会话。 */
@@ -7827,6 +7894,12 @@ async function runSummarySubagent(ctx, agent, instruction, contextText, maxToken
7827
7894
  logger.warn(`摘要调用中止(第 ${attempt}/${maxAttempts} 次尝试前 signal 已中止),放弃本次摘要`);
7828
7895
  return null;
7829
7896
  }
7897
+ /** 限流冷却时长(ms;调用方未传时用默认值)。 */
7898
+ const rateLimitWaitMs = options?.rateLimitWaitMs ?? 6e4;
7899
+ if (!await gateRateLimit(rateLimitWaitMs, signal)) {
7900
+ logger.warn(`摘要调用中止(第 ${attempt}/${maxAttempts} 次尝试前限流等待被 signal 中止),放弃本次摘要`);
7901
+ return null;
7902
+ }
7830
7903
  logger.step(`摘要调用开始(第 ${attempt}/${maxAttempts} 次,provider ${target.provider},model ${target.model},maxTokens ${maxTokens})`);
7831
7904
  try {
7832
7905
  /** 摘要请求选项(new 方式组装)。 */
@@ -7856,6 +7929,10 @@ async function runSummarySubagent(ctx, agent, instruction, contextText, maxToken
7856
7929
  } catch (error) {
7857
7930
  /** 错误信息(统一为字符串)。 */
7858
7931
  const message = error instanceof Error ? error.message : String(error);
7932
+ if (isRateLimitError(message)) {
7933
+ noteRateLimit();
7934
+ logger.warn(`摘要调用触发限流(429,第 ${attempt}/${maxAttempts} 次),下一次请求前至少等待 ${rateLimitWaitMs}ms`);
7935
+ }
7859
7936
  lastFailure = { error: message };
7860
7937
  logger.warn(`摘要调用失败(第 ${attempt}/${maxAttempts} 次,${message})` + (attempt < maxAttempts ? ",将重试" : ",重试耗尽,忽略本次摘要"));
7861
7938
  }
@@ -7899,6 +7976,30 @@ function estimateTextTokens(text) {
7899
7976
  return Math.ceil(text.length / 4);
7900
7977
  }
7901
7978
  /**
7979
+ * 有界并发池:最多 limit 个任务同时运行(limit 非法时按 1 处理),任务按 index 顺序
7980
+ * 取用,结果数组与 items 按 index 对齐(任务自身以返回值表达失败,不在此抛出)。
7981
+ * items 为空返回空数组。
7982
+ */
7983
+ async function runWithConcurrency(items, limit, task) {
7984
+ /** 结果数组(按 index 对齐)。 */
7985
+ const results = new Array(items.length);
7986
+ /** 下一个待处理任务的下标(worker 间共享取号)。 */
7987
+ let next = 0;
7988
+ /** worker 数量(clamp 到 [1, items.length])。 */
7989
+ const workerCount = Math.max(1, Math.min(Math.floor(limit), items.length));
7990
+ /** 各 worker:循环取号执行任务直到取尽。 */
7991
+ const workers = Array.from({ length: workerCount }, async () => {
7992
+ while (next < items.length) {
7993
+ /** 本 worker 领取的任务下标。 */
7994
+ const index = next;
7995
+ next += 1;
7996
+ results[index] = await task(items[index], index);
7997
+ }
7998
+ });
7999
+ await Promise.all(workers);
8000
+ return results;
8001
+ }
8002
+ /**
7902
8003
  * 按 token 边界把完整消息序列分块(观察并行压缩用):完整消息不跨块——
7903
8004
  * 一条完整消息(含其 thinking/text/toolcall&result 全部 seqs)必然整体落在同一块,
7904
8005
  * 单条超界的消息独立成块。空输入返回空数组。
@@ -8268,7 +8369,8 @@ async function reflectPass(ctx, agent, config, target, signal) {
8268
8369
  expected: expectedEnd < 0 ? { start: 0 } : {
8269
8370
  start: 0,
8270
8371
  end: expectedEnd
8271
- }
8372
+ },
8373
+ rateLimitWaitMs: config.rateLimitWaitMs
8272
8374
  });
8273
8375
  if (summaryResult === null || summaryResult.text.trim().length === 0) {
8274
8376
  logger.step("反思:摘要调用失败/无输出,追加 compaction/end(error)");
@@ -8366,7 +8468,7 @@ async function observePass(ctx, agent, config, tailCount, target, signal) {
8366
8468
  logger.step(`观察:保留旧块 ${blocks.length} 条,替换新消息 [${replaceSeqs[0]}..${range.end}](${replaceSeqs.length} 条),尾部保留 ${tailCount} 条(不压缩、不进日志),新消息 index ${startIndex}..${endIndex}`);
8367
8469
  /** 按 observeChunkTokens 边界把完整消息分块(完整消息不跨块;每块独立并行压缩)。 */
8368
8470
  const chunks = chunkCompleteMessages(session, inRangeCms, config.observeChunkTokens, (message) => ctx.tokenMeter.estimateMessage(message));
8369
- logger.step(`观察:${inRangeCms.length} 条完整消息按 ${config.observeChunkTokens} tokens 边界分为 ${chunks.length} 块(每块摘要 maxTokens ${config.observeChunkMaxTokens},除最后一块外要求简单摘要)`);
8471
+ logger.step(`观察:${inRangeCms.length} 条完整消息按 ${config.observeChunkTokens} tokens 边界分为 ${chunks.length} 块(最多 ${config.observeChunkParallelism} 块并行,每块摘要 maxTokens ${config.observeChunkMaxTokens},除最后一块外要求简单摘要)`);
8370
8472
  /** 本次压缩生命周期(compactionId + 当前轮次;start 在摘要调用前开启,UI 压缩中提示)。 */
8371
8473
  const lifecycle = {
8372
8474
  compactionId: newCompactionId(),
@@ -8381,8 +8483,8 @@ async function observePass(ctx, agent, config, tailCount, target, signal) {
8381
8483
  logger.warn(`观察压缩启动失败: ${message}`);
8382
8484
  return;
8383
8485
  }
8384
- /** 各块摘要结果(Promise.all 并行;null = 该块失败)。 */
8385
- const chunkResults = await Promise.all(chunks.map(async (chunk, index) => {
8486
+ /** 各块摘要结果(有界并发池,最多 observeChunkParallelism 块同时进行;null = 该块失败;结果按块顺序)。 */
8487
+ const chunkResults = await runWithConcurrency(chunks, config.observeChunkParallelism, async (chunk, index) => {
8386
8488
  /** 该块提示词(较早块简单摘要;最后一块越往后越细)。 */
8387
8489
  const instruction = buildHistoryPrompt(index === chunks.length - 1 ? "detailed" : "summary");
8388
8490
  /** 该块渲染输入(块内完整消息的 seqs;合法 <history> 块,含绝对 index)。 */
@@ -8395,9 +8497,10 @@ async function observePass(ctx, agent, config, tailCount, target, signal) {
8395
8497
  expected: {
8396
8498
  start,
8397
8499
  end
8398
- }
8500
+ },
8501
+ rateLimitWaitMs: config.rateLimitWaitMs
8399
8502
  });
8400
- }));
8503
+ });
8401
8504
  if (chunkResults.find((r) => r === null || r.text.trim().length === 0) !== void 0) {
8402
8505
  logger.step("观察:分块摘要存在失败/无输出,不产生部分替换,追加 compaction/end(error)");
8403
8506
  try {
@@ -8740,6 +8843,8 @@ const DEFAULT_CONFIG = Object.freeze({
8740
8843
  compressMaxTokens: 1e4,
8741
8844
  observeChunkTokens: 3e4,
8742
8845
  observeChunkMaxTokens: 5e3,
8846
+ observeChunkParallelism: 2,
8847
+ rateLimitWaitMs: 6e4,
8743
8848
  tailMessageCount: 10,
8744
8849
  compressRetryCount: 10,
8745
8850
  omEnabled: true,
@@ -8755,6 +8860,8 @@ const NUMBER_KEYS = [
8755
8860
  ["compressMaxTokens", true],
8756
8861
  ["observeChunkTokens", true],
8757
8862
  ["observeChunkMaxTokens", true],
8863
+ ["observeChunkParallelism", true],
8864
+ ["rateLimitWaitMs", true],
8758
8865
  ["tailMessageCount", true],
8759
8866
  ["compressRetryCount", true]
8760
8867
  ];
@@ -8804,6 +8911,21 @@ function resolveConfig(raw) {
8804
8911
  return Object.freeze(config);
8805
8912
  }
8806
8913
  //#endregion
8914
+ //#region src/json-schema.ts
8915
+ /**
8916
+ * zod schema → 工具 wire 参数 JSON Schema 的转换工具。
8917
+ *
8918
+ * 官方 API(如 api.deepseek.com 的 /chat/completions)要求 tools[].function.parameters
8919
+ * 为根级带 type:'object' 的标准 JSON Schema;工具的参数定义统一由 zod 的 toJSONSchema
8920
+ * 生成,避免手写属性 map 与执行期解析 schema 双份定义漂移。剥除 $schema 元键与
8921
+ * additionalProperties:未知键不在 wire 层拒绝,执行期仍由 zod 解析剥离。
8922
+ */
8923
+ /** 由 zod schema 生成 wire 参数 JSON Schema(根 type:'object',含 properties/required 与 describe 描述)。 */
8924
+ function parametersFromZod(schema) {
8925
+ const { $schema: _schema, additionalProperties: _additional, ...rest } = toJSONSchema(schema);
8926
+ return rest;
8927
+ }
8928
+ //#endregion
8807
8929
  //#region src/recall.ts
8808
8930
  /**
8809
8931
  * recall 工具:按「完整消息」序号(index)回看原始会话(start/end 为完整消息 index,
@@ -8813,17 +8935,19 @@ function resolveConfig(raw) {
8813
8935
  * recall 自身不设输出上限:超大的工具结果由 tool-result-pruner 裁剪(pruneContent),
8814
8936
  * 输出 token 由 pruner 配置控制。
8815
8937
  *
8816
- * 参数由 zod schema(recallArgsSchema)在 execute 入口校验:start 必填(number),
8817
- * end/offset 至少提供一个;非法参数抛出可读错误。
8938
+ * 参数由 zod schema(recallArgsSchema)统一描述:wire 参数 JSON Schema(根 type:'object',
8939
+ * 各字段描述来自 .describe())直接发给模型,execute 入口再做运行时校验(start 必填;
8940
+ * end/offset 至少提供一个;非法参数抛出可读错误)。
8818
8941
  */
8819
8942
  /**
8820
8943
  * recall 工具参数 schema:start 必填(number);end 与 offset 至少提供一个
8821
8944
  * (二者同时给出时 end 优先,与 execute 语义一致);未知键自动剥离。
8945
+ * 各字段描述经 .describe() 透传到 wire JSON Schema(生成见 json-schema.ts)。
8822
8946
  */
8823
8947
  const recallArgsSchema = z.object({
8824
- start: z.number(),
8825
- end: z.number().optional(),
8826
- offset: z.number().optional()
8948
+ start: z.number().describe("完整消息序号(index),作为基准边界,和 end 或 offset 配合,指定区间;end 与 offset 至少提供一个(同时给出时 end 优先)。"),
8949
+ end: z.number().optional().describe("与 offset 互斥,指定区间的另一个边界。"),
8950
+ offset: z.number().optional().describe("与 end 互斥。相对 start 的步数:正数向后、负数向前。")
8827
8951
  }).refine((args) => args.end !== void 0 || args.offset !== void 0, { message: "end 与 offset 至少提供一个" });
8828
8952
  /**
8829
8953
  * 解析并校验 recall 调用参数:校验失败时抛出首个校验问题的可读消息
@@ -8843,21 +8967,7 @@ function buildRecallTool(getPruner) {
8843
8967
  return {
8844
8968
  name: "recall",
8845
8969
  description: `${COMPLETE_MESSAGE_DEFINITION}此工具可以精确查询完整消息。用index指定一个区间,返回区间内所有完整消息的内容。`,
8846
- parameters: {
8847
- start: {
8848
- type: "number",
8849
- description: "完整消息序号(index),作为基准边界,和end或offset配合,指定区间",
8850
- required: true
8851
- },
8852
- end: {
8853
- type: "number",
8854
- description: "与 offset 互斥,指定区间的另一个边界。"
8855
- },
8856
- offset: {
8857
- type: "number",
8858
- description: "与 end 互斥。相对 start 的步数:正数向后、负数向前。"
8859
- }
8860
- },
8970
+ parameters: parametersFromZod(recallArgsSchema),
8861
8971
  output: {
8862
8972
  schema: { type: "string" },
8863
8973
  render: (_args, value) => [{
@@ -8925,6 +9035,8 @@ function buildRecallTool(getPruner) {
8925
9035
  *
8926
9036
  * - 参数:query 必填;top_k(默认 3,1-10);start/end/offset 限定检索区间
8927
9037
  * (意义同 recall:start 为基准边界,end 与 offset 二选一;end 优先)。
9038
+ * wire 参数 JSON Schema 由本 schema 经 toJSONSchema 生成(各字段描述来自 .describe(),
9039
+ * 见 json-schema.ts)。
8928
9040
  * - 区间缺省(start 未提供)→ 检索全部消息;区间不合法(start/end 越界等)→
8929
9041
  * 不报错,回退全量检索并在输出中明确告知(模型可见)。
8930
9042
  * - 向量:本地 ONNX embedding(embedding.ts,懒加载 + 批量);相似度 = cosine。
@@ -8934,11 +9046,11 @@ function buildRecallTool(getPruner) {
8934
9046
  */
8935
9047
  /** recall-semantic 工具参数 schema:query 必填;top_k 默认 3(1-10);区间参数均可选。 */
8936
9048
  const semanticRecallArgsSchema = z.object({
8937
- query: z.string(),
8938
- top_k: z.number().int().min(1).max(10).optional(),
8939
- start: z.number().optional(),
8940
- end: z.number().optional(),
8941
- offset: z.number().optional()
9049
+ query: z.string().describe("描述要找的内容的自然语言 query(可混用中英文与代码术语,如 \"修复 retry backoff 的逻辑\"),不能为空。"),
9050
+ top_k: z.number().int().min(1).max(10).optional().describe("返回最匹配的完整消息条数(1-10,默认 3)。"),
9051
+ start: z.number().optional().describe("完整消息序号(index),可选。作为基准边界,和end或offset配合,指定搜索区间。"),
9052
+ end: z.number().optional().describe("必须和start配合使用,与 offset 互斥,指定搜索区间的另一个边界。"),
9053
+ offset: z.number().optional().describe("必须和start配合使用,与 end 互斥。相对 start 的步数:正数向后、负数向前。")
8942
9054
  }).refine((args) => args.query.trim().length > 0, { message: "query 不能为空" });
8943
9055
  /** 解析并校验参数:失败时抛出可读错误(普通 Error 而非 ZodError)。 */
8944
9056
  function parseSemanticRecallArgs(raw) {
@@ -9033,29 +9145,7 @@ function buildSemanticRecallTool(options) {
9033
9145
  return {
9034
9146
  name: "recall-semantic",
9035
9147
  description: `${COMPLETE_MESSAGE_DEFINITION}此工具可以按自然语言含义,检索最符合的完整消息。默认在全消息范围搜索,可以指定区间。`,
9036
- parameters: {
9037
- query: {
9038
- type: "string",
9039
- description: "描述要找的内容的自然语言 query(可混用中英文与代码术语,如 \"修复 retry backoff 的逻辑\")。",
9040
- required: true
9041
- },
9042
- top_k: {
9043
- type: "number",
9044
- description: "返回最匹配的完整消息条数(1-10,默认 3)。"
9045
- },
9046
- start: {
9047
- type: "number",
9048
- description: "完整消息序号(index),可选。作为基准边界,和end或offset配合,指定搜索区间。"
9049
- },
9050
- end: {
9051
- type: "number",
9052
- description: "必须和start配合使用,与 offset 互斥,指定搜索区间的另一个边界。"
9053
- },
9054
- offset: {
9055
- type: "number",
9056
- description: "必须和start配合使用,与 end 互斥。相对 start 的步数:正数向后、负数向前。"
9057
- }
9058
- },
9148
+ parameters: parametersFromZod(semanticRecallArgsSchema),
9059
9149
  output: {
9060
9150
  schema: { type: "string" },
9061
9151
  render: (_args, value) => [{
@@ -0,0 +1,12 @@
1
+ /**
2
+ * zod schema → 工具 wire 参数 JSON Schema 的转换工具。
3
+ *
4
+ * 官方 API(如 api.deepseek.com 的 /chat/completions)要求 tools[].function.parameters
5
+ * 为根级带 type:'object' 的标准 JSON Schema;工具的参数定义统一由 zod 的 toJSONSchema
6
+ * 生成,避免手写属性 map 与执行期解析 schema 双份定义漂移。剥除 $schema 元键与
7
+ * additionalProperties:未知键不在 wire 层拒绝,执行期仍由 zod 解析剥离。
8
+ */
9
+ import { type $ZodType } from 'zod/v4/core';
10
+ /** 由 zod schema 生成 wire 参数 JSON Schema(根 type:'object',含 properties/required 与 describe 描述)。 */
11
+ export declare function parametersFromZod<T extends $ZodType>(schema: T): Record<string, unknown>;
12
+ //# sourceMappingURL=json-schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-schema.d.ts","sourceRoot":"","sources":["../src/json-schema.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,KAAK,QAAQ,EAAgB,MAAM,aAAa,CAAC;AAE1D,gGAAgG;AAChG,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,QAAQ,EAAE,MAAM,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAIxF"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * 全局限流门(插件进程级共享状态):任一摘要请求遇 429 限流后记录时间戳,
3
+ * 此后所有摘要请求在发出前先等待到「最近一次 429 + rateLimitWaitMs」之后——
4
+ * 并行压缩时其他块的下一次请求同样受限。等待期间 signal 中止则立即放弃。
5
+ *
6
+ * 门在进入时与等待结束时都会重读最近限流时间戳:等待期间发生新的 429 会顺延
7
+ * 冷却期(循环等待直到通过或中止)。
8
+ */
9
+ /** 默认限流冷却时长(ms):调用方未传 rateLimitWaitMs 时的兜底值(与配置默认一致)。 */
10
+ export declare const RATE_LIMIT_WAIT_MS_DEFAULT = 60000;
11
+ /**
12
+ * 判定错误信息是否为 429 限流:匹配 429(独立数字)或 rate limit(空格/连字符/
13
+ * 下划线分隔与 camelCase 均可),大小写不敏感。
14
+ */
15
+ export declare function isRateLimitError(message: string): boolean;
16
+ /** 记录一次 429 限流:把冷却期起点更新为当前时间。 */
17
+ export declare function noteRateLimit(): void;
18
+ /**
19
+ * 限流等待门:处于 429 冷却期(最近一次 429 + waitMs 未到)时等待到期限,
20
+ * 通过后返回 true;等待期间 signal 中止返回 false。未遇过限流或冷却期已过
21
+ * 立即放行。waitMs ≤ 0 视为不限流。
22
+ */
23
+ export declare function gateRateLimit(waitMs: number, signal?: AbortSignal): Promise<boolean>;
24
+ /** 重置限流门状态(仅测试使用:用例间隔离)。 */
25
+ export declare function resetRateLimitGate(): void;
26
+ //# sourceMappingURL=rate-limit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../src/rate-limit.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,yDAAyD;AACzD,eAAO,MAAM,0BAA0B,QAAQ,CAAC;AAEhD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED,iCAAiC;AACjC,wBAAgB,aAAa,IAAI,IAAI,CAEpC;AA4BD;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAW1F;AAED,4BAA4B;AAC5B,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC"}
package/dist/recall.d.ts CHANGED
@@ -6,14 +6,16 @@
6
6
  * recall 自身不设输出上限:超大的工具结果由 tool-result-pruner 裁剪(pruneContent),
7
7
  * 输出 token 由 pruner 配置控制。
8
8
  *
9
- * 参数由 zod schema(recallArgsSchema)在 execute 入口校验:start 必填(number),
10
- * end/offset 至少提供一个;非法参数抛出可读错误。
9
+ * 参数由 zod schema(recallArgsSchema)统一描述:wire 参数 JSON Schema(根 type:'object',
10
+ * 各字段描述来自 .describe())直接发给模型,execute 入口再做运行时校验(start 必填;
11
+ * end/offset 至少提供一个;非法参数抛出可读错误)。
11
12
  */
12
13
  import { z } from 'zod';
13
14
  import type { ToolDefinition } from './types.ts';
14
15
  /**
15
16
  * recall 工具参数 schema:start 必填(number);end 与 offset 至少提供一个
16
17
  * (二者同时给出时 end 优先,与 execute 语义一致);未知键自动剥离。
18
+ * 各字段描述经 .describe() 透传到 wire JSON Schema(生成见 json-schema.ts)。
17
19
  */
18
20
  export declare const recallArgsSchema: z.ZodObject<{
19
21
  start: z.ZodNumber;
@@ -1 +1 @@
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,CAoFzE"}
1
+ {"version":3,"file":"recall.d.ts","sourceRoot":"","sources":["../src/recall.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,KAAK,EAAE,cAAc,EAAkB,MAAM,YAAY,CAAC;AAGjE;;;;GAIG;AACH,eAAO,MAAM,gBAAgB;;;;iBAYzB,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,CAsEzE"}
@@ -6,6 +6,8 @@
6
6
  *
7
7
  * - 参数:query 必填;top_k(默认 3,1-10);start/end/offset 限定检索区间
8
8
  * (意义同 recall:start 为基准边界,end 与 offset 二选一;end 优先)。
9
+ * wire 参数 JSON Schema 由本 schema 经 toJSONSchema 生成(各字段描述来自 .describe(),
10
+ * 见 json-schema.ts)。
9
11
  * - 区间缺省(start 未提供)→ 检索全部消息;区间不合法(start/end 越界等)→
10
12
  * 不报错,回退全量检索并在输出中明确告知(模型可见)。
11
13
  * - 向量:本地 ONNX embedding(embedding.ts,懒加载 + 批量);相似度 = cosine。
@@ -1 +1 @@
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,6HAAyB,CAAC;AAEvE,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,CAqHjB"}
1
+ {"version":3,"file":"semantic-recall.d.ts","sourceRoot":"","sources":["../src/semantic-recall.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAoB,KAAK,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAG/F,OAAO,KAAK,EAAmB,cAAc,EAAkB,MAAM,YAAY,CAAC;AAGlF,qEAAqE;AACrE,eAAO,MAAM,wBAAwB;;;;;;iBA6BjC,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,6HAAyB,CAAC;AAEvE,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,CA8FjB"}
@@ -89,9 +89,13 @@ export declare const SUMMARY_DEFAULT_MAX_ATTEMPTS = 11;
89
89
  * 失败(抛异常 / 空输出 / 非 stop 结束 / 校验不通过)均记录日志并重试,总共最多尝试
90
90
  * options.maxAttempts 次(默认 SUMMARY_DEFAULT_MAX_ATTEMPTS);全部尝试失败返回 null
91
91
  * (不产生任何日志变更)。输出长度受 maxTokens 限制。
92
+ * 每次请求发出前先过全局限流等待门(gateRateLimit):任一请求遇 429 后,后续所有
93
+ * 摘要请求(含并行中的其他调用方)在「最近一次 429 + options.rateLimitWaitMs」之前
94
+ * 不会发出(缺省 RATE_LIMIT_WAIT_MS_DEFAULT)。
92
95
  */
93
96
  export declare function runSummarySubagent(ctx: Context, agent: Agent, instruction: string, contextText: string | undefined, maxTokens: number, target: RoutedTarget, debug: boolean, signal?: AbortSignal, options?: {
94
97
  maxAttempts?: number;
95
98
  expected?: SummaryValidationRange;
99
+ rateLimitWaitMs?: number;
96
100
  }): Promise<SummarySubagentResult | null>;
97
101
  //# sourceMappingURL=summarize.d.ts.map
@@ -1 +1 @@
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;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,MAAM,CAiDxE;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;IACnB,4DAA4D;IAC5D,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AA8EF,gDAAgD;AAChD,eAAO,MAAM,kBAAkB,KAAK,CAAC;AAErC,0DAA0D;AAC1D,eAAO,MAAM,mBAAmB,yrBAA6K,CAAC;AAE9M,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"}
1
+ {"version":3,"file":"summarize.d.ts","sourceRoot":"","sources":["../src/summarize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAmBH,OAAO,KAAK,EAAE,KAAK,EAAmB,OAAO,EAAE,OAAO,EAAE,UAAU,EAAe,MAAM,YAAY,CAAC;AACpG,OAAO,EAAE,KAAK,YAAY,EAAQ,MAAM,YAAY,CAAC;AAErD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,MAAM,CAiDxE;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;IACnB,4DAA4D;IAC5D,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AA8EF,gDAAgD;AAChD,eAAO,MAAM,kBAAkB,KAAK,CAAC;AAErC,0DAA0D;AAC1D,eAAO,MAAM,mBAAmB,yrBAA6K,CAAC;AAE9M,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;;;;;;;;GAQG;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,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9F,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAgGvC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-plugin-om",
3
- "version": "0.0.20",
3
+ "version": "0.0.21",
4
4
  "type": "module",
5
5
  "main": "./dist/index.mjs",
6
6
  "module": "./dist/index.mjs",