@vibe-lark/larkpal 0.1.73 → 0.1.74

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 +150 -7
  2. package/package.json +1 -1
package/dist/main.mjs CHANGED
@@ -782,7 +782,10 @@ function getToolDisplayName(toolName) {
782
782
  * - parseError(error, rawLine) — 解析错误(不中断流)
783
783
  */
784
784
  const log$36 = larkLogger("cc-runtime/stream-parser");
785
+ const MAX_TOOL_RESULT_CONTENT_CHARS = 8e3;
785
786
  var CCStreamParser = class extends EventEmitter {
787
+ toolNamesById = /* @__PURE__ */ new Map();
788
+ declaredTools = null;
786
789
  /**
787
790
  * 解析一行 NDJSON 文本
788
791
  *
@@ -830,6 +833,7 @@ var CCStreamParser = class extends EventEmitter {
830
833
  subtype: msg.subtype,
831
834
  detail: JSON.stringify(msg).slice(0, 500)
832
835
  });
836
+ this.handleSystem(msg);
833
837
  this.emit("system", msg);
834
838
  break;
835
839
  default:
@@ -858,6 +862,7 @@ var CCStreamParser = class extends EventEmitter {
858
862
  toolUseId: block?.id
859
863
  });
860
864
  if (block?.type === "tool_use" && block.name) {
865
+ this.recordToolUse(block.name, block.id);
861
866
  log$36.info("工具调用开始", {
862
867
  toolName: block.name,
863
868
  displayName: getToolDisplayName(block.name),
@@ -905,6 +910,7 @@ var CCStreamParser = class extends EventEmitter {
905
910
  });
906
911
  if (Array.isArray(content)) {
907
912
  for (const block of content) if (block.type === "tool_use" && block.name) {
913
+ this.recordToolUse(block.name, block.id);
908
914
  log$36.info("从 assistant 消息提取工具调用", {
909
915
  toolName: block.name,
910
916
  displayName: getToolDisplayName(block.name),
@@ -924,10 +930,46 @@ var CCStreamParser = class extends EventEmitter {
924
930
  const content = msg.message?.content;
925
931
  if (!Array.isArray(content)) return;
926
932
  for (const item of content) if (item.type === "tool_result" && item.tool_use_id) {
927
- log$36.debug("工具结果返回", { toolUseId: item.tool_use_id });
928
- this.emit("toolResult", item.tool_use_id);
933
+ const result = this.buildToolResultSummary(item, msg.toolUseResult);
934
+ log$36.debug("工具结果返回", {
935
+ toolUseId: item.tool_use_id,
936
+ toolName: result.toolName,
937
+ isError: result.isError,
938
+ truncated: result.truncated
939
+ });
940
+ this.emit("toolResult", item.tool_use_id, result);
941
+ }
942
+ }
943
+ handleSystem(msg) {
944
+ if (msg.subtype !== "init" || !Array.isArray(msg.tools)) return;
945
+ this.declaredTools = new Set(msg.tools);
946
+ }
947
+ recordToolUse(toolName, toolUseId) {
948
+ if (toolUseId) this.toolNamesById.set(toolUseId, toolName);
949
+ if (this.declaredTools && !this.declaredTools.has(toolName)) {
950
+ log$36.warn("模型请求了未声明工具", {
951
+ toolName,
952
+ toolUseId
953
+ });
954
+ this.emit("unknownToolUse", toolName, toolUseId);
929
955
  }
930
956
  }
957
+ buildToolResultSummary(item, toolUseResult) {
958
+ const serializedContent = serializeToolResultContent(item.content);
959
+ const truncatedContent = truncateToolResultContent(serializedContent);
960
+ const toolUseResultSummary = summarizeToolUseResult(toolUseResult);
961
+ return {
962
+ toolCallId: item.tool_use_id,
963
+ toolName: this.toolNamesById.get(item.tool_use_id),
964
+ rawType: "tool_result",
965
+ isError: item.is_error,
966
+ content: truncatedContent.content,
967
+ resultSummary: extractToolResultSummary(serializedContent, toolUseResultSummary),
968
+ truncated: truncatedContent.truncated || toolUseResultSummary.truncated,
969
+ originalSize: Math.max(serializedContent.length, toolUseResultSummary.originalSize),
970
+ toolUseResult: toolUseResultSummary.summary
971
+ };
972
+ }
931
973
  /**
932
974
  * 处理 tool_progress 消息 — 工具执行进度
933
975
  */
@@ -959,6 +1001,52 @@ var CCStreamParser = class extends EventEmitter {
959
1001
  });
960
1002
  }
961
1003
  };
1004
+ function serializeToolResultContent(content) {
1005
+ if (typeof content === "string") return content;
1006
+ return safeJsonStringify(content);
1007
+ }
1008
+ function summarizeToolUseResult(value) {
1009
+ if (value === void 0) return {
1010
+ originalSize: 0,
1011
+ truncated: false
1012
+ };
1013
+ const serialized = typeof value === "string" ? value : safeJsonStringify(value);
1014
+ const truncated = truncateToolResultContent(serialized);
1015
+ return {
1016
+ summary: typeof value === "string" ? truncated.content : tryParseJson$1(truncated.content) ?? truncated.content,
1017
+ originalSize: serialized.length,
1018
+ truncated: truncated.truncated
1019
+ };
1020
+ }
1021
+ function truncateToolResultContent(content) {
1022
+ if (content.length <= MAX_TOOL_RESULT_CONTENT_CHARS) return {
1023
+ content,
1024
+ truncated: false
1025
+ };
1026
+ return {
1027
+ content: content.slice(0, MAX_TOOL_RESULT_CONTENT_CHARS),
1028
+ truncated: true
1029
+ };
1030
+ }
1031
+ function extractToolResultSummary(content, toolUseResult) {
1032
+ const text = (typeof toolUseResult.summary === "string" ? toolUseResult.summary : toolUseResult.summary === void 0 ? void 0 : safeJsonStringify(toolUseResult.summary)) || content;
1033
+ const summary = (text.match(/<tool_use_error>([\s\S]*?)<\/tool_use_error>/)?.[1] || text).trim();
1034
+ return summary ? truncateToolResultContent(summary).content : void 0;
1035
+ }
1036
+ function safeJsonStringify(value) {
1037
+ try {
1038
+ return JSON.stringify(value);
1039
+ } catch {
1040
+ return String(value);
1041
+ }
1042
+ }
1043
+ function tryParseJson$1(value) {
1044
+ try {
1045
+ return JSON.parse(value);
1046
+ } catch {
1047
+ return;
1048
+ }
1049
+ }
962
1050
  //#endregion
963
1051
  //#region src/cc-runtime/process-manager.ts
964
1052
  /**
@@ -1416,8 +1504,11 @@ var SessionProcessManager = class {
1416
1504
  parser.on("toolUseStart", (toolName, toolInput) => {
1417
1505
  getCallbacks()?.onToolUseStart?.(toolName, toolInput);
1418
1506
  });
1419
- parser.on("toolResult", (toolUseId) => {
1420
- getCallbacks()?.onToolResult?.(toolUseId);
1507
+ parser.on("toolResult", (toolUseId, result) => {
1508
+ getCallbacks()?.onToolResult?.(toolUseId, result);
1509
+ });
1510
+ parser.on("unknownToolUse", (toolName, toolUseId) => {
1511
+ getCallbacks()?.onUnknownToolUse?.(toolName, toolUseId);
1421
1512
  });
1422
1513
  parser.on("toolProgress", (toolName, elapsedSeconds) => {
1423
1514
  getCallbacks()?.onToolProgress?.(toolName, elapsedSeconds);
@@ -3732,6 +3823,9 @@ function serializeChatRun(run) {
3732
3823
  lastEventAt: run.lastEventAt,
3733
3824
  lastEventType: run.lastEventType,
3734
3825
  lastToolName: run.lastToolName,
3826
+ lastToolError: run.lastToolError,
3827
+ unknownToolCallCount: run.unknownToolCallCount,
3828
+ lastUnknownToolName: run.lastUnknownToolName,
3735
3829
  idleSeconds,
3736
3830
  adapterBusy: run.status === "running" ? run.adapterBusy : false,
3737
3831
  processStatus,
@@ -4244,6 +4338,29 @@ function isPathInside(parent, child) {
4244
4338
  const path = relative(parent, child);
4245
4339
  return path !== "" && !path.startsWith("..") && !isAbsolute(path);
4246
4340
  }
4341
+ function buildToolResultPayload(result, resultSummary) {
4342
+ if (!result || typeof result !== "object" || Array.isArray(result)) return { result: resultSummary };
4343
+ const record = result;
4344
+ return {
4345
+ rawType: record.rawType,
4346
+ isError: record.isError,
4347
+ content: record.content,
4348
+ resultSummary: record.resultSummary ?? resultSummary,
4349
+ truncated: record.truncated,
4350
+ originalSize: record.originalSize,
4351
+ result: resultSummary
4352
+ };
4353
+ }
4354
+ function readStringField(value, key) {
4355
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
4356
+ const field = value[key];
4357
+ return typeof field === "string" ? field : void 0;
4358
+ }
4359
+ function readBooleanField(value, key) {
4360
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
4361
+ const field = value[key];
4362
+ return typeof field === "boolean" ? field : void 0;
4363
+ }
4247
4364
  /**
4248
4365
  * 创建 Chat 流式对话 + 历史查询路由
4249
4366
  *
@@ -4594,8 +4711,12 @@ function createChatRouter(config) {
4594
4711
  if (run.status !== "running") return;
4595
4712
  recordRunEvent(run, "tool-result");
4596
4713
  const resultSummary = summarizeForAudit(result);
4714
+ const toolName = readStringField(result, "toolName") || run.lastToolName;
4715
+ const isError = readBooleanField(result, "isError");
4716
+ if (isError) run.lastToolError = resultSummary;
4597
4717
  if (runtimeConfig.requestContext) logChatAudit(buildAuditEvent(runtimeConfig.requestContext, "tool_call_finished", {
4598
4718
  toolCallId: toolUseId,
4719
+ toolName,
4599
4720
  resultSummary,
4600
4721
  metadata: buildToolResultAuditMetadata(result)
4601
4722
  }));
@@ -4604,7 +4725,8 @@ function createChatRouter(config) {
4604
4725
  role: "tool",
4605
4726
  content: JSON.stringify({
4606
4727
  toolUseId,
4607
- result: resultSummary
4728
+ toolName,
4729
+ ...buildToolResultPayload(result, resultSummary)
4608
4730
  }),
4609
4731
  channel: "web",
4610
4732
  metadata: {
@@ -4614,12 +4736,33 @@ function createChatRouter(config) {
4614
4736
  scenarioId,
4615
4737
  runtimeEventType: "tool-result",
4616
4738
  toolCallId: toolUseId,
4617
- toolResult: resultSummary
4739
+ toolName,
4740
+ toolResult: resultSummary,
4741
+ isError
4618
4742
  }
4619
4743
  }, "[stream] 保存 tool result 消息失败");
4620
4744
  broadcastRunEvent(run, "tool-result", {
4621
4745
  toolUseId,
4622
- result: resultSummary
4746
+ toolName,
4747
+ ...buildToolResultPayload(result, resultSummary)
4748
+ });
4749
+ },
4750
+ onUnknownToolUse: (toolName, toolUseId) => {
4751
+ if (run.status !== "running") return;
4752
+ run.unknownToolCallCount = (run.unknownToolCallCount ?? 0) + 1;
4753
+ run.lastUnknownToolName = toolName;
4754
+ run.lastToolError = {
4755
+ isError: true,
4756
+ reasonCode: "UNKNOWN_TOOL_CALL",
4757
+ toolName,
4758
+ toolCallId: toolUseId
4759
+ };
4760
+ recordRunEvent(run, "unknown-tool-use", { toolName });
4761
+ broadcastRunEvent(run, "runtime-event", {
4762
+ type: "unknown-tool-use",
4763
+ toolName,
4764
+ toolUseId,
4765
+ unknownToolCallCount: run.unknownToolCallCount
4623
4766
  });
4624
4767
  },
4625
4768
  onToolProgress: (toolName, elapsedSeconds) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibe-lark/larkpal",
3
- "version": "0.1.73",
3
+ "version": "0.1.74",
4
4
  "description": "LarkPal - Lark/Feishu bot service",
5
5
  "type": "module",
6
6
  "main": "./dist/main.mjs",