@vibe-lark/larkpal 0.1.80 → 0.1.82

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 (2) hide show
  1. package/dist/main.mjs +55 -16
  2. package/package.json +1 -1
package/dist/main.mjs CHANGED
@@ -22,7 +22,6 @@ import { pipeline } from "node:stream/promises";
22
22
  import { PassThrough, Readable, Transform } from "node:stream";
23
23
  import express, { Router } from "express";
24
24
  import Busboy from "busboy";
25
- import { EventEmitter as EventEmitter$1 } from "events";
26
25
  import cron from "node-cron";
27
26
  import * as Lark from "@larksuiteoapi/node-sdk";
28
27
  import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/account-id";
@@ -894,7 +893,7 @@ var CCStreamParser = class extends EventEmitter {
894
893
  displayName: getToolDisplayName(block.name),
895
894
  toolUseId: block.id
896
895
  });
897
- this.emit("toolUseStart", block.name, block.input ?? {});
896
+ this.emit("toolUseStart", block.name, block.input ?? {}, block.id);
898
897
  }
899
898
  break;
900
899
  }
@@ -942,7 +941,7 @@ var CCStreamParser = class extends EventEmitter {
942
941
  displayName: getToolDisplayName(block.name),
943
942
  toolUseId: block.id
944
943
  });
945
- this.emit("toolUseStart", block.name, block.input ?? {});
944
+ this.emit("toolUseStart", block.name, block.input ?? {}, block.id);
946
945
  }
947
946
  }
948
947
  this.emit("assistant", msg);
@@ -1757,8 +1756,8 @@ var SessionProcessManager = class {
1757
1756
  }
1758
1757
  getCallbacks()?.onThinkingDelta?.(text);
1759
1758
  });
1760
- parser.on("toolUseStart", (toolName, toolInput) => {
1761
- getCallbacks()?.onToolUseStart?.(toolName, toolInput);
1759
+ parser.on("toolUseStart", (toolName, toolInput, toolUseId) => {
1760
+ getCallbacks()?.onToolUseStart?.(toolName, toolInput, toolUseId);
1762
1761
  });
1763
1762
  parser.on("toolResult", (toolUseId, result) => {
1764
1763
  getCallbacks()?.onToolResult?.(toolUseId, result);
@@ -4779,6 +4778,14 @@ function normalizeRuntimeResult(result) {
4779
4778
  error
4780
4779
  };
4781
4780
  }
4781
+ function shouldTreatUnknownToolErrorAsRecovered(run, normalizedResult, result) {
4782
+ if (!normalizedResult.isError || normalizedResult.finalStatus !== "error_during_execution") return false;
4783
+ if (!run.unknownToolCallCount || run.lastToolError !== void 0) return false;
4784
+ if (!run.lastToolName || run.lastToolName === run.lastUnknownToolName) return false;
4785
+ const terminalText = normalizeWhitespace(result.result || "");
4786
+ if (terminalText && /\bNo such tool available\b/i.test(terminalText)) return false;
4787
+ return Boolean(run.text.trim() || terminalText);
4788
+ }
4782
4789
  function buildRuntimeErrorSummary(subtype, result) {
4783
4790
  const message = normalizeWhitespace(result || `Runtime execution failed: ${subtype}`);
4784
4791
  const httpStatus = extractHttpStatus(message);
@@ -4874,6 +4881,11 @@ function readBooleanField(value, key) {
4874
4881
  const field = value[key];
4875
4882
  return typeof field === "boolean" ? field : void 0;
4876
4883
  }
4884
+ function isUnknownToolResult(result) {
4885
+ const summary = readStringField(result, "resultSummary") ?? "";
4886
+ const content = readStringField(result, "content") ?? "";
4887
+ return /\bNo such tool available\b/i.test(`${summary}\n${content}`);
4888
+ }
4877
4889
  /**
4878
4890
  * 创建 Chat 流式对话 + 历史查询路由
4879
4891
  *
@@ -5194,10 +5206,11 @@ function createChatRouter(config) {
5194
5206
  recordRunEvent(run, "thinking-delta");
5195
5207
  broadcastRunEvent(run, "thinking-delta", { text });
5196
5208
  },
5197
- onToolUseStart: (toolName, toolInput) => {
5209
+ onToolUseStart: (toolName, toolInput, toolUseId) => {
5198
5210
  if (run.status !== "running") return;
5199
5211
  recordRunEvent(run, "tool-use-start", { toolName });
5200
5212
  if (runtimeConfig.requestContext) logChatAudit(buildAuditEvent(runtimeConfig.requestContext, "tool_call_started", {
5213
+ toolCallId: toolUseId,
5201
5214
  toolName,
5202
5215
  inputSummary: summarizeForAudit(toolInput)
5203
5216
  }));
@@ -5215,11 +5228,13 @@ function createChatRouter(config) {
5215
5228
  traceId,
5216
5229
  scenarioId,
5217
5230
  runtimeEventType: "tool-use-start",
5231
+ toolCallId: toolUseId,
5218
5232
  toolName
5219
5233
  }
5220
5234
  }, "[stream] 保存 tool 消息失败");
5221
5235
  broadcastRunEvent(run, "tool-use-start", {
5222
5236
  toolName,
5237
+ toolUseId,
5223
5238
  input: toolInput
5224
5239
  });
5225
5240
  },
@@ -5229,7 +5244,8 @@ function createChatRouter(config) {
5229
5244
  const resultSummary = summarizeForAudit(result);
5230
5245
  const toolName = readStringField(result, "toolName") || run.lastToolName;
5231
5246
  const isError = readBooleanField(result, "isError");
5232
- if (isError) run.lastToolError = resultSummary;
5247
+ if (isError && !isUnknownToolResult(result)) run.lastToolError = resultSummary;
5248
+ else if (!isError) run.lastToolError = void 0;
5233
5249
  if (runtimeConfig.requestContext) logChatAudit(buildAuditEvent(runtimeConfig.requestContext, "tool_call_finished", {
5234
5250
  toolCallId: toolUseId,
5235
5251
  toolName,
@@ -5267,12 +5283,6 @@ function createChatRouter(config) {
5267
5283
  if (run.status !== "running") return;
5268
5284
  run.unknownToolCallCount = (run.unknownToolCallCount ?? 0) + 1;
5269
5285
  run.lastUnknownToolName = toolName;
5270
- run.lastToolError = {
5271
- isError: true,
5272
- reasonCode: "UNKNOWN_TOOL_CALL",
5273
- toolName,
5274
- toolCallId: toolUseId
5275
- };
5276
5286
  recordRunEvent(run, "unknown-tool-use", { toolName });
5277
5287
  broadcastRunEvent(run, "runtime-event", {
5278
5288
  type: "unknown-tool-use",
@@ -5298,8 +5308,14 @@ function createChatRouter(config) {
5298
5308
  onResult: async (result) => {
5299
5309
  if (run.status !== "running") return;
5300
5310
  recordRunEvent(run, "result");
5301
- const normalizedResult = normalizeRuntimeResult(result);
5311
+ let normalizedResult = normalizeRuntimeResult(result);
5302
5312
  const partialText = run.text.trim() ? run.text : void 0;
5313
+ if (shouldTreatUnknownToolErrorAsRecovered(run, normalizedResult, result)) normalizedResult = {
5314
+ status: "completed",
5315
+ finalStatus: "completed_with_warnings",
5316
+ isError: false,
5317
+ finalText: partialText || result.result
5318
+ };
5303
5319
  const finalText = normalizedResult.isError ? normalizedResult.finalText || partialText || "" : partialText || normalizedResult.finalText || "";
5304
5320
  run.text = finalText;
5305
5321
  run.runtimeError = normalizedResult.error;
@@ -7794,13 +7810,17 @@ const sessionNoReplyFlags = /* @__PURE__ */ new Map();
7794
7810
  /** TTL: 30 分钟 */
7795
7811
  const TTL_MS = 1800 * 1e3;
7796
7812
  /** 定期清理过期的 pending requests(每 5 分钟检查一次) */
7797
- setInterval(() => {
7813
+ function cleanupExpiredPendingRequests() {
7798
7814
  const now = Date.now();
7799
7815
  let cleaned = 0;
7800
7816
  for (const [id, req] of pendingRequests) if (now - req.createdAt > TTL_MS) {
7801
7817
  pendingRequests.delete(id);
7802
7818
  cleaned++;
7803
7819
  }
7820
+ return cleaned;
7821
+ }
7822
+ setInterval(() => {
7823
+ const cleaned = cleanupExpiredPendingRequests();
7804
7824
  if (cleaned > 0) logger$4.info("TTL cleanup completed", {
7805
7825
  cleaned,
7806
7826
  remaining: pendingRequests.size
@@ -7811,7 +7831,7 @@ setInterval(() => {
7811
7831
  * 事件名: `callback:${sessionId}`,payload 为 PendingMcpRequest。
7812
7832
  * 用于 dispatch-cc 订阅并在收到 ask_user/request_permission 回调时发送飞书卡片。
7813
7833
  */
7814
- const onMcpCallback = new EventEmitter$1();
7834
+ const onMcpCallback = new EventEmitter();
7815
7835
  onMcpCallback.setMaxListeners(100);
7816
7836
  /**
7817
7837
  * 将 result 存入对应的 pending request
@@ -7943,6 +7963,25 @@ function createMcpCallbackRouter() {
7943
7963
  requestId
7944
7964
  });
7945
7965
  });
7966
+ router.get("/pending", (req, res) => {
7967
+ const sessionId = typeof req.query.session_id === "string" ? req.query.session_id : typeof req.query.sessionId === "string" ? req.query.sessionId : void 0;
7968
+ const cleaned = cleanupExpiredPendingRequests();
7969
+ const now = Date.now();
7970
+ const requests = [...pendingRequests.values()].filter((pending) => pending.result === void 0).filter((pending) => !sessionId || pending.sessionId === sessionId).map((pending) => ({
7971
+ requestId: pending.requestId,
7972
+ tool: pending.tool,
7973
+ sessionId: pending.sessionId,
7974
+ params: pending.params,
7975
+ createdAt: pending.createdAt,
7976
+ waitingMs: now - pending.createdAt
7977
+ }));
7978
+ logger$4.debug("pending requests listed", {
7979
+ sessionId,
7980
+ count: requests.length,
7981
+ cleaned
7982
+ });
7983
+ res.json({ requests });
7984
+ });
7946
7985
  router.get("/resolve/:requestId", (req, res) => {
7947
7986
  const requestId = req.params.requestId;
7948
7987
  logger$4.debug("resolve poll", { requestId });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibe-lark/larkpal",
3
- "version": "0.1.80",
3
+ "version": "0.1.82",
4
4
  "description": "LarkPal - Lark/Feishu bot service",
5
5
  "type": "module",
6
6
  "main": "./dist/main.mjs",