linkque-cli-v2 1.1.2 → 1.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (15) hide show
  1. package/package.json +1 -1
  2. package/vendor/linkque-agent-appwrite-integrate/dist/esm/{anthropic-messages-B5T6TFD2.js → anthropic-messages-YOPI234A.js} +1 -1
  3. package/vendor/linkque-agent-appwrite-integrate/dist/esm/{azure-openai-responses-S7HNQOSE.js → azure-openai-responses-67YPFLZQ.js} +2 -2
  4. package/vendor/linkque-agent-appwrite-integrate/dist/esm/{chunk-IKZ25GJD.js → chunk-LSBJJGJC.js} +1 -1
  5. package/vendor/linkque-agent-appwrite-integrate/dist/esm/{chunk-3S3TOEBZ.js → chunk-Y3G4J3TB.js} +1 -0
  6. package/vendor/linkque-agent-appwrite-integrate/dist/esm/{chunk-XGIMLCNP.js → chunk-YAKPGLYU.js} +160 -44
  7. package/vendor/linkque-agent-appwrite-integrate/dist/esm/{google-generative-ai-IOXNKFEV.js → google-generative-ai-R5DASQKW.js} +1 -1
  8. package/vendor/linkque-agent-appwrite-integrate/dist/esm/{google-vertex-U4ZV5IXZ.js → google-vertex-OLX2NFGJ.js} +1 -1
  9. package/vendor/linkque-agent-appwrite-integrate/dist/esm/{mistral-conversations-G3K7SSWR.js → mistral-conversations-L6T7EWC2.js} +1 -1
  10. package/vendor/linkque-agent-appwrite-integrate/dist/esm/{openai-codex-responses-4JJLPTCS.js → openai-codex-responses-7QJMWGY5.js} +2 -2
  11. package/vendor/linkque-agent-appwrite-integrate/dist/esm/{openai-completions-PH4WW6E7.js → openai-completions-75YD6VJJ.js} +1 -1
  12. package/vendor/linkque-agent-appwrite-integrate/dist/esm/{openai-responses-KGWAX6HR.js → openai-responses-G6MVJCGC.js} +2 -2
  13. package/vendor/linkque-agent-appwrite-integrate/dist/esm/runtime/handler/chat.js +2 -2
  14. package/vendor/linkque-agent-appwrite-integrate/dist/esm/runtime/protocol.js +2 -2
  15. package/worker.js +158 -35
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "linkque-cli-v2",
3
- "version": "1.1.2",
3
+ "version": "1.1.4",
4
4
  "description": "Public Linkque CLI bundle for sandbox debugging",
5
5
  "bin": {
6
6
  "linkquejs": "linkquejs.js"
@@ -19,7 +19,7 @@ import {
19
19
  } from "./chunk-Y6UTJIT4.js";
20
20
  import {
21
21
  calculateCost
22
- } from "./chunk-3S3TOEBZ.js";
22
+ } from "./chunk-Y3G4J3TB.js";
23
23
  import {
24
24
  getProviderEnvValue
25
25
  } from "./chunk-OXGCUIKV.js";
@@ -2,7 +2,7 @@ import {
2
2
  convertResponsesMessages,
3
3
  convertResponsesTools,
4
4
  processResponsesStream
5
- } from "./chunk-IKZ25GJD.js";
5
+ } from "./chunk-LSBJJGJC.js";
6
6
  import "./chunk-UFVAKOTZ.js";
7
7
  import {
8
8
  AzureOpenAI
@@ -23,7 +23,7 @@ import {
23
23
  } from "./chunk-Y6UTJIT4.js";
24
24
  import {
25
25
  clampThinkingLevel
26
- } from "./chunk-3S3TOEBZ.js";
26
+ } from "./chunk-Y3G4J3TB.js";
27
27
  import {
28
28
  getProviderEnvValue
29
29
  } from "./chunk-OXGCUIKV.js";
@@ -9,7 +9,7 @@ import {
9
9
  } from "./chunk-CT4G24PS.js";
10
10
  import {
11
11
  calculateCost
12
- } from "./chunk-3S3TOEBZ.js";
12
+ } from "./chunk-Y3G4J3TB.js";
13
13
  import {
14
14
  parseStreamingJson
15
15
  } from "./chunk-DYEQRE6N.js";
@@ -600,6 +600,7 @@ function clampThinkingLevel(model, level) {
600
600
  }
601
601
 
602
602
  export {
603
+ lazyStream,
603
604
  lazyApi,
604
605
  createModels,
605
606
  createProvider,
@@ -132,8 +132,9 @@ import {
132
132
  import {
133
133
  createModels,
134
134
  createProvider,
135
- lazyApi
136
- } from "./chunk-3S3TOEBZ.js";
135
+ lazyApi,
136
+ lazyStream
137
+ } from "./chunk-Y3G4J3TB.js";
137
138
  import {
138
139
  getProviderEnvValue
139
140
  } from "./chunk-OXGCUIKV.js";
@@ -16583,6 +16584,7 @@ var require_dist2 = __commonJS({
16583
16584
  // ../linkque-agent-runtime/dist/esm/core/types.js
16584
16585
  var EDebugLogScope;
16585
16586
  (function(EDebugLogScope2) {
16587
+ EDebugLogScope2["CONFIG"] = "CONFIG";
16586
16588
  EDebugLogScope2["LLM"] = "LLM";
16587
16589
  EDebugLogScope2["PI_EVENT"] = "PI_EVENT";
16588
16590
  EDebugLogScope2["MCP"] = "MCP";
@@ -18647,6 +18649,9 @@ var McpProxyTool = class {
18647
18649
  if (params.describe !== void 0) {
18648
18650
  return this.executeDescribe(params.describe, params.server, signal);
18649
18651
  }
18652
+ if (params.searches !== void 0) {
18653
+ return this.executeBatchSearch(params.searches, params.server);
18654
+ }
18650
18655
  if (params.search !== void 0) {
18651
18656
  return this.executeSearch(params.search, params.server);
18652
18657
  }
@@ -18743,6 +18748,20 @@ ${formatSchema(tool.inputSchema, " ")}`);
18743
18748
  }
18744
18749
  return lines.join("\n").trim();
18745
18750
  }
18751
+ /** `mcp({ searches: [...] })`:一次连接元数据并按 query 分组执行多组搜索。 */
18752
+ async executeBatchSearch(queries, serverHint) {
18753
+ const normalized = [
18754
+ ...new Set(queries.map((query) => query.trim()).filter(Boolean))
18755
+ ].slice(0, MCP_BATCH_SEARCH_MAX_ITEMS);
18756
+ if (normalized.length === 0) {
18757
+ return "Batch search requires at least one non-empty query.";
18758
+ }
18759
+ const specs = serverHint ? this.specsMatching(serverHint) : this.specs;
18760
+ await Promise.all(specs.map((spec) => this.ensureEntry(spec.serverName)));
18761
+ const results = await Promise.all(normalized.map((query) => this.executeSearch(query, serverHint)));
18762
+ return results.map((result, index2) => `Query ${index2 + 1}: "${normalized[index2]}"
18763
+ ${result}`).join("\n\n");
18764
+ }
18746
18765
  /** `mcp({ describe: "tool" })`:输出工具所属 server + 参数 schema。 */
18747
18766
  async executeDescribe(toolName, serverHint, signal) {
18748
18767
  const found = await this.findTool(toolName, serverHint, signal);
@@ -18834,6 +18853,9 @@ function parseProxyArgs(args) {
18834
18853
  out.describe = args.describe;
18835
18854
  if (typeof args.search === "string")
18836
18855
  out.search = args.search;
18856
+ if (Array.isArray(args.searches)) {
18857
+ out.searches = args.searches.filter((query) => typeof query === "string").slice(0, MCP_BATCH_SEARCH_MAX_ITEMS);
18858
+ }
18837
18859
  if (typeof args.tool === "string")
18838
18860
  out.tool = args.tool;
18839
18861
  if (typeof args.server === "string")
@@ -18877,12 +18899,14 @@ function truncate(text, max2) {
18877
18899
  function isRecord(value) {
18878
18900
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
18879
18901
  }
18902
+ var MCP_BATCH_SEARCH_MAX_ITEMS = 5;
18880
18903
  var MCP_PROXY_DESCRIPTION = [
18881
18904
  "MCP \u7F51\u5173:\u53D1\u73B0\u5E76\u8C03\u7528 MCP server \u63D0\u4F9B\u7684\u5DE5\u5177\u3002\u53EF\u7528\u52A8\u4F5C:",
18882
18905
  "- mcp({}) \u6216 mcp({ status: true }):\u67E5\u770B\u6240\u6709 server \u8FDE\u63A5\u72B6\u6001\u4E0E\u5DE5\u5177\u6570\u3002",
18883
18906
  '- mcp({ connect: "server" }):\u8FDE\u63A5\u5E76\u5237\u65B0\u67D0 server \u7684\u5DE5\u5177\u5217\u8868\u3002',
18884
18907
  '- mcp({ server: "name" }):\u5217\u51FA\u8BE5 server \u7684\u5DE5\u5177\u3002',
18885
18908
  '- mcp({ search: "\u5173\u952E\u8BCD" }):\u6309\u540D\u79F0/\u63CF\u8FF0\u6A21\u7CCA\u641C\u7D22\u5DE5\u5177(\u7A7A\u683C\u5206\u8BCD OR)\u3002',
18909
+ '- mcp({ searches: ["\u5173\u952E\u8BCD1", "\u5173\u952E\u8BCD2"] }):\u4E00\u6B21\u6267\u884C\u591A\u7EC4\u641C\u7D22\u5E76\u6309 query \u5206\u7EC4\u8FD4\u56DE(\u6700\u591A 5 \u7EC4)\u3002',
18886
18910
  '- mcp({ describe: "toolName" }):\u67E5\u770B\u67D0\u5DE5\u5177\u7684\u53C2\u6570 schema\u3002',
18887
18911
  '- mcp({ tool: "toolName", args: { ... } }):\u8C03\u7528\u67D0\u5DE5\u5177,args \u4E3A\u5BF9\u8C61\u3002',
18888
18912
  "\u53EF\u7528 server \u540D\u89C1 mcp({}) \u8F93\u51FA\u3002\u4EC5\u5728\u786E\u9700\u8C03\u7528 MCP \u5DE5\u5177\u65F6\u4F7F\u7528\u672C\u5DE5\u5177\u3002",
@@ -18905,6 +18929,13 @@ var MCP_PROXY_INPUT_SCHEMA = {
18905
18929
  type: "string",
18906
18930
  description: "\u6309\u540D\u79F0/\u63CF\u8FF0\u6A21\u7CCA\u641C\u7D22\u5DE5\u5177(\u7A7A\u683C\u5206\u8BCD OR)"
18907
18931
  },
18932
+ searches: {
18933
+ type: "array",
18934
+ description: "\u6279\u91CF\u641C\u7D22\u5173\u952E\u8BCD\uFF1B\u4E00\u6B21\u63D0\u4EA4\u6240\u6709\u5019\u9009 query\uFF0C\u6309 query \u5206\u7EC4\u8FD4\u56DE",
18935
+ minItems: 1,
18936
+ maxItems: MCP_BATCH_SEARCH_MAX_ITEMS,
18937
+ items: { type: "string", minLength: 1 }
18938
+ },
18908
18939
  describe: { type: "string", description: "\u67E5\u770B\u67D0\u5DE5\u5177\u7684\u53C2\u6570 schema" },
18909
18940
  tool: { type: "string", description: "\u8981\u8C03\u7528\u7684\u5DE5\u5177\u540D(\u53EF\u914D\u5408 server \u6D88\u6B67)" },
18910
18941
  args: {
@@ -20153,10 +20184,10 @@ function extractName(args) {
20153
20184
  }
20154
20185
 
20155
20186
  // ../../node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.lazy.js
20156
- var anthropicMessagesApi = () => lazyApi(() => import("./anthropic-messages-B5T6TFD2.js"));
20187
+ var anthropicMessagesApi = () => lazyApi(() => import("./anthropic-messages-YOPI234A.js"));
20157
20188
 
20158
20189
  // ../../node_modules/@earendil-works/pi-ai/dist/api/azure-openai-responses.lazy.js
20159
- var azureOpenAIResponsesApi = () => lazyApi(() => import("./azure-openai-responses-S7HNQOSE.js"));
20190
+ var azureOpenAIResponsesApi = () => lazyApi(() => import("./azure-openai-responses-67YPFLZQ.js"));
20160
20191
 
20161
20192
  // ../../node_modules/@earendil-works/pi-ai/dist/api/bedrock-converse-stream.lazy.js
20162
20193
  var __rewriteRelativeImportExtension = function(path2, preserveJsx) {
@@ -20175,22 +20206,22 @@ var bedrockModuleOverride;
20175
20206
  var bedrockConverseStreamApi = () => lazyApi(async () => bedrockModuleOverride ?? await importNodeOnlyApi("./bedrock-converse-stream.ts"));
20176
20207
 
20177
20208
  // ../../node_modules/@earendil-works/pi-ai/dist/api/google-generative-ai.lazy.js
20178
- var googleGenerativeAIApi = () => lazyApi(() => import("./google-generative-ai-IOXNKFEV.js"));
20209
+ var googleGenerativeAIApi = () => lazyApi(() => import("./google-generative-ai-R5DASQKW.js"));
20179
20210
 
20180
20211
  // ../../node_modules/@earendil-works/pi-ai/dist/api/google-vertex.lazy.js
20181
- var googleVertexApi = () => lazyApi(() => import("./google-vertex-U4ZV5IXZ.js"));
20212
+ var googleVertexApi = () => lazyApi(() => import("./google-vertex-OLX2NFGJ.js"));
20182
20213
 
20183
20214
  // ../../node_modules/@earendil-works/pi-ai/dist/api/mistral-conversations.lazy.js
20184
- var mistralConversationsApi = () => lazyApi(() => import("./mistral-conversations-G3K7SSWR.js"));
20215
+ var mistralConversationsApi = () => lazyApi(() => import("./mistral-conversations-L6T7EWC2.js"));
20185
20216
 
20186
20217
  // ../../node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.lazy.js
20187
- var openAICodexResponsesApi = () => lazyApi(() => import("./openai-codex-responses-4JJLPTCS.js"));
20218
+ var openAICodexResponsesApi = () => lazyApi(() => import("./openai-codex-responses-7QJMWGY5.js"));
20188
20219
 
20189
20220
  // ../../node_modules/@earendil-works/pi-ai/dist/api/openai-completions.lazy.js
20190
- var openAICompletionsApi = () => lazyApi(() => import("./openai-completions-PH4WW6E7.js"));
20221
+ var openAICompletionsApi = () => lazyApi(() => import("./openai-completions-75YD6VJJ.js"));
20191
20222
 
20192
20223
  // ../../node_modules/@earendil-works/pi-ai/dist/api/openai-responses.lazy.js
20193
- var openAIResponsesApi = () => lazyApi(() => import("./openai-responses-KGWAX6HR.js"));
20224
+ var openAIResponsesApi = () => lazyApi(() => import("./openai-responses-G6MVJCGC.js"));
20194
20225
 
20195
20226
  // ../../node_modules/@earendil-works/pi-ai/dist/api/pi-messages.lazy.js
20196
20227
  var piMessagesApi = () => lazyApi(() => import("./pi-messages-ZX3KUWSZ.js"));
@@ -51496,8 +51527,68 @@ var import_yaml2 = __toESM(require_dist(), 1);
51496
51527
  var DEFAULT_MAX_BYTES = 50 * 1024;
51497
51528
  var runtimeBuffer = globalThis.Buffer;
51498
51529
 
51530
+ // ../linkque-agent-runtime/dist/esm/impl/agent/pi/llmRequestThrottle.js
51531
+ var DEFAULT_LLM_REQUEST_MIN_INTERVAL_MS = 1e3;
51532
+ var LlmRequestThrottle = class {
51533
+ minIntervalMs;
51534
+ now;
51535
+ delay;
51536
+ onDelay;
51537
+ queue = Promise.resolve();
51538
+ nextRequestAt = 0;
51539
+ constructor(options = {}) {
51540
+ const configured = options.minIntervalMs ?? DEFAULT_LLM_REQUEST_MIN_INTERVAL_MS;
51541
+ this.minIntervalMs = Number.isFinite(configured) && configured > 0 ? Math.floor(configured) : 0;
51542
+ this.now = options.now ?? Date.now;
51543
+ this.delay = options.delay ?? delayWithSignal;
51544
+ this.onDelay = options.onDelay ?? (() => {
51545
+ });
51546
+ }
51547
+ /** 等到当前请求允许启动;取消信号会中断尚未开始的等待。 */
51548
+ waitForTurn(signal) {
51549
+ const scheduled = this.queue.then(async () => {
51550
+ signal?.throwIfAborted();
51551
+ const delayMs = Math.max(0, this.nextRequestAt - this.now());
51552
+ if (delayMs > 0) {
51553
+ this.onDelay(delayMs);
51554
+ await this.delay(delayMs, signal);
51555
+ }
51556
+ signal?.throwIfAborted();
51557
+ this.nextRequestAt = this.now() + this.minIntervalMs;
51558
+ });
51559
+ this.queue = scheduled.catch(() => void 0);
51560
+ return scheduled;
51561
+ }
51562
+ };
51563
+ function delayWithSignal(delayMs, signal) {
51564
+ return new Promise((resolve, reject) => {
51565
+ if (signal?.aborted) {
51566
+ reject(signal.reason);
51567
+ return;
51568
+ }
51569
+ const timer = setTimeout(() => {
51570
+ signal?.removeEventListener("abort", onAbort);
51571
+ resolve();
51572
+ }, delayMs);
51573
+ const onAbort = () => {
51574
+ clearTimeout(timer);
51575
+ reject(signal?.reason);
51576
+ };
51577
+ signal?.addEventListener("abort", onAbort, { once: true });
51578
+ });
51579
+ }
51580
+
51499
51581
  // ../linkque-agent-runtime/dist/esm/impl/agent/pi/createAgentSession.js
51500
51582
  async function createAgentSession(options) {
51583
+ const llmThrottle = new LlmRequestThrottle({
51584
+ minIntervalMs: options.llmRequestMinIntervalMs ?? DEFAULT_LLM_REQUEST_MIN_INTERVAL_MS,
51585
+ onDelay: (delayMs) => {
51586
+ try {
51587
+ options.debugLog?.(`[llm-throttle] wait ${delayMs}ms before next request`, EDebugLogScope.LLM);
51588
+ } catch {
51589
+ }
51590
+ }
51591
+ });
51501
51592
  const agent = new Agent({
51502
51593
  initialState: {
51503
51594
  model: options.model,
@@ -51517,28 +51608,30 @@ async function createAgentSession(options) {
51517
51608
  // 不 await/转换(否则破坏 stream)。
51518
51609
  streamFn: (model, context, streamOptions) => {
51519
51610
  const logSink = options.debugLog;
51520
- if (!logSink) {
51521
- return options.models.streamSimple(model, context, streamOptions);
51522
- }
51523
51611
  const opts = { ...streamOptions };
51524
- const baseUrl = model.baseUrl ?? "<unknown>";
51525
- const prevOnPayload = opts.onPayload;
51526
- opts.onPayload = async (payload, m) => {
51527
- await prevOnPayload?.(payload, m);
51528
- try {
51529
- logSink(formatHttpLogLine("llm", "req", `POST ${baseUrl} model=${m.id} payload=${summarizeBody(safeStringifyPayload(payload))}`), EDebugLogScope.LLM);
51530
- } catch {
51531
- }
51532
- };
51533
- const prevOnResponse = opts.onResponse;
51534
- opts.onResponse = async (response, m) => {
51535
- await prevOnResponse?.(response, m);
51536
- try {
51537
- logSink(formatHttpLogLine("llm", "resp", `POST ${baseUrl} model=${m.id} ${response.status} headers=${redactHeaders(response.headers)}`), EDebugLogScope.LLM);
51538
- } catch {
51539
- }
51540
- };
51541
- return options.models.streamSimple(model, context, opts);
51612
+ if (logSink) {
51613
+ const baseUrl = model.baseUrl ?? "<unknown>";
51614
+ const prevOnPayload = opts.onPayload;
51615
+ opts.onPayload = async (payload, m) => {
51616
+ await prevOnPayload?.(payload, m);
51617
+ try {
51618
+ logSink(formatHttpLogLine("llm", "req", `POST ${baseUrl} model=${m.id} payload=${summarizeBody(safeStringifyPayload(payload))}`), EDebugLogScope.LLM);
51619
+ } catch {
51620
+ }
51621
+ };
51622
+ const prevOnResponse = opts.onResponse;
51623
+ opts.onResponse = async (response, m) => {
51624
+ await prevOnResponse?.(response, m);
51625
+ try {
51626
+ logSink(formatHttpLogLine("llm", "resp", `POST ${baseUrl} model=${m.id} ${response.status} headers=${redactHeaders(response.headers)}`), EDebugLogScope.LLM);
51627
+ } catch {
51628
+ }
51629
+ };
51630
+ }
51631
+ return lazyStream(model, async () => {
51632
+ await llmThrottle.waitForTurn(opts.signal);
51633
+ return options.models.streamSimple(model, context, opts);
51634
+ });
51542
51635
  },
51543
51636
  getApiKey: options.getApiKey
51544
51637
  });
@@ -52805,6 +52898,8 @@ var AgentRuntime = class _AgentRuntime {
52805
52898
  hookMetricsSink;
52806
52899
  /** 装配期固化的统一诊断 sink(逐 run options.debugLog 可覆盖)。 */
52807
52900
  portsDebugLog;
52901
+ /** 插件处理后、runtime 实际使用的完整 Agent Config JSON 快照。 */
52902
+ effectiveAgentConfigJson;
52808
52903
  // —— 从 IAgentProtocol 提取并固化的运行期默认(经 create 注入)——
52809
52904
  /** systemPrompt 默认(来自 protocol.agent.systemPrompt.content)。 */
52810
52905
  defaultSystemPrompt = "";
@@ -52888,6 +52983,11 @@ var AgentRuntime = class _AgentRuntime {
52888
52983
  rt.agentId = agentConfig.agentId;
52889
52984
  rt.followUpQuestionGenerationEnabled = followUpQuestionGenerationEnabled;
52890
52985
  rt.hookResources = normalizeHookResources(agentConfig.agent.resources.filter((r) => r.resourceType === EResourceType.HOOK));
52986
+ try {
52987
+ rt.effectiveAgentConfigJson = JSON.stringify(agentConfig);
52988
+ } catch {
52989
+ rt.effectiveAgentConfigJson = void 0;
52990
+ }
52891
52991
  return rt;
52892
52992
  }
52893
52993
  async prepareFollowUpQuestionContext(sessionId, history = []) {
@@ -52908,6 +53008,12 @@ var AgentRuntime = class _AgentRuntime {
52908
53008
  async *runAgentLoop(request, auth2, options = {}) {
52909
53009
  const sessionId = options.sessionId;
52910
53010
  const debugLog = options.debugLog ?? this.portsDebugLog;
53011
+ if (debugLog) {
53012
+ try {
53013
+ debugLog(this.effectiveAgentConfigJson === void 0 ? "[agent-config] final=<Agent Config \u5E8F\u5217\u5316\u5931\u8D25\uFF0C\u65E0\u6CD5\u6253\u5370\u5B8C\u6574\u5185\u5BB9>" : `[agent-config] final=${this.effectiveAgentConfigJson}`, EDebugLogScope.CONFIG);
53014
+ } catch {
53015
+ }
53016
+ }
52911
53017
  const newTurns = request.messages.map((m) => ({
52912
53018
  role: m.role,
52913
53019
  content: m.content,
@@ -53015,6 +53121,19 @@ var AgentRuntime = class _AgentRuntime {
53015
53121
  let assistantText = "";
53016
53122
  let failed = false;
53017
53123
  let runError;
53124
+ let terminalHookDispatched = false;
53125
+ const dispatchTerminalHook = async () => {
53126
+ if (terminalHookDispatched || hookDispatcher.isEmpty)
53127
+ return;
53128
+ terminalHookDispatched = true;
53129
+ if (failed) {
53130
+ await hookDispatcher.dispatch(EHookStage.RUN_FAILED, hookCommonParams, {
53131
+ error: runError ?? { message: "unknown error" }
53132
+ });
53133
+ return;
53134
+ }
53135
+ await hookDispatcher.dispatch(EHookStage.RUN_COMPLETED, hookCommonParams, { runDurationMs: Date.now() - runStartedAt });
53136
+ };
53018
53137
  try {
53019
53138
  for await (const ev of this.agentLoop.run(agentReq)) {
53020
53139
  if (ev.type === "delta")
@@ -53022,6 +53141,7 @@ var AgentRuntime = class _AgentRuntime {
53022
53141
  if (ev.type === "error") {
53023
53142
  failed = true;
53024
53143
  runError = { message: ev.error.message, code: ev.error.code };
53144
+ await dispatchTerminalHook();
53025
53145
  }
53026
53146
  if (ev.type === "done" && !failed && sessionId !== void 0) {
53027
53147
  const completedTurns = [
@@ -53036,22 +53156,18 @@ var AgentRuntime = class _AgentRuntime {
53036
53156
  }
53037
53157
  }
53038
53158
  }
53159
+ if (ev.type === "done")
53160
+ await dispatchTerminalHook();
53039
53161
  yield ev;
53040
53162
  }
53041
- if (!hookDispatcher.isEmpty) {
53042
- if (failed) {
53043
- await hookDispatcher.dispatch(EHookStage.RUN_FAILED, hookCommonParams, { error: runError ?? { message: "unknown error" } });
53044
- } else {
53045
- await hookDispatcher.dispatch(EHookStage.RUN_COMPLETED, hookCommonParams, { runDurationMs: Date.now() - runStartedAt });
53046
- }
53047
- }
53163
+ await dispatchTerminalHook();
53048
53164
  } catch (error) {
53049
- if (!hookDispatcher.isEmpty) {
53050
- await hookDispatcher.dispatch(EHookStage.RUN_FAILED, hookCommonParams, {
53051
- error: {
53052
- message: error instanceof Error ? error.message : String(error)
53053
- }
53054
- });
53165
+ if (!terminalHookDispatched) {
53166
+ failed = true;
53167
+ runError = {
53168
+ message: error instanceof Error ? error.message : String(error)
53169
+ };
53170
+ await dispatchTerminalHook();
53055
53171
  }
53056
53172
  throw error;
53057
53173
  } finally {
@@ -24,7 +24,7 @@ import {
24
24
  import {
25
25
  calculateCost,
26
26
  clampThinkingLevel
27
- } from "./chunk-3S3TOEBZ.js";
27
+ } from "./chunk-Y3G4J3TB.js";
28
28
  import {
29
29
  AssistantMessageEventStream
30
30
  } from "./chunk-46SEH6ER.js";
@@ -26,7 +26,7 @@ import {
26
26
  import {
27
27
  calculateCost,
28
28
  clampThinkingLevel
29
- } from "./chunk-3S3TOEBZ.js";
29
+ } from "./chunk-Y3G4J3TB.js";
30
30
  import {
31
31
  getProviderEnvValue
32
32
  } from "./chunk-OXGCUIKV.js";
@@ -73,7 +73,7 @@ import {
73
73
  import {
74
74
  calculateCost,
75
75
  clampThinkingLevel
76
- } from "./chunk-3S3TOEBZ.js";
76
+ } from "./chunk-Y3G4J3TB.js";
77
77
  import {
78
78
  parseStreamingJson
79
79
  } from "./chunk-DYEQRE6N.js";
@@ -13,7 +13,7 @@ import {
13
13
  convertResponsesMessages,
14
14
  convertResponsesTools,
15
15
  processResponsesStream
16
- } from "./chunk-IKZ25GJD.js";
16
+ } from "./chunk-LSBJJGJC.js";
17
17
  import "./chunk-UFVAKOTZ.js";
18
18
  import {
19
19
  clampOpenAIPromptCacheKey
@@ -31,7 +31,7 @@ import {
31
31
  } from "./chunk-Y6UTJIT4.js";
32
32
  import {
33
33
  clampThinkingLevel
34
- } from "./chunk-3S3TOEBZ.js";
34
+ } from "./chunk-Y3G4J3TB.js";
35
35
  import {
36
36
  getProviderEnvValue
37
37
  } from "./chunk-OXGCUIKV.js";
@@ -25,7 +25,7 @@ import {
25
25
  import {
26
26
  calculateCost,
27
27
  clampThinkingLevel
28
- } from "./chunk-3S3TOEBZ.js";
28
+ } from "./chunk-Y3G4J3TB.js";
29
29
  import {
30
30
  getProviderEnvValue
31
31
  } from "./chunk-OXGCUIKV.js";
@@ -9,7 +9,7 @@ import {
9
9
  convertResponsesMessages,
10
10
  convertResponsesTools,
11
11
  processResponsesStream
12
- } from "./chunk-IKZ25GJD.js";
12
+ } from "./chunk-LSBJJGJC.js";
13
13
  import "./chunk-UFVAKOTZ.js";
14
14
  import {
15
15
  OpenAI
@@ -30,7 +30,7 @@ import {
30
30
  } from "./chunk-Y6UTJIT4.js";
31
31
  import {
32
32
  clampThinkingLevel
33
- } from "./chunk-3S3TOEBZ.js";
33
+ } from "./chunk-Y3G4J3TB.js";
34
34
  import {
35
35
  getProviderEnvValue
36
36
  } from "./chunk-OXGCUIKV.js";
@@ -51,12 +51,12 @@ import {
51
51
  parseConversationRunRequest,
52
52
  parseSkillFile,
53
53
  streamToConversationEvents
54
- } from "../../chunk-XGIMLCNP.js";
54
+ } from "../../chunk-YAKPGLYU.js";
55
55
  import "../../chunk-XUFLSZM4.js";
56
56
  import "../../chunk-I64V3ICJ.js";
57
57
  import "../../chunk-6MHDOBWO.js";
58
58
  import "../../chunk-E2P6TIFG.js";
59
- import "../../chunk-3S3TOEBZ.js";
59
+ import "../../chunk-Y3G4J3TB.js";
60
60
  import "../../chunk-OXGCUIKV.js";
61
61
  import "../../chunk-DYEQRE6N.js";
62
62
  import "../../chunk-46SEH6ER.js";
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  getBakedProtocol,
3
3
  setBakedProtocol
4
- } from "../chunk-XGIMLCNP.js";
4
+ } from "../chunk-YAKPGLYU.js";
5
5
  import "../chunk-XUFLSZM4.js";
6
6
  import "../chunk-I64V3ICJ.js";
7
7
  import "../chunk-6MHDOBWO.js";
8
8
  import "../chunk-E2P6TIFG.js";
9
- import "../chunk-3S3TOEBZ.js";
9
+ import "../chunk-Y3G4J3TB.js";
10
10
  import "../chunk-OXGCUIKV.js";
11
11
  import "../chunk-DYEQRE6N.js";
12
12
  import "../chunk-46SEH6ER.js";
package/worker.js CHANGED
@@ -4981,6 +4981,7 @@ var init_types2 = __esm({
4981
4981
  "../linkque-agent-runtime/dist/esm/core/types.js"() {
4982
4982
  "use strict";
4983
4983
  (function(EDebugLogScope2) {
4984
+ EDebugLogScope2["CONFIG"] = "CONFIG";
4984
4985
  EDebugLogScope2["LLM"] = "LLM";
4985
4986
  EDebugLogScope2["PI_EVENT"] = "PI_EVENT";
4986
4987
  EDebugLogScope2["MCP"] = "MCP";
@@ -15466,6 +15467,9 @@ function parseProxyArgs(args) {
15466
15467
  out.describe = args.describe;
15467
15468
  if (typeof args.search === "string")
15468
15469
  out.search = args.search;
15470
+ if (Array.isArray(args.searches)) {
15471
+ out.searches = args.searches.filter((query) => typeof query === "string").slice(0, MCP_BATCH_SEARCH_MAX_ITEMS);
15472
+ }
15469
15473
  if (typeof args.tool === "string")
15470
15474
  out.tool = args.tool;
15471
15475
  if (typeof args.server === "string")
@@ -15509,7 +15513,7 @@ function truncate(text, max2) {
15509
15513
  function isRecord2(value) {
15510
15514
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
15511
15515
  }
15512
- var MCP_PROXY_TOOL_NAME, McpProxyTool, MCP_PROXY_DESCRIPTION, MCP_PROXY_INPUT_SCHEMA;
15516
+ var MCP_PROXY_TOOL_NAME, McpProxyTool, MCP_BATCH_SEARCH_MAX_ITEMS, MCP_PROXY_DESCRIPTION, MCP_PROXY_INPUT_SCHEMA;
15513
15517
  var init_mcpProxyTool = __esm({
15514
15518
  "../linkque-agent-runtime/dist/esm/core/mcpProxyTool.js"() {
15515
15519
  "use strict";
@@ -15654,6 +15658,9 @@ var init_mcpProxyTool = __esm({
15654
15658
  if (params.describe !== void 0) {
15655
15659
  return this.executeDescribe(params.describe, params.server, signal);
15656
15660
  }
15661
+ if (params.searches !== void 0) {
15662
+ return this.executeBatchSearch(params.searches, params.server);
15663
+ }
15657
15664
  if (params.search !== void 0) {
15658
15665
  return this.executeSearch(params.search, params.server);
15659
15666
  }
@@ -15750,6 +15757,20 @@ ${formatSchema(tool.inputSchema, " ")}`);
15750
15757
  }
15751
15758
  return lines.join("\n").trim();
15752
15759
  }
15760
+ /** `mcp({ searches: [...] })`:一次连接元数据并按 query 分组执行多组搜索。 */
15761
+ async executeBatchSearch(queries, serverHint) {
15762
+ const normalized = [
15763
+ ...new Set(queries.map((query) => query.trim()).filter(Boolean))
15764
+ ].slice(0, MCP_BATCH_SEARCH_MAX_ITEMS);
15765
+ if (normalized.length === 0) {
15766
+ return "Batch search requires at least one non-empty query.";
15767
+ }
15768
+ const specs = serverHint ? this.specsMatching(serverHint) : this.specs;
15769
+ await Promise.all(specs.map((spec) => this.ensureEntry(spec.serverName)));
15770
+ const results = await Promise.all(normalized.map((query) => this.executeSearch(query, serverHint)));
15771
+ return results.map((result, index2) => `Query ${index2 + 1}: "${normalized[index2]}"
15772
+ ${result}`).join("\n\n");
15773
+ }
15753
15774
  /** `mcp({ describe: "tool" })`:输出工具所属 server + 参数 schema。 */
15754
15775
  async executeDescribe(toolName, serverHint, signal) {
15755
15776
  const found = await this.findTool(toolName, serverHint, signal);
@@ -15831,12 +15852,14 @@ ${formatSchema(tool.inputSchema)}`);
15831
15852
  return lines.join("\n").trim();
15832
15853
  }
15833
15854
  };
15855
+ MCP_BATCH_SEARCH_MAX_ITEMS = 5;
15834
15856
  MCP_PROXY_DESCRIPTION = [
15835
15857
  "MCP \u7F51\u5173:\u53D1\u73B0\u5E76\u8C03\u7528 MCP server \u63D0\u4F9B\u7684\u5DE5\u5177\u3002\u53EF\u7528\u52A8\u4F5C:",
15836
15858
  "- mcp({}) \u6216 mcp({ status: true }):\u67E5\u770B\u6240\u6709 server \u8FDE\u63A5\u72B6\u6001\u4E0E\u5DE5\u5177\u6570\u3002",
15837
15859
  '- mcp({ connect: "server" }):\u8FDE\u63A5\u5E76\u5237\u65B0\u67D0 server \u7684\u5DE5\u5177\u5217\u8868\u3002',
15838
15860
  '- mcp({ server: "name" }):\u5217\u51FA\u8BE5 server \u7684\u5DE5\u5177\u3002',
15839
15861
  '- mcp({ search: "\u5173\u952E\u8BCD" }):\u6309\u540D\u79F0/\u63CF\u8FF0\u6A21\u7CCA\u641C\u7D22\u5DE5\u5177(\u7A7A\u683C\u5206\u8BCD OR)\u3002',
15862
+ '- mcp({ searches: ["\u5173\u952E\u8BCD1", "\u5173\u952E\u8BCD2"] }):\u4E00\u6B21\u6267\u884C\u591A\u7EC4\u641C\u7D22\u5E76\u6309 query \u5206\u7EC4\u8FD4\u56DE(\u6700\u591A 5 \u7EC4)\u3002',
15840
15863
  '- mcp({ describe: "toolName" }):\u67E5\u770B\u67D0\u5DE5\u5177\u7684\u53C2\u6570 schema\u3002',
15841
15864
  '- mcp({ tool: "toolName", args: { ... } }):\u8C03\u7528\u67D0\u5DE5\u5177,args \u4E3A\u5BF9\u8C61\u3002',
15842
15865
  "\u53EF\u7528 server \u540D\u89C1 mcp({}) \u8F93\u51FA\u3002\u4EC5\u5728\u786E\u9700\u8C03\u7528 MCP \u5DE5\u5177\u65F6\u4F7F\u7528\u672C\u5DE5\u5177\u3002",
@@ -15859,6 +15882,13 @@ ${formatSchema(tool.inputSchema)}`);
15859
15882
  type: "string",
15860
15883
  description: "\u6309\u540D\u79F0/\u63CF\u8FF0\u6A21\u7CCA\u641C\u7D22\u5DE5\u5177(\u7A7A\u683C\u5206\u8BCD OR)"
15861
15884
  },
15885
+ searches: {
15886
+ type: "array",
15887
+ description: "\u6279\u91CF\u641C\u7D22\u5173\u952E\u8BCD\uFF1B\u4E00\u6B21\u63D0\u4EA4\u6240\u6709\u5019\u9009 query\uFF0C\u6309 query \u5206\u7EC4\u8FD4\u56DE",
15888
+ minItems: 1,
15889
+ maxItems: MCP_BATCH_SEARCH_MAX_ITEMS,
15890
+ items: { type: "string", minLength: 1 }
15891
+ },
15862
15892
  describe: { type: "string", description: "\u67E5\u770B\u67D0\u5DE5\u5177\u7684\u53C2\u6570 schema" },
15863
15893
  tool: { type: "string", description: "\u8981\u8C03\u7528\u7684\u5DE5\u5177\u540D(\u53EF\u914D\u5408 server \u6D88\u6B67)" },
15864
15894
  args: {
@@ -187318,8 +187348,74 @@ var init_dist4 = __esm({
187318
187348
  }
187319
187349
  });
187320
187350
 
187351
+ // ../linkque-agent-runtime/dist/esm/impl/agent/pi/llmRequestThrottle.js
187352
+ function delayWithSignal(delayMs, signal) {
187353
+ return new Promise((resolve, reject) => {
187354
+ if (signal?.aborted) {
187355
+ reject(signal.reason);
187356
+ return;
187357
+ }
187358
+ const timer = setTimeout(() => {
187359
+ signal?.removeEventListener("abort", onAbort);
187360
+ resolve();
187361
+ }, delayMs);
187362
+ const onAbort = () => {
187363
+ clearTimeout(timer);
187364
+ reject(signal?.reason);
187365
+ };
187366
+ signal?.addEventListener("abort", onAbort, { once: true });
187367
+ });
187368
+ }
187369
+ var DEFAULT_LLM_REQUEST_MIN_INTERVAL_MS, LlmRequestThrottle;
187370
+ var init_llmRequestThrottle = __esm({
187371
+ "../linkque-agent-runtime/dist/esm/impl/agent/pi/llmRequestThrottle.js"() {
187372
+ "use strict";
187373
+ DEFAULT_LLM_REQUEST_MIN_INTERVAL_MS = 1e3;
187374
+ LlmRequestThrottle = class {
187375
+ minIntervalMs;
187376
+ now;
187377
+ delay;
187378
+ onDelay;
187379
+ queue = Promise.resolve();
187380
+ nextRequestAt = 0;
187381
+ constructor(options = {}) {
187382
+ const configured = options.minIntervalMs ?? DEFAULT_LLM_REQUEST_MIN_INTERVAL_MS;
187383
+ this.minIntervalMs = Number.isFinite(configured) && configured > 0 ? Math.floor(configured) : 0;
187384
+ this.now = options.now ?? Date.now;
187385
+ this.delay = options.delay ?? delayWithSignal;
187386
+ this.onDelay = options.onDelay ?? (() => {
187387
+ });
187388
+ }
187389
+ /** 等到当前请求允许启动;取消信号会中断尚未开始的等待。 */
187390
+ waitForTurn(signal) {
187391
+ const scheduled = this.queue.then(async () => {
187392
+ signal?.throwIfAborted();
187393
+ const delayMs = Math.max(0, this.nextRequestAt - this.now());
187394
+ if (delayMs > 0) {
187395
+ this.onDelay(delayMs);
187396
+ await this.delay(delayMs, signal);
187397
+ }
187398
+ signal?.throwIfAborted();
187399
+ this.nextRequestAt = this.now() + this.minIntervalMs;
187400
+ });
187401
+ this.queue = scheduled.catch(() => void 0);
187402
+ return scheduled;
187403
+ }
187404
+ };
187405
+ }
187406
+ });
187407
+
187321
187408
  // ../linkque-agent-runtime/dist/esm/impl/agent/pi/createAgentSession.js
187322
187409
  async function createAgentSession(options) {
187410
+ const llmThrottle = new LlmRequestThrottle({
187411
+ minIntervalMs: options.llmRequestMinIntervalMs ?? DEFAULT_LLM_REQUEST_MIN_INTERVAL_MS,
187412
+ onDelay: (delayMs) => {
187413
+ try {
187414
+ options.debugLog?.(`[llm-throttle] wait ${delayMs}ms before next request`, EDebugLogScope.LLM);
187415
+ } catch {
187416
+ }
187417
+ }
187418
+ });
187323
187419
  const agent = new Agent({
187324
187420
  initialState: {
187325
187421
  model: options.model,
@@ -187339,28 +187435,30 @@ async function createAgentSession(options) {
187339
187435
  // 不 await/转换(否则破坏 stream)。
187340
187436
  streamFn: (model, context2, streamOptions) => {
187341
187437
  const logSink = options.debugLog;
187342
- if (!logSink) {
187343
- return options.models.streamSimple(model, context2, streamOptions);
187344
- }
187345
187438
  const opts = { ...streamOptions };
187346
- const baseUrl = model.baseUrl ?? "<unknown>";
187347
- const prevOnPayload = opts.onPayload;
187348
- opts.onPayload = async (payload, m2) => {
187349
- await prevOnPayload?.(payload, m2);
187350
- try {
187351
- logSink(formatHttpLogLine("llm", "req", `POST ${baseUrl} model=${m2.id} payload=${summarizeBody(safeStringifyPayload(payload))}`), EDebugLogScope.LLM);
187352
- } catch {
187353
- }
187354
- };
187355
- const prevOnResponse = opts.onResponse;
187356
- opts.onResponse = async (response, m2) => {
187357
- await prevOnResponse?.(response, m2);
187358
- try {
187359
- logSink(formatHttpLogLine("llm", "resp", `POST ${baseUrl} model=${m2.id} ${response.status} headers=${redactHeaders(response.headers)}`), EDebugLogScope.LLM);
187360
- } catch {
187361
- }
187362
- };
187363
- return options.models.streamSimple(model, context2, opts);
187439
+ if (logSink) {
187440
+ const baseUrl = model.baseUrl ?? "<unknown>";
187441
+ const prevOnPayload = opts.onPayload;
187442
+ opts.onPayload = async (payload, m2) => {
187443
+ await prevOnPayload?.(payload, m2);
187444
+ try {
187445
+ logSink(formatHttpLogLine("llm", "req", `POST ${baseUrl} model=${m2.id} payload=${summarizeBody(safeStringifyPayload(payload))}`), EDebugLogScope.LLM);
187446
+ } catch {
187447
+ }
187448
+ };
187449
+ const prevOnResponse = opts.onResponse;
187450
+ opts.onResponse = async (response, m2) => {
187451
+ await prevOnResponse?.(response, m2);
187452
+ try {
187453
+ logSink(formatHttpLogLine("llm", "resp", `POST ${baseUrl} model=${m2.id} ${response.status} headers=${redactHeaders(response.headers)}`), EDebugLogScope.LLM);
187454
+ } catch {
187455
+ }
187456
+ };
187457
+ }
187458
+ return lazyStream(model, async () => {
187459
+ await llmThrottle.waitForTurn(opts.signal);
187460
+ return options.models.streamSimple(model, context2, opts);
187461
+ });
187364
187462
  },
187365
187463
  getApiKey: options.getApiKey
187366
187464
  });
@@ -187450,9 +187548,11 @@ var init_createAgentSession = __esm({
187450
187548
  "../linkque-agent-runtime/dist/esm/impl/agent/pi/createAgentSession.js"() {
187451
187549
  "use strict";
187452
187550
  init_dist4();
187551
+ init_dist3();
187453
187552
  init_types2();
187454
187553
  init_cardTools();
187455
187554
  init_httpLoggingFetch();
187555
+ init_llmRequestThrottle();
187456
187556
  }
187457
187557
  });
187458
187558
 
@@ -188764,6 +188864,8 @@ var init_agentRuntime = __esm({
188764
188864
  hookMetricsSink;
188765
188865
  /** 装配期固化的统一诊断 sink(逐 run options.debugLog 可覆盖)。 */
188766
188866
  portsDebugLog;
188867
+ /** 插件处理后、runtime 实际使用的完整 Agent Config JSON 快照。 */
188868
+ effectiveAgentConfigJson;
188767
188869
  // —— 从 IAgentProtocol 提取并固化的运行期默认(经 create 注入)——
188768
188870
  /** systemPrompt 默认(来自 protocol.agent.systemPrompt.content)。 */
188769
188871
  defaultSystemPrompt = "";
@@ -188847,6 +188949,11 @@ var init_agentRuntime = __esm({
188847
188949
  rt.agentId = agentConfig.agentId;
188848
188950
  rt.followUpQuestionGenerationEnabled = followUpQuestionGenerationEnabled;
188849
188951
  rt.hookResources = normalizeHookResources(agentConfig.agent.resources.filter((r2) => r2.resourceType === EResourceType.HOOK));
188952
+ try {
188953
+ rt.effectiveAgentConfigJson = JSON.stringify(agentConfig);
188954
+ } catch {
188955
+ rt.effectiveAgentConfigJson = void 0;
188956
+ }
188850
188957
  return rt;
188851
188958
  }
188852
188959
  async prepareFollowUpQuestionContext(sessionId, history = []) {
@@ -188867,6 +188974,12 @@ var init_agentRuntime = __esm({
188867
188974
  async *runAgentLoop(request, auth2, options = {}) {
188868
188975
  const sessionId = options.sessionId;
188869
188976
  const debugLog = options.debugLog ?? this.portsDebugLog;
188977
+ if (debugLog) {
188978
+ try {
188979
+ debugLog(this.effectiveAgentConfigJson === void 0 ? "[agent-config] final=<Agent Config \u5E8F\u5217\u5316\u5931\u8D25\uFF0C\u65E0\u6CD5\u6253\u5370\u5B8C\u6574\u5185\u5BB9>" : `[agent-config] final=${this.effectiveAgentConfigJson}`, EDebugLogScope.CONFIG);
188980
+ } catch {
188981
+ }
188982
+ }
188870
188983
  const newTurns = request.messages.map((m2) => ({
188871
188984
  role: m2.role,
188872
188985
  content: m2.content,
@@ -188974,6 +189087,19 @@ var init_agentRuntime = __esm({
188974
189087
  let assistantText = "";
188975
189088
  let failed = false;
188976
189089
  let runError;
189090
+ let terminalHookDispatched = false;
189091
+ const dispatchTerminalHook = async () => {
189092
+ if (terminalHookDispatched || hookDispatcher.isEmpty)
189093
+ return;
189094
+ terminalHookDispatched = true;
189095
+ if (failed) {
189096
+ await hookDispatcher.dispatch(EHookStage.RUN_FAILED, hookCommonParams, {
189097
+ error: runError ?? { message: "unknown error" }
189098
+ });
189099
+ return;
189100
+ }
189101
+ await hookDispatcher.dispatch(EHookStage.RUN_COMPLETED, hookCommonParams, { runDurationMs: Date.now() - runStartedAt });
189102
+ };
188977
189103
  try {
188978
189104
  for await (const ev of this.agentLoop.run(agentReq)) {
188979
189105
  if (ev.type === "delta")
@@ -188981,6 +189107,7 @@ var init_agentRuntime = __esm({
188981
189107
  if (ev.type === "error") {
188982
189108
  failed = true;
188983
189109
  runError = { message: ev.error.message, code: ev.error.code };
189110
+ await dispatchTerminalHook();
188984
189111
  }
188985
189112
  if (ev.type === "done" && !failed && sessionId !== void 0) {
188986
189113
  const completedTurns = [
@@ -188995,22 +189122,18 @@ var init_agentRuntime = __esm({
188995
189122
  }
188996
189123
  }
188997
189124
  }
189125
+ if (ev.type === "done")
189126
+ await dispatchTerminalHook();
188998
189127
  yield ev;
188999
189128
  }
189000
- if (!hookDispatcher.isEmpty) {
189001
- if (failed) {
189002
- await hookDispatcher.dispatch(EHookStage.RUN_FAILED, hookCommonParams, { error: runError ?? { message: "unknown error" } });
189003
- } else {
189004
- await hookDispatcher.dispatch(EHookStage.RUN_COMPLETED, hookCommonParams, { runDurationMs: Date.now() - runStartedAt });
189005
- }
189006
- }
189129
+ await dispatchTerminalHook();
189007
189130
  } catch (error40) {
189008
- if (!hookDispatcher.isEmpty) {
189009
- await hookDispatcher.dispatch(EHookStage.RUN_FAILED, hookCommonParams, {
189010
- error: {
189011
- message: error40 instanceof Error ? error40.message : String(error40)
189012
- }
189013
- });
189131
+ if (!terminalHookDispatched) {
189132
+ failed = true;
189133
+ runError = {
189134
+ message: error40 instanceof Error ? error40.message : String(error40)
189135
+ };
189136
+ await dispatchTerminalHook();
189014
189137
  }
189015
189138
  throw error40;
189016
189139
  } finally {