@invergent/agent-chat-react 2.3.1 → 2.4.1

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
@@ -1090,9 +1090,9 @@ var defaultGetThinkingMessage = (isStreaming, duration) => {
1090
1090
  return /* @__PURE__ */ jsxRuntime.jsx(Shimmer, { duration: 1, children: "Thinking..." });
1091
1091
  }
1092
1092
  if (duration === void 0) {
1093
- return /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-foreground", children: "Thought for a few seconds" });
1093
+ return /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground italic", children: "Thought for a few seconds" });
1094
1094
  }
1095
- return /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-foreground", children: [
1095
+ return /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-muted-foreground italic", children: [
1096
1096
  "Thought for ",
1097
1097
  duration,
1098
1098
  " seconds"
@@ -6865,6 +6865,59 @@ function useSmoothStream(target, isStreaming) {
6865
6865
  return displayedLen >= target.length ? target : target.slice(0, displayedLen);
6866
6866
  }
6867
6867
 
6868
+ // src/lib/next-action.ts
6869
+ var _NEXT_ACTION_RE = /<next_action([^>]*)>([\s\S]*?)<\/next_action>\s*/gi;
6870
+ var _ATTR_RE = /(\w+)="([^"]*)"/g;
6871
+ var _VALID_COMPLEXITY = /* @__PURE__ */ new Set([
6872
+ "low",
6873
+ "medium",
6874
+ "high"
6875
+ ]);
6876
+ var _VALID_SUMMARY = /* @__PURE__ */ new Set([
6877
+ "show",
6878
+ "hide"
6879
+ ]);
6880
+ function _parseAttrs(rawAttrs) {
6881
+ const out = {};
6882
+ for (const m of rawAttrs.matchAll(_ATTR_RE)) {
6883
+ out[m[1].toLowerCase()] = m[2];
6884
+ }
6885
+ return out;
6886
+ }
6887
+ function _inferNarration(text) {
6888
+ if (!text) return null;
6889
+ const head = text.trimStart().split(/\n\s*\n/, 1)[0].slice(0, 240);
6890
+ const endMatch = /([.!?])(\s|$)/.exec(head);
6891
+ const firstSentence = (endMatch ? head.slice(0, endMatch.index + 1) : head).trim();
6892
+ if (!firstSentence || firstSentence.length > 200) return null;
6893
+ return firstSentence;
6894
+ }
6895
+ function stripAndParseNextAction(text) {
6896
+ if (!text) {
6897
+ return { cleaned: text ?? "", action: null, inferredNarration: null };
6898
+ }
6899
+ let last = null;
6900
+ const matches = Array.from(text.matchAll(_NEXT_ACTION_RE));
6901
+ if (matches.length === 0) {
6902
+ return {
6903
+ cleaned: text,
6904
+ action: null,
6905
+ inferredNarration: _inferNarration(text)
6906
+ };
6907
+ }
6908
+ for (const match of matches) {
6909
+ const attrs = _parseAttrs(match[1] ?? "");
6910
+ const rawComplexity = (attrs["complexity"] ?? "").trim().toLowerCase();
6911
+ const complexity = _VALID_COMPLEXITY.has(rawComplexity) ? rawComplexity : "medium";
6912
+ const rawSummary = (attrs["summary"] ?? "").trim().toLowerCase();
6913
+ const summary = _VALID_SUMMARY.has(rawSummary) ? rawSummary : "hide";
6914
+ const body = (match[2] ?? "").trim() || "done";
6915
+ last = { complexity, summary, body };
6916
+ }
6917
+ const cleaned = text.replace(_NEXT_ACTION_RE, "").trimEnd();
6918
+ return { cleaned, action: last, inferredNarration: null };
6919
+ }
6920
+
6868
6921
  // src/components/ai-elements/artifact.tsx
6869
6922
  init_utils();
6870
6923
  var Artifact = ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx(
@@ -6995,12 +7048,21 @@ var EXPANDED_HEIGHT_PX = 800;
6995
7048
  var MIN_ZOOM = 0.5;
6996
7049
  var MAX_ZOOM = 2;
6997
7050
  var ZOOM_STEP = 0.1;
7051
+ var SAFETY_STYLE_PREAMBLE = "<style>html,body{max-height:100vh}canvas{max-height:80vh!important}</style>";
7052
+ function injectSafetyStyle(html) {
7053
+ const headCloseIdx = html.search(/<\/head\s*>/i);
7054
+ if (headCloseIdx >= 0) {
7055
+ return html.slice(0, headCloseIdx) + SAFETY_STYLE_PREAMBLE + html.slice(headCloseIdx);
7056
+ }
7057
+ return SAFETY_STYLE_PREAMBLE + html;
7058
+ }
6998
7059
  function ArtifactHtml({
6999
7060
  spec,
7000
7061
  fill = false
7001
7062
  }) {
7002
7063
  const [expanded, setExpanded] = react.useState(false);
7003
7064
  const [zoom, setZoom] = react.useState(1);
7065
+ const safeSrcdoc = react.useMemo(() => injectSafetyStyle(spec.html), [spec.html]);
7004
7066
  const viewportHeight = expanded ? EXPANDED_HEIGHT_PX : DEFAULT_HEIGHT_PX;
7005
7067
  const clamp = (v) => Math.round(Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, v)) * 100) / 100;
7006
7068
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -7020,7 +7082,7 @@ function ArtifactHtml({
7020
7082
  "iframe",
7021
7083
  {
7022
7084
  title: "artifact-html",
7023
- srcDoc: spec.html,
7085
+ srcDoc: safeSrcdoc,
7024
7086
  sandbox: "allow-scripts",
7025
7087
  className: cn("border-0", fill && "h-full w-full"),
7026
7088
  style: fill ? { zoom } : {
@@ -8119,16 +8181,6 @@ function TurnSummaryCard({
8119
8181
  }) })
8120
8182
  ] });
8121
8183
  }
8122
- function TurnSummaryPending() {
8123
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 rounded border border-border bg-muted/50 px-3 py-2 text-sm", children: [
8124
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-2 text-xs font-semibold uppercase tracking-wide", children: "Summary" }),
8125
- /* @__PURE__ */ jsxRuntime.jsx(Shimmer, { duration: 3, spread: 3, className: "mb-2 text-sm", children: "Summarizing conversation..." }),
8126
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
8127
- /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { className: "h-3 w-3/4" }),
8128
- /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { className: "h-3 w-2/3" })
8129
- ] })
8130
- ] });
8131
- }
8132
8184
  function ArtifactRow({
8133
8185
  artifact,
8134
8186
  sessionId,
@@ -8194,6 +8246,7 @@ function ArtifactRow({
8194
8246
 
8195
8247
  // src/components/chat/chat-thread.tsx
8196
8248
  init_utils();
8249
+ var WORKING_ON_IT_DELAY_MS = 250;
8197
8250
  function messageToEntries(msg, isLast, artifactFallbacks) {
8198
8251
  if (msg.role === "system") {
8199
8252
  if (msg.systemKind === "skill_invoked") {
@@ -8224,16 +8277,23 @@ function messageToEntries(msg, isLast, artifactFallbacks) {
8224
8277
  const hasToolCalls = !!(msg.toolCalls && msg.toolCalls.length > 0);
8225
8278
  const hasContent = !!(msg.content && msg.content !== msg.reasoning);
8226
8279
  const isStreaming = msg.status === "streaming" && isLast;
8227
- const effectiveReasoning = hasToolCalls && hasContent ? msg.reasoning ? msg.reasoning + "\n" + msg.content : msg.content : msg.reasoning;
8228
8280
  const effectiveHasContent = hasContent && !hasToolCalls;
8229
- if (effectiveReasoning) {
8281
+ if (msg.reasoning) {
8230
8282
  entries.push({
8231
8283
  kind: "reasoning",
8232
8284
  key: `${msg.id}-reasoning`,
8233
- reasoning: effectiveReasoning,
8285
+ reasoning: msg.reasoning,
8234
8286
  isStreaming: isStreaming && !effectiveHasContent && !hasToolCalls
8235
8287
  });
8236
8288
  }
8289
+ if (hasContent && hasToolCalls) {
8290
+ entries.push({
8291
+ kind: "narration",
8292
+ key: `${msg.id}-narration`,
8293
+ text: msg.content,
8294
+ isStreaming: isStreaming && !effectiveHasContent
8295
+ });
8296
+ }
8237
8297
  if (hasToolCalls) {
8238
8298
  for (const tc of msg.toolCalls) {
8239
8299
  if (tc.toolName === "create_artifact") {
@@ -8264,12 +8324,6 @@ function messageToEntries(msg, isLast, artifactFallbacks) {
8264
8324
  msg
8265
8325
  });
8266
8326
  }
8267
- const hasRunningTool = hasToolCalls && msg.toolCalls.some(
8268
- (tc) => tc.status === "running"
8269
- );
8270
- if (isStreaming && !effectiveHasContent && !hasRunningTool) {
8271
- entries.push({ kind: "thinking", key: `${msg.id}-thinking` });
8272
- }
8273
8327
  return entries;
8274
8328
  }
8275
8329
  function groupBrowserActivityEntries(entries) {
@@ -8381,7 +8435,10 @@ function OrphanSystemMarker({
8381
8435
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "my-2 flex items-center gap-2 px-4 text-xs text-foreground/60 ", children: [
8382
8436
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "size-2 rounded-full bg-emerald-500" }),
8383
8437
  /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
8384
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-foreground", children: "Skill" }),
8438
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-semibold text-foreground", children: [
8439
+ "Running skill",
8440
+ " "
8441
+ ] }),
8385
8442
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground/60 truncate", children: skill })
8386
8443
  ] })
8387
8444
  ] });
@@ -8496,6 +8553,9 @@ function TimelineEntryItem({
8496
8553
  if (entry.kind === "text") {
8497
8554
  return /* @__PURE__ */ jsxRuntime.jsx(TextEntry, { entry, step });
8498
8555
  }
8556
+ if (entry.kind === "narration") {
8557
+ return /* @__PURE__ */ jsxRuntime.jsx(NarrationEntry, { entry, step });
8558
+ }
8499
8559
  if (entry.kind === "skill_invoked") {
8500
8560
  return /* @__PURE__ */ jsxRuntime.jsxs(TimelineItem, { step, children: [
8501
8561
  /* @__PURE__ */ jsxRuntime.jsxs(TimelineHeader, { children: [
@@ -8554,18 +8614,35 @@ function ReasoningEntry({
8554
8614
  ] }) })
8555
8615
  ] });
8556
8616
  }
8617
+ function NarrationEntry({
8618
+ entry,
8619
+ step
8620
+ }) {
8621
+ const text = useSmoothStream(entry.text, entry.isStreaming);
8622
+ const { action, inferredNarration } = stripAndParseNextAction(text);
8623
+ const line = action ? action.body.trim().toLowerCase() === "done" ? null : action.body : inferredNarration;
8624
+ if (!line) return null;
8625
+ return /* @__PURE__ */ jsxRuntime.jsxs(TimelineItem, { step, children: [
8626
+ /* @__PURE__ */ jsxRuntime.jsxs(TimelineHeader, { children: [
8627
+ /* @__PURE__ */ jsxRuntime.jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
8628
+ /* @__PURE__ */ jsxRuntime.jsx(TimelineIndicator, { className: "size-2 border-none bg-foreground/30" })
8629
+ ] }),
8630
+ /* @__PURE__ */ jsxRuntime.jsx(TimelineContent, { children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: line }) })
8631
+ ] });
8632
+ }
8557
8633
  function TextEntry({
8558
8634
  entry,
8559
8635
  step
8560
8636
  }) {
8561
8637
  const content = useSmoothStream(entry.content, entry.isStreaming);
8638
+ const { cleaned } = stripAndParseNextAction(content);
8562
8639
  return /* @__PURE__ */ jsxRuntime.jsxs(TimelineItem, { step, children: [
8563
8640
  /* @__PURE__ */ jsxRuntime.jsxs(TimelineHeader, { children: [
8564
8641
  /* @__PURE__ */ jsxRuntime.jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
8565
8642
  /* @__PURE__ */ jsxRuntime.jsx(TimelineIndicator, { className: "size-2 border-none bg-foreground/40" })
8566
8643
  ] }),
8567
8644
  /* @__PURE__ */ jsxRuntime.jsxs(TimelineContent, { children: [
8568
- /* @__PURE__ */ jsxRuntime.jsx(MessageResponse, { children: content }),
8645
+ /* @__PURE__ */ jsxRuntime.jsx(MessageResponse, { children: cleaned }),
8569
8646
  entry.isFinalTurnText && entry.msg.status === "complete" && /* @__PURE__ */ jsxRuntime.jsx(TurnFeedback, { msg: entry.msg })
8570
8647
  ] })
8571
8648
  ] });
@@ -8577,8 +8654,9 @@ function SimpleFinalAnswer({
8577
8654
  }) {
8578
8655
  const content = useSmoothStream(text, isStreaming);
8579
8656
  const revealComplete = content.length >= text.length;
8657
+ const { cleaned } = stripAndParseNextAction(content);
8580
8658
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
8581
- /* @__PURE__ */ jsxRuntime.jsx(MessageResponse, { children: content }),
8659
+ /* @__PURE__ */ jsxRuntime.jsx(MessageResponse, { children: cleaned }),
8582
8660
  tail?.status === "complete" && revealComplete && /* @__PURE__ */ jsxRuntime.jsx(TurnFeedback, { msg: tail })
8583
8661
  ] });
8584
8662
  }
@@ -8871,7 +8949,7 @@ function IterationGroup({
8871
8949
  if (!label) {
8872
8950
  return null;
8873
8951
  }
8874
- const labelTone = summary ? "text-foreground/80" : "text-foreground/50";
8952
+ const labelTone = summary ? "text-muted-foreground italic" : "text-muted-foreground";
8875
8953
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
8876
8954
  /* @__PURE__ */ jsxRuntime.jsxs(
8877
8955
  "button",
@@ -8957,10 +9035,7 @@ function deriveFileArtifactsFromMessages(messages) {
8957
9035
  }
8958
9036
  function SimpleAssistantGroup({
8959
9037
  messages,
8960
- lastGlobalIndex,
8961
- totalMessages,
8962
9038
  isRunning,
8963
- terminal,
8964
9039
  sessionId,
8965
9040
  artifactFallbacks,
8966
9041
  onFileSelect,
@@ -8971,16 +9046,15 @@ function SimpleAssistantGroup({
8971
9046
  const tailHasTools = !!(tail?.toolCalls && tail.toolCalls.length > 0);
8972
9047
  const tailIsTextOnly = !!tail && !tailHasTools;
8973
9048
  const finalText = tailIsTextOnly && tail.content ? tail.content : "";
8974
- const isTailGroup = lastGlobalIndex === totalMessages - 1;
8975
- const tailRendersOwnShimmer = !!tail && isIterationLive(tail) && !tailIsTextOnly;
8976
- const showThinkingShim = isTailGroup && isRunning && !tailRendersOwnShimmer;
8977
9049
  const showErrorInfo = !!tail && tail.status === "error" && !!tail.errorInfo;
8978
9050
  const turnComplete = !isRunning && tail?.status === "complete";
9051
+ const summaryPref = finalText !== null ? stripAndParseNextAction(finalText).action?.summary ?? "hide" : "hide";
8979
9052
  const effectiveTurnSummary = (() => {
8980
9053
  const fromHarness = tail?.turnSummary;
8981
9054
  if (fromHarness && fromHarness.artifacts.length > 0) {
8982
9055
  return fromHarness;
8983
9056
  }
9057
+ if (summaryPref === "hide") return null;
8984
9058
  if (!turnComplete) return fromHarness;
8985
9059
  const derived = deriveFileArtifactsFromMessages(messages);
8986
9060
  if (derived.length === 0) return fromHarness;
@@ -9004,17 +9078,22 @@ function SimpleAssistantGroup({
9004
9078
  message.id
9005
9079
  );
9006
9080
  }
9007
- if (message === tail && tailIsTextOnly) return null;
9008
- return /* @__PURE__ */ jsxRuntime.jsx(
9009
- IterationGroup,
9010
- {
9011
- message,
9012
- sessionId,
9013
- artifactFallbacks,
9014
- onFileSelect
9015
- },
9016
- message.id
9017
- );
9081
+ if (message === tail && tailIsTextOnly && finalText) return null;
9082
+ const rawContent = (message.content ?? "").trim();
9083
+ const { action, inferredNarration } = stripAndParseNextAction(rawContent);
9084
+ const narrationLine = action ? action.body.trim().toLowerCase() === "done" ? null : action.body : inferredNarration;
9085
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
9086
+ narrationLine && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-foreground", children: narrationLine }),
9087
+ /* @__PURE__ */ jsxRuntime.jsx(
9088
+ IterationGroup,
9089
+ {
9090
+ message,
9091
+ sessionId,
9092
+ artifactFallbacks,
9093
+ onFileSelect
9094
+ }
9095
+ )
9096
+ ] }, message.id);
9018
9097
  }) }),
9019
9098
  finalText && /* @__PURE__ */ jsxRuntime.jsx(
9020
9099
  SimpleFinalAnswer,
@@ -9024,8 +9103,7 @@ function SimpleAssistantGroup({
9024
9103
  tail
9025
9104
  }
9026
9105
  ),
9027
- showThinkingShim && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2", children: /* @__PURE__ */ jsxRuntime.jsx(Shimmer, { duration: 3, spread: 3, className: "text-sm", children: "Working on it..." }) }),
9028
- effectiveTurnSummary ? /* @__PURE__ */ jsxRuntime.jsx(
9106
+ effectiveTurnSummary && /* @__PURE__ */ jsxRuntime.jsx(
9029
9107
  TurnSummaryCard,
9030
9108
  {
9031
9109
  summary: effectiveTurnSummary,
@@ -9033,16 +9111,6 @@ function SimpleAssistantGroup({
9033
9111
  messages,
9034
9112
  onFileSelect
9035
9113
  }
9036
- ) : (
9037
- // The harness summarizer runs after the last assistant
9038
- // response and before ``session.complete``. Show a pending
9039
- // placeholder during that window so users aren't surprised
9040
- // when the Summary card pops in. Gated on ``!terminal``
9041
- // rather than ``isRunning`` because the text-only final
9042
- // ``llm.response`` already flips ``isRunning`` to false —
9043
- // the summarizer then runs in the gap before
9044
- // ``session.complete`` (which is what sets ``terminal``).
9045
- isTailGroup && !terminal && !!finalText && tail?.status === "complete" && /* @__PURE__ */ jsxRuntime.jsx(TurnSummaryPending, {})
9046
9114
  ),
9047
9115
  showErrorInfo && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3", children: /* @__PURE__ */ jsxRuntime.jsx(ErrorMessage, { errorInfo: tail.errorInfo, onRetry }) })
9048
9116
  ] }) });
@@ -9052,7 +9120,6 @@ function AssistantGroup({
9052
9120
  lastGlobalIndex,
9053
9121
  totalMessages,
9054
9122
  isRunning,
9055
- terminal,
9056
9123
  sessionId,
9057
9124
  artifactFallbacks,
9058
9125
  onFileSelect,
@@ -9064,10 +9131,7 @@ function AssistantGroup({
9064
9131
  SimpleAssistantGroup,
9065
9132
  {
9066
9133
  messages,
9067
- lastGlobalIndex,
9068
- totalMessages,
9069
9134
  isRunning,
9070
- terminal,
9071
9135
  sessionId,
9072
9136
  artifactFallbacks,
9073
9137
  onFileSelect,
@@ -9089,15 +9153,6 @@ function AssistantGroup({
9089
9153
  break;
9090
9154
  }
9091
9155
  }
9092
- const isTailGroup = lastGlobalIndex === totalMessages - 1;
9093
- const lastEntry = entries[entries.length - 1];
9094
- const hasRunningTool = entries.some(
9095
- (e) => e.kind === "tool" && e.tc.status === "running"
9096
- );
9097
- const tailMsg = messages[messages.length - 1];
9098
- if (isTailGroup && isRunning && !hasRunningTool && lastEntry?.kind !== "thinking") {
9099
- entries.push({ kind: "thinking", key: `${tailMsg.id}-tail-thinking` });
9100
- }
9101
9156
  const tail = messages[messages.length - 1];
9102
9157
  const showErrorInfo = tail && tail.role === "assistant" && tail.status === "error" && !!tail.errorInfo;
9103
9158
  return /* @__PURE__ */ jsxRuntime.jsx(Message, { from: "assistant", children: /* @__PURE__ */ jsxRuntime.jsxs(MessageContent, { children: [
@@ -9145,11 +9200,30 @@ function RetryBanner({ indicator }) {
9145
9200
  }
9146
9201
  );
9147
9202
  }
9203
+ function WorkingOnItIndicator() {
9204
+ return /* @__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..." }) }) });
9205
+ }
9206
+ function useDelayedRunningIndicator(isRunning) {
9207
+ const [visible, setVisible] = react.useState(isRunning);
9208
+ react.useEffect(() => {
9209
+ if (!isRunning) {
9210
+ setVisible(false);
9211
+ return;
9212
+ }
9213
+ if (visible) return;
9214
+ const timeout = window.setTimeout(() => {
9215
+ setVisible(true);
9216
+ }, WORKING_ON_IT_DELAY_MS);
9217
+ return () => {
9218
+ window.clearTimeout(timeout);
9219
+ };
9220
+ }, [isRunning, visible]);
9221
+ return visible;
9222
+ }
9148
9223
  function ChatThread({
9149
9224
  sessionId,
9150
9225
  messages,
9151
9226
  isRunning,
9152
- terminal,
9153
9227
  isLoadingHistory = false,
9154
9228
  onSend,
9155
9229
  onStop,
@@ -9170,6 +9244,7 @@ function ChatThread({
9170
9244
  onViewModeChange
9171
9245
  }) {
9172
9246
  const groups = react.useMemo(() => groupMessages(messages), [messages]);
9247
+ const showWorkingOnIt = useDelayedRunningIndicator(isRunning);
9173
9248
  const artifactFallbacks = react.useMemo(() => {
9174
9249
  const fallbacks = {};
9175
9250
  const createArtifactToolCallIds = [];
@@ -9203,7 +9278,7 @@ function ChatThread({
9203
9278
  }
9204
9279
  return null;
9205
9280
  }, [messages]);
9206
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col overflow-hidden bg-background text-sm", children: [
9281
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col overflow-hidden bg-background text-base", children: [
9207
9282
  /* @__PURE__ */ jsxRuntime.jsxs(Conversation, { className: "relative flex-1 min-h-0", children: [
9208
9283
  /* @__PURE__ */ jsxRuntime.jsx(ConversationContent, { className: "mx-auto w-full max-w-4xl", children: messages.length === 0 && isLoadingHistory ? /* @__PURE__ */ jsxRuntime.jsx(
9209
9284
  ConversationEmptyState,
@@ -9257,7 +9332,6 @@ function ChatThread({
9257
9332
  lastGlobalIndex: group.lastGlobalIndex,
9258
9333
  totalMessages: messages.length,
9259
9334
  isRunning,
9260
- terminal,
9261
9335
  sessionId,
9262
9336
  artifactFallbacks,
9263
9337
  onFileSelect,
@@ -9267,7 +9341,7 @@ function ChatThread({
9267
9341
  group.messages[0].id
9268
9342
  );
9269
9343
  }),
9270
- 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..." }) }) })
9344
+ showWorkingOnIt && /* @__PURE__ */ jsxRuntime.jsx(WorkingOnItIndicator, {})
9271
9345
  ] }) }),
9272
9346
  /* @__PURE__ */ jsxRuntime.jsx(ConversationScrollButton, {})
9273
9347
  ] }),
@@ -10060,6 +10134,9 @@ function applyAgentChatEvent(state, event) {
10060
10134
  sessionDone: state.sessionDone || event.type === "session.done"
10061
10135
  };
10062
10136
  nextState = applyRetryIndicator(nextState, event);
10137
+ if (state.terminal && isPostTerminalLiveEvent(event.type)) {
10138
+ return nextState;
10139
+ }
10063
10140
  switch (event.type) {
10064
10141
  case "user.message":
10065
10142
  return withMessages(
@@ -10202,6 +10279,9 @@ function applyAgentChatEvent(state, event) {
10202
10279
  return applyTurnSummary(nextState, event);
10203
10280
  }
10204
10281
  }
10282
+ function isPostTerminalLiveEvent(type) {
10283
+ return type === "harness.wake" || type === "llm.request" || type === "session.resume" || type === "llm.delta" || type === "llm.response" || type === "llm.thinking" || type === "tool.call";
10284
+ }
10205
10285
  function applyRetryIndicator(state, event) {
10206
10286
  switch (event.type) {
10207
10287
  case "harness.wake":
@@ -10390,30 +10470,18 @@ function applyLlmResponse(state, event) {
10390
10470
  );
10391
10471
  if (state.hadDeltas && idx >= 0 && !hasUserAfter) {
10392
10472
  const current = messages[idx];
10393
- if (hasToolCalls) {
10394
- messages[idx] = {
10395
- ...current,
10396
- reasoning: (current.reasoning ?? "") + current.content,
10397
- content: "",
10398
- status: "streaming",
10399
- llmResponseEventId: event.eventId,
10400
- turnId: turnId ?? current.turnId,
10401
- iterationIndex: iterationIndex ?? current.iterationIndex
10402
- };
10403
- } else {
10404
- messages[idx] = {
10405
- ...current,
10406
- status: "complete",
10407
- llmResponseEventId: event.eventId,
10408
- turnId: turnId ?? current.turnId,
10409
- iterationIndex: iterationIndex ?? current.iterationIndex
10410
- };
10411
- }
10473
+ messages[idx] = {
10474
+ ...current,
10475
+ status: hasToolCalls ? "streaming" : "complete",
10476
+ llmResponseEventId: event.eventId,
10477
+ turnId: turnId ?? current.turnId,
10478
+ iterationIndex: iterationIndex ?? current.iterationIndex
10479
+ };
10412
10480
  } else if (matchesExistingToolTurn && idx >= 0) {
10413
10481
  const current = messages[idx];
10414
10482
  messages[idx] = {
10415
10483
  ...current,
10416
- reasoning: responseContent ? appendText(current.reasoning, responseContent) : current.reasoning,
10484
+ content: responseContent ? appendText(current.content, responseContent) : current.content,
10417
10485
  status: "streaming",
10418
10486
  llmResponseEventId: event.eventId,
10419
10487
  turnId: turnId ?? current.turnId,
@@ -10423,8 +10491,8 @@ function applyLlmResponse(state, event) {
10423
10491
  messages.push({
10424
10492
  id: `evt-${event.eventId}`,
10425
10493
  role: "assistant",
10426
- content: hasToolCalls ? "" : responseContent,
10427
- reasoning: hasToolCalls && responseContent ? responseContent : void 0,
10494
+ content: responseContent,
10495
+ reasoning: void 0,
10428
10496
  createdAt: /* @__PURE__ */ new Date(),
10429
10497
  status: hasToolCalls ? "streaming" : "complete",
10430
10498
  llmResponseEventId: event.eventId,
@@ -10433,25 +10501,14 @@ function applyLlmResponse(state, event) {
10433
10501
  });
10434
10502
  } else {
10435
10503
  const current = messages[idx];
10436
- if (hasToolCalls && responseContent) {
10437
- messages[idx] = {
10438
- ...current,
10439
- reasoning: (current.reasoning ?? "") + responseContent,
10440
- status: "streaming",
10441
- llmResponseEventId: event.eventId,
10442
- turnId: turnId ?? current.turnId,
10443
- iterationIndex: iterationIndex ?? current.iterationIndex
10444
- };
10445
- } else {
10446
- messages[idx] = {
10447
- ...current,
10448
- content: responseContent || current.content,
10449
- status: hasToolCalls ? "streaming" : "complete",
10450
- llmResponseEventId: event.eventId,
10451
- turnId: turnId ?? current.turnId,
10452
- iterationIndex: iterationIndex ?? current.iterationIndex
10453
- };
10454
- }
10504
+ messages[idx] = {
10505
+ ...current,
10506
+ content: responseContent || current.content,
10507
+ status: hasToolCalls ? "streaming" : "complete",
10508
+ llmResponseEventId: event.eventId,
10509
+ turnId: turnId ?? current.turnId,
10510
+ iterationIndex: iterationIndex ?? current.iterationIndex
10511
+ };
10455
10512
  }
10456
10513
  const inputTokens = numberValue(event.data.input_tokens);
10457
10514
  const outputTokens = numberValue(event.data.output_tokens);
@@ -13825,7 +13882,7 @@ function TreeNodeRow({
13825
13882
  type: "button",
13826
13883
  className: cn(
13827
13884
  "p-2 md:p-1 rounded hover:bg-destructive/10 hover:text-destructive disabled:pointer-events-none transition-all",
13828
- deletingSessionId === entry.id ? "opacity-100" : "opacity-100 md:opacity-0 md:group-hover:opacity-100 md:focus-visible:opacity-100"
13885
+ deletingSessionId === entry.id ? "opacity-100" : "opacity-60 md:opacity-50 md:group-hover:opacity-100 md:focus-visible:opacity-100"
13829
13886
  ),
13830
13887
  onClick: (e) => {
13831
13888
  e.stopPropagation();