@invergent/agent-chat-react 1.5.4 → 1.5.5

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/dist/index.cjs CHANGED
@@ -3555,7 +3555,7 @@ function ClarifyLocked({
3555
3555
  function ArtifactToolBlock({ tc }) {
3556
3556
  const args = parseArgs(tc.args) ?? {};
3557
3557
  const status = effectiveStatus(tc);
3558
- const label = status === "running" ? "Creating artifact\u2026" : status === "error" ? "Tried to create" : "Created";
3558
+ const label = status === "running" ? "Creating artifact\u2026" : status === "error" ? "Creating artifact\u2026" : "Created";
3559
3559
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 text-sm ", children: [
3560
3560
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-foreground", children: label }),
3561
3561
  args.name && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground truncate", children: args.name })
@@ -6234,14 +6234,17 @@ function TimelineEntryItem({
6234
6234
  ] });
6235
6235
  }
6236
6236
  if (entry.kind === "tool") {
6237
- const failureSummary = effectiveStatus(entry.tc) === "error" ? toolErrorSummary(entry.tc.result) : "";
6237
+ const rawStatus = effectiveStatus(entry.tc);
6238
+ const hideArtifactFailure = rawStatus === "error" && entry.tc.toolName === "create_artifact";
6239
+ const indicatorStatus = hideArtifactFailure ? "running" : rawStatus;
6240
+ const failureSummary = rawStatus === "error" && !hideArtifactFailure ? toolErrorSummary(entry.tc.result) : "";
6238
6241
  return /* @__PURE__ */ jsxRuntime.jsxs(TimelineItem, { step, children: [
6239
6242
  /* @__PURE__ */ jsxRuntime.jsxs(TimelineHeader, { children: [
6240
6243
  /* @__PURE__ */ jsxRuntime.jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
6241
6244
  /* @__PURE__ */ jsxRuntime.jsx(
6242
6245
  TimelineIndicator,
6243
6246
  {
6244
- className: cn("size-2 border-none", statusColorClass(effectiveStatus(entry.tc)))
6247
+ className: cn("size-2 border-none", statusColorClass(indicatorStatus))
6245
6248
  }
6246
6249
  )
6247
6250
  ] }),
@@ -6299,13 +6302,14 @@ function TimelineEntryItem({
6299
6302
  /* @__PURE__ */ jsxRuntime.jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
6300
6303
  /* @__PURE__ */ jsxRuntime.jsx(TimelineIndicator, { className: "size-2 border-none bg-primary animate-pulse" })
6301
6304
  ] }),
6302
- /* @__PURE__ */ jsxRuntime.jsx(TimelineContent, { children: /* @__PURE__ */ jsxRuntime.jsx(Shimmer, { duration: 5, className: "text-sm text-foreground", children: "Working on it..." }) })
6305
+ /* @__PURE__ */ jsxRuntime.jsx(TimelineContent, { children: /* @__PURE__ */ jsxRuntime.jsx(Shimmer, { duration: 3, spread: 3, className: "text-sm", children: "Working on it..." }) })
6303
6306
  ] });
6304
6307
  }
6305
6308
  function AssistantGroup({
6306
6309
  messages,
6307
6310
  lastGlobalIndex,
6308
6311
  totalMessages,
6312
+ isRunning,
6309
6313
  sessionId,
6310
6314
  onFileSelect,
6311
6315
  onRetry
@@ -6315,6 +6319,15 @@ function AssistantGroup({
6315
6319
  const isLast = i === messages.length - 1 && lastGlobalIndex === totalMessages - 1;
6316
6320
  entries.push(...messageToEntries(messages[i], isLast));
6317
6321
  }
6322
+ const isTailGroup = lastGlobalIndex === totalMessages - 1;
6323
+ const lastEntry = entries[entries.length - 1];
6324
+ const hasRunningTool = entries.some(
6325
+ (e) => e.kind === "tool" && e.tc.status === "running"
6326
+ );
6327
+ const tailMsg = messages[messages.length - 1];
6328
+ if (isTailGroup && isRunning && !hasRunningTool && lastEntry?.kind !== "thinking") {
6329
+ entries.push({ kind: "thinking", key: `${tailMsg.id}-tail-thinking` });
6330
+ }
6318
6331
  const tail = messages[messages.length - 1];
6319
6332
  const showErrorInfo = tail && tail.role === "assistant" && tail.status === "error" && !!tail.errorInfo;
6320
6333
  return /* @__PURE__ */ jsxRuntime.jsx(Message, { from: "assistant", children: /* @__PURE__ */ jsxRuntime.jsxs(MessageContent, { children: [
@@ -6438,6 +6451,7 @@ function ChatThread({
6438
6451
  messages: group.messages,
6439
6452
  lastGlobalIndex: group.lastGlobalIndex,
6440
6453
  totalMessages: messages.length,
6454
+ isRunning,
6441
6455
  sessionId,
6442
6456
  onFileSelect,
6443
6457
  onRetry: groupRetry
@@ -6445,7 +6459,7 @@ function ChatThread({
6445
6459
  group.messages[0].id
6446
6460
  );
6447
6461
  }),
6448
- isRunning && messages.length > 0 && messages[messages.length - 1].role === "user" && /* @__PURE__ */ jsxRuntime.jsx(Message, { from: "assistant", children: /* @__PURE__ */ jsxRuntime.jsx(MessageContent, { children: /* @__PURE__ */ jsxRuntime.jsx(Shimmer, { duration: 5, className: "text-sm", children: "Working on it..." }) }) })
6462
+ isRunning && messages.length > 0 && messages[messages.length - 1].role === "user" && /* @__PURE__ */ jsxRuntime.jsx(Message, { from: "assistant", children: /* @__PURE__ */ jsxRuntime.jsx(MessageContent, { children: /* @__PURE__ */ jsxRuntime.jsx(Shimmer, { duration: 3, spread: 3, className: "text-sm", children: "Working on it..." }) }) })
6449
6463
  ] }) }),
6450
6464
  /* @__PURE__ */ jsxRuntime.jsx(ConversationScrollButton, {})
6451
6465
  ] }),
@@ -7143,6 +7157,7 @@ function WorkspacePanel({
7143
7157
  onSelectedPathChange,
7144
7158
  collapsed = false,
7145
7159
  onCollapsedChange,
7160
+ refreshSignal = 0,
7146
7161
  disabled = false
7147
7162
  }) {
7148
7163
  const fileInputRef = react.useRef(null);
@@ -7222,6 +7237,13 @@ function WorkspacePanel({
7222
7237
  react.useEffect(() => {
7223
7238
  void fetchTree();
7224
7239
  }, [fetchTree]);
7240
+ react.useEffect(() => {
7241
+ if (!sessionId || refreshSignal === 0) return;
7242
+ const timer = setTimeout(() => {
7243
+ void fetchTree();
7244
+ }, 300);
7245
+ return () => clearTimeout(timer);
7246
+ }, [refreshSignal, sessionId, fetchTree]);
7225
7247
  react.useEffect(() => {
7226
7248
  if (!sessionId) {
7227
7249
  setFile(null);
@@ -7562,6 +7584,12 @@ function ConfirmDialog({
7562
7584
  }
7563
7585
 
7564
7586
  // src/runtime/events.ts
7587
+ var WORKSPACE_MUTATING_TOOLS = /* @__PURE__ */ new Set([
7588
+ "terminal",
7589
+ "write_file",
7590
+ "patch",
7591
+ "execute_code"
7592
+ ]);
7565
7593
  var AGENT_CHAT_LISTENED_EVENTS = [
7566
7594
  "user.message",
7567
7595
  "llm.request",
@@ -7610,7 +7638,8 @@ function createInitialAgentChatState(options = {}) {
7610
7638
  lastEventId: 0,
7611
7639
  sessionDone: false,
7612
7640
  hadDeltas: false,
7613
- terminal: false
7641
+ terminal: false,
7642
+ workspaceRefreshKey: 0
7614
7643
  };
7615
7644
  }
7616
7645
  function applyAgentChatEvent(state, event) {
@@ -7672,11 +7701,17 @@ function applyAgentChatEvent(state, event) {
7672
7701
  return applyLlmThinking(nextState, event);
7673
7702
  case "tool.call":
7674
7703
  return applyToolCall(nextState, event);
7675
- case "tool.result":
7676
- return withMessages(
7677
- nextState,
7678
- applyToolResult(nextState.messages, event.data)
7679
- );
7704
+ case "tool.result": {
7705
+ const toolCallId = stringValue(event.data.tool_call_id);
7706
+ const toolName = findToolNameById(nextState.messages, toolCallId);
7707
+ const messages = applyToolResult(nextState.messages, event.data);
7708
+ const mutatesWorkspace = toolName !== null && WORKSPACE_MUTATING_TOOLS.has(toolName);
7709
+ return {
7710
+ ...nextState,
7711
+ messages,
7712
+ workspaceRefreshKey: mutatesWorkspace ? nextState.workspaceRefreshKey + 1 : nextState.workspaceRefreshKey
7713
+ };
7714
+ }
7680
7715
  case "harness.wake":
7681
7716
  case "llm.request":
7682
7717
  return nextState.terminal ? nextState : { ...nextState, isRunning: true };
@@ -8116,6 +8151,14 @@ function hasUserAfterIndex(messages, idx) {
8116
8151
  }
8117
8152
  return false;
8118
8153
  }
8154
+ function findToolNameById(messages, toolCallId) {
8155
+ if (!toolCallId) return null;
8156
+ for (let i = messages.length - 1; i >= 0; i--) {
8157
+ const tc = messages[i]?.toolCalls?.find((c) => c.id === toolCallId);
8158
+ if (tc) return tc.toolName;
8159
+ }
8160
+ return null;
8161
+ }
8119
8162
  function findLatestConsultExpertCall(messages) {
8120
8163
  for (let i = messages.length - 1; i >= 0; i--) {
8121
8164
  const msg = messages[i];
@@ -8366,6 +8409,7 @@ function useAgentChatRuntime({
8366
8409
  isLoadingHistory: state.isLoadingHistory,
8367
8410
  tokenUsage: state.tokenUsage,
8368
8411
  retryIndicator: state.retryIndicator,
8412
+ workspaceRefreshKey: state.workspaceRefreshKey,
8369
8413
  send,
8370
8414
  stop,
8371
8415
  retry,
@@ -8451,6 +8495,7 @@ function AgentChat({
8451
8495
  onSelectedPathChange: setWorkspacePath,
8452
8496
  collapsed: workspaceCollapsed,
8453
8497
  onCollapsedChange: setWorkspaceCollapsed,
8498
+ refreshSignal: runtime.workspaceRefreshKey,
8454
8499
  disabled
8455
8500
  }
8456
8501
  )
@@ -8556,6 +8601,7 @@ function TreeNodeRow({
8556
8601
  const hasChildren = entry.children.length > 0;
8557
8602
  const isActive = entry.id === activeSessionId;
8558
8603
  const isRunning = entry.status === "active";
8604
+ const isSubAgent = entry.parentId != null;
8559
8605
  const title = entry.title ?? "New session";
8560
8606
  const subtitle = [
8561
8607
  entry.model ?? "default",
@@ -8595,7 +8641,7 @@ function TreeNodeRow({
8595
8641
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm truncate", children: title }),
8596
8642
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-faint truncate", children: subtitle })
8597
8643
  ] }),
8598
- isRunning && canStop && /* @__PURE__ */ jsxRuntime.jsx(
8644
+ isRunning && canStop && isSubAgent && /* @__PURE__ */ jsxRuntime.jsx(
8599
8645
  "button",
8600
8646
  {
8601
8647
  type: "button",