@yushaw/sanqian-chat 0.3.1 → 0.3.3

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.
@@ -90,6 +90,7 @@ module.exports = __toCommonJS(renderer_exports);
90
90
  var import_react = require("react");
91
91
 
92
92
  // src/core/tool-status.ts
93
+ var BLOCKING_ACTION_REQUIRED = /* @__PURE__ */ new Set(["install_git_bash"]);
93
94
  function normalizeToolExecutionStatus(status) {
94
95
  if (typeof status !== "string") return void 0;
95
96
  switch (status.trim().toLowerCase()) {
@@ -112,7 +113,7 @@ function normalizeToolExecutionStatus(status) {
112
113
  }
113
114
  }
114
115
  function deriveToolExecutionStatus(options) {
115
- if (typeof options.actionRequired === "string" && options.actionRequired.length > 0) {
116
+ if (typeof options.actionRequired === "string" && BLOCKING_ACTION_REQUIRED.has(options.actionRequired)) {
116
117
  return "error";
117
118
  }
118
119
  if (options.error === true) {
@@ -178,6 +179,27 @@ function getToolResultStatus(event) {
178
179
  fallback: "completed"
179
180
  });
180
181
  }
182
+ function readToolExecutionNumber(value) {
183
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
184
+ }
185
+ function readToolExecutionBoolean(value) {
186
+ return typeof value === "boolean" ? value : void 0;
187
+ }
188
+ function readToolExecutionString(value) {
189
+ return typeof value === "string" && value.trim().length > 0 ? value : void 0;
190
+ }
191
+ function getToolExecutionMetadata(event) {
192
+ return {
193
+ commandExitCode: readToolExecutionNumber(event.command_exit_code),
194
+ durationMs: readToolExecutionNumber(event.duration_ms),
195
+ sandboxed: readToolExecutionBoolean(event.sandboxed),
196
+ timedOut: readToolExecutionBoolean(event.timed_out),
197
+ truncated: readToolExecutionBoolean(event.truncated),
198
+ stdoutPath: readToolExecutionString(event.stdout_path),
199
+ stderrPath: readToolExecutionString(event.stderr_path),
200
+ presentation: readToolExecutionString(event.presentation)
201
+ };
202
+ }
181
203
  function cloneBlocks(blocks) {
182
204
  return blocks?.map((block) => ({
183
205
  ...block,
@@ -323,6 +345,7 @@ function updateDetachedSnapshotForEvent(streamContext, event) {
323
345
  case "tool_result": {
324
346
  const toolStatus = getToolResultStatus(event);
325
347
  const resultContent = formatToolResultContent(event.result, event.error);
348
+ const toolExecutionMetadata = getToolExecutionMetadata(event);
326
349
  const toolCalls = (assistant.toolCalls || []).map((toolCall) => toolCall.id === event.tool_call_id ? {
327
350
  ...toolCall,
328
351
  status: toolStatus,
@@ -330,7 +353,8 @@ function updateDetachedSnapshotForEvent(streamContext, event) {
330
353
  error: toolStatus === "error" ? typeof event.error === "string" && event.error.trim().length > 0 ? event.error : resultContent : void 0,
331
354
  actionRequired: event.action_required,
332
355
  settingsTab: event.settings_tab,
333
- settingsSubTab: event.settings_sub_tab
356
+ settingsSubTab: event.settings_sub_tab,
357
+ ...toolExecutionMetadata
334
358
  } : toolCall);
335
359
  const hasRunning = toolCalls.some((toolCall) => toolCall.status === "running");
336
360
  const blocks = cloneBlocks(assistant.blocks) || [];
@@ -340,7 +364,9 @@ function updateDetachedSnapshotForEvent(streamContext, event) {
340
364
  if (toolBlockIndex !== -1) {
341
365
  blocks[toolBlockIndex] = {
342
366
  ...blocks[toolBlockIndex],
343
- toolStatus
367
+ toolStatus,
368
+ actionRequired: event.action_required,
369
+ ...toolExecutionMetadata
344
370
  };
345
371
  }
346
372
  if (resultContent) {
@@ -350,7 +376,9 @@ function updateDetachedSnapshotForEvent(streamContext, event) {
350
376
  timestamp: Date.now(),
351
377
  toolName: toolBlockIndex !== -1 ? blocks[toolBlockIndex].toolName : void 0,
352
378
  toolCallId: event.tool_call_id,
353
- isIntermediate: true
379
+ actionRequired: event.action_required,
380
+ isIntermediate: true,
381
+ ...toolExecutionMetadata
354
382
  });
355
383
  }
356
384
  snapshot[assistantIndex] = {
@@ -475,16 +503,18 @@ function useChat(options) {
475
503
  }, [conversationId]);
476
504
  (0, import_react.useEffect)(() => {
477
505
  isMountedRef.current = true;
506
+ const streamContexts = streamContextsRef.current;
507
+ const conversationStreamTokens = conversationStreamTokensRef.current;
478
508
  return () => {
479
509
  isMountedRef.current = false;
480
510
  cancelRef.current?.();
481
- streamContextsRef.current.forEach((context) => {
511
+ streamContexts.forEach((context) => {
482
512
  context.suppressed = true;
483
513
  context.terminal = true;
484
514
  context.cancel?.();
485
515
  });
486
- streamContextsRef.current.clear();
487
- conversationStreamTokensRef.current.clear();
516
+ streamContexts.clear();
517
+ conversationStreamTokens.clear();
488
518
  if (typewriterIntervalRef.current) clearTimeout(typewriterIntervalRef.current);
489
519
  };
490
520
  }, []);
@@ -1076,9 +1106,17 @@ function useChat(options) {
1076
1106
  const toolId = event.tool_call_id;
1077
1107
  const toolStatus = getToolResultStatus(event);
1078
1108
  const resultContent = formatToolResultContent(event.result, event.error);
1109
+ const toolExecutionMetadata = getToolExecutionMetadata(event);
1079
1110
  const blockIdx = currentBlocksRef.current.findIndex((b) => b.type === "tool_call" && b.toolCallId === toolId);
1080
1111
  const toolName = blockIdx !== -1 ? currentBlocksRef.current[blockIdx].toolName : void 0;
1081
- if (blockIdx !== -1) currentBlocksRef.current[blockIdx].toolStatus = toolStatus;
1112
+ if (blockIdx !== -1) {
1113
+ currentBlocksRef.current[blockIdx] = {
1114
+ ...currentBlocksRef.current[blockIdx],
1115
+ toolStatus,
1116
+ actionRequired: event.action_required,
1117
+ ...toolExecutionMetadata
1118
+ };
1119
+ }
1082
1120
  if (resultContent) {
1083
1121
  currentBlocksRef.current.push({
1084
1122
  type: "tool_result",
@@ -1086,7 +1124,9 @@ function useChat(options) {
1086
1124
  timestamp: Date.now(),
1087
1125
  toolName,
1088
1126
  toolCallId: toolId,
1089
- isIntermediate: true
1127
+ actionRequired: event.action_required,
1128
+ isIntermediate: true,
1129
+ ...toolExecutionMetadata
1090
1130
  });
1091
1131
  }
1092
1132
  setMessages((prev) => {
@@ -1101,7 +1141,8 @@ function useChat(options) {
1101
1141
  error: toolStatus === "error" ? typeof event.error === "string" && event.error.trim().length > 0 ? event.error : resultContent : void 0,
1102
1142
  actionRequired: event.action_required,
1103
1143
  settingsTab: event.settings_tab,
1104
- settingsSubTab: event.settings_sub_tab
1144
+ settingsSubTab: event.settings_sub_tab,
1145
+ ...toolExecutionMetadata
1105
1146
  } : t
1106
1147
  );
1107
1148
  const hasRunning = updatedCalls.some((tc) => tc.status === "running");
@@ -2012,7 +2053,9 @@ function useConnection(options) {
2012
2053
  const [errorCode, setErrorCode] = (0, import_react4.useState)();
2013
2054
  const isMountedRef = (0, import_react4.useRef)(true);
2014
2055
  const onStatusChangeRef = (0, import_react4.useRef)(onStatusChange);
2015
- onStatusChangeRef.current = onStatusChange;
2056
+ (0, import_react4.useEffect)(() => {
2057
+ onStatusChangeRef.current = onStatusChange;
2058
+ }, [onStatusChange]);
2016
2059
  const reconnectAttemptsRef = (0, import_react4.useRef)(0);
2017
2060
  (0, import_react4.useEffect)(() => {
2018
2061
  isMountedRef.current = true;
@@ -6459,6 +6502,27 @@ function useWindowDragLock(active) {
6459
6502
  }
6460
6503
 
6461
6504
  // src/core/history.ts
6505
+ function readToolExecutionNumber2(value) {
6506
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
6507
+ }
6508
+ function readToolExecutionBoolean2(value) {
6509
+ return typeof value === "boolean" ? value : void 0;
6510
+ }
6511
+ function readToolExecutionString2(value) {
6512
+ return typeof value === "string" && value.trim().length > 0 ? value : void 0;
6513
+ }
6514
+ function readToolExecutionMetadata(tc) {
6515
+ return {
6516
+ commandExitCode: readToolExecutionNumber2(tc.command_exit_code ?? tc.commandExitCode),
6517
+ durationMs: readToolExecutionNumber2(tc.duration_ms ?? tc.durationMs),
6518
+ sandboxed: readToolExecutionBoolean2(tc.sandboxed),
6519
+ timedOut: readToolExecutionBoolean2(tc.timed_out ?? tc.timedOut),
6520
+ truncated: readToolExecutionBoolean2(tc.truncated),
6521
+ stdoutPath: readToolExecutionString2(tc.stdout_path ?? tc.stdoutPath),
6522
+ stderrPath: readToolExecutionString2(tc.stderr_path ?? tc.stderrPath),
6523
+ presentation: readToolExecutionString2(tc.presentation)
6524
+ };
6525
+ }
6462
6526
  function safeParseArgs(value) {
6463
6527
  if (!value) return void 0;
6464
6528
  if (typeof value === "object") return value;
@@ -6506,7 +6570,8 @@ function parseToolCalls(toolCalls) {
6506
6570
  actionRequired,
6507
6571
  error: tc.error,
6508
6572
  fallback: "completed"
6509
- })
6573
+ }),
6574
+ ...readToolExecutionMetadata(tc)
6510
6575
  };
6511
6576
  }).filter((tc) => tc.name || tc.id);
6512
6577
  }
@@ -6574,6 +6639,10 @@ function mergeConsecutiveAssistantMessages(rawMessages) {
6574
6639
  const consecutiveAssistantMsgs = [msg];
6575
6640
  const toolMessages = [];
6576
6641
  let j = i + 1;
6642
+ const hasDeclaredToolCalls = (message) => {
6643
+ const calls = parseToolCalls(message.toolCalls || message.tool_calls);
6644
+ return Boolean(calls && calls.length > 0);
6645
+ };
6577
6646
  while (j < rawMessages.length) {
6578
6647
  if (rawMessages[j].role === "assistant") {
6579
6648
  consecutiveAssistantMsgs.push(rawMessages[j]);
@@ -6589,11 +6658,12 @@ function mergeConsecutiveAssistantMessages(rawMessages) {
6589
6658
  let blockTime = Date.now();
6590
6659
  let fallbackToolCalls;
6591
6660
  let lastEffectiveToolCalls;
6661
+ const groupHasDeclaredToolCalls = consecutiveAssistantMsgs.some(hasDeclaredToolCalls);
6592
6662
  for (let k = 0; k < consecutiveAssistantMsgs.length; k++) {
6593
6663
  const assistantMsg = consecutiveAssistantMsgs[k];
6594
6664
  const msgToolCalls = parseToolCalls(assistantMsg.toolCalls || assistantMsg.tool_calls);
6595
6665
  const isLastAssistant = k === consecutiveAssistantMsgs.length - 1;
6596
- const fallbackCalls = isLastAssistant && toolMessages.length > 0 ? toolMessages.map((toolMessage, idx) => ({
6666
+ const fallbackCalls = !groupHasDeclaredToolCalls && isLastAssistant && toolMessages.length > 0 ? toolMessages.map((toolMessage, idx) => ({
6597
6667
  id: (toolMessage.tool_call_id || void 0) ?? `tool-${idx}`,
6598
6668
  name: "",
6599
6669
  args: void 0,
@@ -6651,7 +6721,16 @@ function mergeConsecutiveAssistantMessages(rawMessages) {
6651
6721
  toolArgs: tc.args,
6652
6722
  toolCallId: tc.id,
6653
6723
  toolStatus,
6654
- isIntermediate: true
6724
+ actionRequired: tc.actionRequired,
6725
+ isIntermediate: true,
6726
+ commandExitCode: tc.commandExitCode,
6727
+ durationMs: tc.durationMs,
6728
+ sandboxed: tc.sandboxed,
6729
+ timedOut: tc.timedOut,
6730
+ truncated: tc.truncated,
6731
+ stdoutPath: tc.stdoutPath,
6732
+ stderrPath: tc.stderrPath,
6733
+ presentation: tc.presentation
6655
6734
  });
6656
6735
  const resultContent = tc.result ?? toolResult?.content;
6657
6736
  const toolResultId = toolResult?.tool_call_id || void 0;
@@ -6662,7 +6741,16 @@ function mergeConsecutiveAssistantMessages(rawMessages) {
6662
6741
  timestamp: blockTime++,
6663
6742
  toolName: tc.name,
6664
6743
  toolCallId: tc.id || toolResultId,
6665
- isIntermediate: true
6744
+ actionRequired: tc.actionRequired,
6745
+ isIntermediate: true,
6746
+ commandExitCode: tc.commandExitCode,
6747
+ durationMs: tc.durationMs,
6748
+ sandboxed: tc.sandboxed,
6749
+ timedOut: tc.timedOut,
6750
+ truncated: tc.truncated,
6751
+ stdoutPath: tc.stdoutPath,
6752
+ stderrPath: tc.stderrPath,
6753
+ presentation: tc.presentation
6666
6754
  });
6667
6755
  tc.result = resultContent;
6668
6756
  }
@@ -7310,7 +7398,15 @@ function processStreamEvents(stream, onEvent, sdk, setCurrentRunId, streamId) {
7310
7398
  status: toolResultEvent.status,
7311
7399
  action_required: toolResultEvent.action_required,
7312
7400
  settings_tab: toolResultEvent.settings_tab,
7313
- settings_sub_tab: toolResultEvent.settings_sub_tab
7401
+ settings_sub_tab: toolResultEvent.settings_sub_tab,
7402
+ command_exit_code: toolResultEvent.command_exit_code,
7403
+ duration_ms: toolResultEvent.duration_ms,
7404
+ sandboxed: toolResultEvent.sandboxed,
7405
+ timed_out: toolResultEvent.timed_out,
7406
+ truncated: toolResultEvent.truncated,
7407
+ stdout_path: toolResultEvent.stdout_path,
7408
+ stderr_path: toolResultEvent.stderr_path,
7409
+ presentation: toolResultEvent.presentation
7314
7410
  });
7315
7411
  break;
7316
7412
  }
@@ -8538,6 +8634,7 @@ function buildFallbackBlocksFromToolCalls(toolCalls) {
8538
8634
  toolArgs: toolCall.args,
8539
8635
  toolCallId: toolCall.id,
8540
8636
  toolStatus,
8637
+ actionRequired: toolCall.actionRequired,
8541
8638
  isIntermediate: true
8542
8639
  });
8543
8640
  const resultContent = normalizeToolResult(toolCall.result);
@@ -8548,6 +8645,7 @@ function buildFallbackBlocksFromToolCalls(toolCalls) {
8548
8645
  timestamp: timestamp++,
8549
8646
  toolName: toolCall.name,
8550
8647
  toolCallId: toolCall.id,
8648
+ actionRequired: toolCall.actionRequired,
8551
8649
  isIntermediate: true
8552
8650
  });
8553
8651
  }
@@ -9068,9 +9166,13 @@ var HitlCard = (0, import_react24.memo)(function HitlCard2({
9068
9166
  const riskLevel = interrupt.risk_level || "medium";
9069
9167
  const riskStyle = riskColors[riskLevel];
9070
9168
  const onSubmitRef = (0, import_react24.useRef)(onSubmit);
9071
- onSubmitRef.current = onSubmit;
9072
9169
  const onCancelRef = (0, import_react24.useRef)(onCancel);
9073
- onCancelRef.current = onCancel;
9170
+ (0, import_react24.useEffect)(() => {
9171
+ onSubmitRef.current = onSubmit;
9172
+ }, [onSubmit]);
9173
+ (0, import_react24.useEffect)(() => {
9174
+ onCancelRef.current = onCancel;
9175
+ }, [onCancel]);
9074
9176
  (0, import_react24.useEffect)(() => {
9075
9177
  if (isUserInput) {
9076
9178
  if (!interrupt.options || interrupt.options.length === 0) {