@agent-native/core 0.91.2 → 0.92.0

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 (216) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +17 -0
  3. package/corpus/core/docs/content/faq.mdx +17 -0
  4. package/corpus/core/docs/content/notifications.mdx +12 -6
  5. package/corpus/core/package.json +1 -1
  6. package/corpus/core/src/agent/production-agent.ts +140 -46
  7. package/corpus/core/src/agent/tool-search.ts +71 -4
  8. package/corpus/core/src/cli/index.ts +20 -0
  9. package/corpus/core/src/cli/upgrade.ts +798 -0
  10. package/corpus/core/src/client/AssistantChat.tsx +1 -1
  11. package/corpus/core/src/client/HighlightedCodeBlock.tsx +20 -3
  12. package/corpus/core/src/client/agent-chat-adapter.ts +31 -6
  13. package/corpus/core/src/client/chat/message-components.tsx +85 -8
  14. package/corpus/core/src/client/chat/tool-call-display.tsx +355 -144
  15. package/corpus/core/src/client/code-agent-chat-adapter.ts +2 -9
  16. package/corpus/core/src/client/session-replay.ts +3 -97
  17. package/corpus/core/src/client/settings/SettingsPanel.tsx +533 -389
  18. package/corpus/core/src/client/settings/SettingsSection.tsx +154 -17
  19. package/corpus/core/src/client/sse-event-processor.ts +29 -2
  20. package/corpus/core/src/extensions/actions.ts +113 -5
  21. package/corpus/core/src/notifications/channels.ts +88 -25
  22. package/corpus/core/src/notifications/registry.ts +17 -3
  23. package/corpus/core/src/notifications/types.ts +4 -1
  24. package/corpus/core/src/server/agent-chat-plugin.ts +7 -3
  25. package/corpus/core/src/server/request-context.ts +7 -0
  26. package/corpus/core/src/styles/agent-conversation.css +1 -1
  27. package/corpus/core/src/templates/default/.agents/skills/self-modifying-code/SKILL.md +20 -2
  28. package/corpus/core/src/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  29. package/corpus/core/src/templates/default/AGENTS.md +10 -3
  30. package/corpus/core/src/templates/default/package.json +2 -1
  31. package/corpus/core/src/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  32. package/corpus/core/src/templates/headless/AGENTS.md +9 -3
  33. package/corpus/core/src/templates/headless/package.json +1 -0
  34. package/corpus/core/src/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +20 -2
  35. package/corpus/core/src/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  36. package/corpus/core/src/templates/workspace-root/AGENTS.md +10 -4
  37. package/corpus/core/src/templates/workspace-root/package.json +1 -0
  38. package/corpus/templates/analytics/.agents/skills/self-modifying-code/SKILL.md +20 -2
  39. package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +5 -6
  40. package/corpus/templates/analytics/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  41. package/corpus/templates/analytics/AGENTS.md +7 -5
  42. package/corpus/templates/analytics/actions/save-monitor.ts +14 -0
  43. package/corpus/templates/analytics/app/components/dashboard/DataTable.tsx +41 -6
  44. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +122 -11
  45. package/corpus/templates/analytics/app/pages/monitoring/MonitoringPage.tsx +8 -2
  46. package/corpus/templates/analytics/app/pages/monitoring/uptime/MonitorFormPage.tsx +151 -32
  47. package/corpus/templates/analytics/app/pages/monitoring/uptime/i18n.ts +17 -2
  48. package/corpus/templates/analytics/app/pages/monitoring/uptime/types.ts +4 -0
  49. package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +54 -190
  50. package/corpus/templates/analytics/changelog/2026-07-08-dashboard-tables-keep-their-size-while-loading.md +6 -0
  51. package/corpus/templates/analytics/changelog/2026-07-08-monitoring-uptime-and-errors-tabs-now-clearly-show-which-view-is-active.md +6 -0
  52. package/corpus/templates/analytics/changelog/2026-07-08-session-replay-uses-stock-rrweb-sizing-again-so-recorded.md +6 -0
  53. package/corpus/templates/analytics/changelog/2026-07-08-sidebar-dashboard-menus-now-open-above-the-dashboard-canvas.md +6 -0
  54. package/corpus/templates/analytics/changelog/2026-07-08-uptime-alerting-clarifies-in-app-inbox-vs-email-and-lets-you-paste-slack-or-webhook-urls-per-monitor.md +6 -0
  55. package/corpus/templates/analytics/docs/uptime-monitoring.md +13 -11
  56. package/corpus/templates/analytics/server/db/schema-monitoring.ts +4 -0
  57. package/corpus/templates/analytics/server/lib/uptime-monitors.ts +60 -12
  58. package/corpus/templates/analytics/server/plugins/db.ts +10 -0
  59. package/corpus/templates/assets/.agents/skills/self-modifying-code/SKILL.md +20 -2
  60. package/corpus/templates/assets/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  61. package/corpus/templates/brain/.agents/skills/self-modifying-code/SKILL.md +20 -2
  62. package/corpus/templates/brain/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  63. package/corpus/templates/calendar/.agents/skills/self-modifying-code/SKILL.md +20 -2
  64. package/corpus/templates/calendar/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  65. package/corpus/templates/chat/.agents/skills/self-modifying-code/SKILL.md +20 -2
  66. package/corpus/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  67. package/corpus/templates/clips/.agents/skills/self-modifying-code/SKILL.md +20 -2
  68. package/corpus/templates/clips/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  69. package/corpus/templates/clips/changelog/2026-07-08-desktop-meeting-notes-stay-active-from-tray-and-shortcut-controls.md +6 -0
  70. package/corpus/templates/clips/changelog/2026-07-08-desktop-meeting-popovers-can-start-notes-and-join-the-meetin.md +6 -0
  71. package/corpus/templates/clips/changelog/2026-07-08-meeting-notes-keep-their-recording-state-when-the-desktop.md +6 -0
  72. package/corpus/templates/clips/changelog/2026-07-08-meeting-reminder-dropdowns-now-expand-fully-instead-of-being.md +6 -0
  73. package/corpus/templates/clips/desktop/src/app.tsx +123 -3
  74. package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +15 -1
  75. package/corpus/templates/clips/desktop/src/overlays/meeting-notification.tsx +23 -0
  76. package/corpus/templates/clips/desktop/src/styles.css +23 -1
  77. package/corpus/templates/clips/desktop/src-tauri/src/adhoc_meetings_watcher.rs +1 -3
  78. package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +40 -6
  79. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +4 -2
  80. package/corpus/templates/clips/desktop/src-tauri/src/meetings_watcher.rs +3 -5
  81. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +23 -19
  82. package/corpus/templates/clips/desktop/src-tauri/src/shortcuts.rs +3 -3
  83. package/corpus/templates/clips/desktop/src-tauri/src/silence_detector.rs +0 -1
  84. package/corpus/templates/clips/desktop/src-tauri/src/state.rs +5 -0
  85. package/corpus/templates/clips/desktop/src-tauri/src/tray.rs +18 -6
  86. package/corpus/templates/content/.agents/skills/self-modifying-code/SKILL.md +20 -2
  87. package/corpus/templates/content/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  88. package/corpus/templates/content/actions/_batch-utils.ts +8 -0
  89. package/corpus/templates/content/actions/_builder-cms-read-client.ts +7 -5
  90. package/corpus/templates/content/actions/_database-source-utils.ts +776 -319
  91. package/corpus/templates/content/actions/_database-utils.ts +6 -1
  92. package/corpus/templates/content/actions/_property-utils.ts +168 -0
  93. package/corpus/templates/content/actions/add-content-database-source-field-property.ts +19 -12
  94. package/corpus/templates/content/actions/bind-content-database-source-field.ts +19 -12
  95. package/corpus/templates/content/actions/delete-document.ts +9 -13
  96. package/corpus/templates/content/actions/refresh-content-database-source.ts +5 -5
  97. package/corpus/templates/content/app/components/editor/body-hydration.ts +35 -11
  98. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +47 -5
  99. package/corpus/templates/content/app/hooks/use-documents.ts +8 -2
  100. package/corpus/templates/content/changelog/2026-07-08-builder-source-sync-now-completes-reliably-on-hosted-databases.md +6 -0
  101. package/corpus/templates/content/changelog/2026-07-08-fixed-builder-database-sync-so-large-sources-continue-past-t.md +6 -0
  102. package/corpus/templates/content/server/plugins/db.ts +19 -0
  103. package/corpus/templates/design/.agents/skills/self-modifying-code/SKILL.md +20 -2
  104. package/corpus/templates/design/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  105. package/corpus/templates/dispatch/.agents/skills/self-modifying-code/SKILL.md +20 -2
  106. package/corpus/templates/dispatch/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  107. package/corpus/templates/forms/.agents/skills/self-modifying-code/SKILL.md +20 -2
  108. package/corpus/templates/forms/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  109. package/corpus/templates/macros/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  110. package/corpus/templates/mail/.agents/skills/self-modifying-code/SKILL.md +20 -2
  111. package/corpus/templates/mail/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  112. package/corpus/templates/plan/.agents/skills/self-modifying-code/SKILL.md +20 -2
  113. package/corpus/templates/plan/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  114. package/corpus/templates/slides/.agents/skills/self-modifying-code/SKILL.md +20 -2
  115. package/corpus/templates/slides/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  116. package/corpus/templates/videos/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  117. package/corpus/templates/voice/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  118. package/dist/agent/production-agent.d.ts +5 -1
  119. package/dist/agent/production-agent.d.ts.map +1 -1
  120. package/dist/agent/production-agent.js +112 -42
  121. package/dist/agent/production-agent.js.map +1 -1
  122. package/dist/agent/tool-search.d.ts +2 -0
  123. package/dist/agent/tool-search.d.ts.map +1 -1
  124. package/dist/agent/tool-search.js +60 -4
  125. package/dist/agent/tool-search.js.map +1 -1
  126. package/dist/cli/index.js +19 -0
  127. package/dist/cli/index.js.map +1 -1
  128. package/dist/cli/upgrade.d.ts +100 -0
  129. package/dist/cli/upgrade.d.ts.map +1 -0
  130. package/dist/cli/upgrade.js +678 -0
  131. package/dist/cli/upgrade.js.map +1 -0
  132. package/dist/client/AssistantChat.js +1 -1
  133. package/dist/client/AssistantChat.js.map +1 -1
  134. package/dist/client/HighlightedCodeBlock.d.ts +2 -0
  135. package/dist/client/HighlightedCodeBlock.d.ts.map +1 -1
  136. package/dist/client/HighlightedCodeBlock.js +10 -1
  137. package/dist/client/HighlightedCodeBlock.js.map +1 -1
  138. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  139. package/dist/client/agent-chat-adapter.js +32 -4
  140. package/dist/client/agent-chat-adapter.js.map +1 -1
  141. package/dist/client/chat/message-components.d.ts.map +1 -1
  142. package/dist/client/chat/message-components.js +61 -8
  143. package/dist/client/chat/message-components.js.map +1 -1
  144. package/dist/client/chat/tool-call-display.d.ts +12 -0
  145. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  146. package/dist/client/chat/tool-call-display.js +136 -42
  147. package/dist/client/chat/tool-call-display.js.map +1 -1
  148. package/dist/client/code-agent-chat-adapter.js +2 -9
  149. package/dist/client/code-agent-chat-adapter.js.map +1 -1
  150. package/dist/client/session-replay.d.ts +0 -8
  151. package/dist/client/session-replay.d.ts.map +1 -1
  152. package/dist/client/session-replay.js +3 -80
  153. package/dist/client/session-replay.js.map +1 -1
  154. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  155. package/dist/client/settings/SettingsPanel.js +52 -19
  156. package/dist/client/settings/SettingsPanel.js.map +1 -1
  157. package/dist/client/settings/SettingsSection.d.ts +19 -4
  158. package/dist/client/settings/SettingsSection.d.ts.map +1 -1
  159. package/dist/client/settings/SettingsSection.js +33 -4
  160. package/dist/client/settings/SettingsSection.js.map +1 -1
  161. package/dist/client/sse-event-processor.d.ts +9 -0
  162. package/dist/client/sse-event-processor.d.ts.map +1 -1
  163. package/dist/client/sse-event-processor.js +20 -2
  164. package/dist/client/sse-event-processor.js.map +1 -1
  165. package/dist/collab/routes.d.ts +1 -1
  166. package/dist/extensions/actions.d.ts.map +1 -1
  167. package/dist/extensions/actions.js +85 -5
  168. package/dist/extensions/actions.js.map +1 -1
  169. package/dist/notifications/channels.d.ts +8 -3
  170. package/dist/notifications/channels.d.ts.map +1 -1
  171. package/dist/notifications/channels.js +61 -22
  172. package/dist/notifications/channels.js.map +1 -1
  173. package/dist/notifications/registry.d.ts.map +1 -1
  174. package/dist/notifications/registry.js +14 -3
  175. package/dist/notifications/registry.js.map +1 -1
  176. package/dist/notifications/routes.d.ts +1 -1
  177. package/dist/notifications/types.d.ts +4 -1
  178. package/dist/notifications/types.d.ts.map +1 -1
  179. package/dist/notifications/types.js.map +1 -1
  180. package/dist/observability/routes.d.ts +1 -1
  181. package/dist/resources/handlers.d.ts +1 -1
  182. package/dist/server/agent-chat-plugin.d.ts +5 -1
  183. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  184. package/dist/server/agent-chat-plugin.js +2 -2
  185. package/dist/server/agent-chat-plugin.js.map +1 -1
  186. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  187. package/dist/server/request-context.d.ts +7 -0
  188. package/dist/server/request-context.d.ts.map +1 -1
  189. package/dist/server/request-context.js.map +1 -1
  190. package/dist/styles/agent-conversation.css +1 -1
  191. package/dist/templates/default/.agents/skills/self-modifying-code/SKILL.md +20 -2
  192. package/dist/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  193. package/dist/templates/default/AGENTS.md +10 -3
  194. package/dist/templates/default/package.json +2 -1
  195. package/dist/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  196. package/dist/templates/headless/AGENTS.md +9 -3
  197. package/dist/templates/headless/package.json +1 -0
  198. package/dist/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +20 -2
  199. package/dist/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  200. package/dist/templates/workspace-root/AGENTS.md +10 -4
  201. package/dist/templates/workspace-root/package.json +1 -0
  202. package/docs/content/faq.mdx +17 -0
  203. package/docs/content/notifications.mdx +12 -6
  204. package/package.json +2 -2
  205. package/src/templates/default/.agents/skills/self-modifying-code/SKILL.md +20 -2
  206. package/src/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  207. package/src/templates/default/AGENTS.md +10 -3
  208. package/src/templates/default/package.json +2 -1
  209. package/src/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  210. package/src/templates/headless/AGENTS.md +9 -3
  211. package/src/templates/headless/package.json +1 -0
  212. package/src/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +20 -2
  213. package/src/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  214. package/src/templates/workspace-root/AGENTS.md +10 -4
  215. package/src/templates/workspace-root/package.json +1 -0
  216. package/corpus/templates/analytics/changelog/2026-07-08-session-replay-clamps-ultra-wide-viewports-while-keeping-the.md +0 -6
@@ -355,7 +355,7 @@ function isAssistantUiDuplicateMessageIdError(error: unknown): boolean {
355
355
 
356
356
  function cloneContentParts(content: ContentPart[]): ContentPart[] {
357
357
  return content.map((part) =>
358
- part.type === "text"
358
+ part.type === "text" || part.type === "reasoning"
359
359
  ? { ...part }
360
360
  : {
361
361
  ...part,
@@ -8,6 +8,8 @@
8
8
  * - A content hash gate means identical re-renders never re-invoke Shiki.
9
9
  * - A final highlight is triggered immediately when streaming ends (caller
10
10
  * passes streaming=false).
11
+ * - Non-streaming first paint waits for Shiki (invisible placeholder reserves
12
+ * space) so the UI never snaps from plain text to highlighted HTML.
11
13
  *
12
14
  * Usage:
13
15
  * <HighlightedCodeBlock code={code} lang="typescript" containerClass="agent-markdown-shiki" />
@@ -69,6 +71,7 @@ export function HighlightedCodeBlock({
69
71
  loadHighlighter,
70
72
  }: HighlightedCodeBlockProps): React.ReactElement {
71
73
  const [html, setHtml] = useState<string | null>(null);
74
+ const [failed, setFailed] = useState(false);
72
75
  // Track the content hash for which html was last rendered so identical
73
76
  // re-renders never re-invoke Shiki.
74
77
  const renderedHashRef = useRef<number | null>(null);
@@ -111,12 +114,14 @@ export function HighlightedCodeBlock({
111
114
  .then((out) => {
112
115
  if (!cancelledRef.current) {
113
116
  renderedHashRef.current = contentHash;
117
+ setFailed(false);
114
118
  setHtml(out as string);
115
119
  }
116
120
  })
117
121
  .catch(() => {
118
122
  if (!cancelledRef.current) {
119
123
  renderedHashRef.current = contentHash;
124
+ setFailed(true);
120
125
  setHtml(null);
121
126
  }
122
127
  });
@@ -148,9 +153,21 @@ export function HighlightedCodeBlock({
148
153
  />
149
154
  );
150
155
  }
156
+
157
+ // Streaming: show plain growing text (previous html already kept above when
158
+ // available). Non-streaming first paint: reserve space invisibly so we never
159
+ // flash unhighlighted → highlighted.
160
+ const showPlain = streaming || failed;
151
161
  return (
152
- <pre>
153
- <code className={lang ? `language-${lang}` : undefined}>{code}</code>
154
- </pre>
162
+ <div className={containerClass} aria-busy={!showPlain && !failed}>
163
+ <pre>
164
+ <code
165
+ className={lang ? `language-${lang}` : undefined}
166
+ style={showPlain ? undefined : { visibility: "hidden" }}
167
+ >
168
+ {code}
169
+ </code>
170
+ </pre>
171
+ </div>
155
172
  );
156
173
  }
@@ -196,6 +196,7 @@ function contentToContinuationHistory(content: ContentPart[]): string {
196
196
  if (part.text.trim()) chunks.push(part.text.trim());
197
197
  continue;
198
198
  }
199
+ if (part.type === "reasoning") continue;
199
200
  if (part.activity === true) continue;
200
201
  const toolSummary = [
201
202
  `Tool: ${part.toolName}`,
@@ -577,6 +578,12 @@ function contentToStructuredMessages(
577
578
  continue;
578
579
  }
579
580
 
581
+ // Reasoning/thinking is UI-only — do not send chain-of-thought back into
582
+ // model history on continuation.
583
+ if (part.type === "reasoning") {
584
+ continue;
585
+ }
586
+
580
587
  if (isToolCallContentPart(part)) {
581
588
  if (part.activity === true) continue;
582
589
  const toolCallId = nextToolCallId();
@@ -736,11 +743,11 @@ function combineContinuationHistory(fragments: string[]): string {
736
743
  }
737
744
 
738
745
  function hasContinuationProgress(content: ContentPart[]): boolean {
739
- return content.some((part) =>
740
- part.type === "text"
741
- ? part.text.trim().length > 0
742
- : part.result !== undefined,
743
- );
746
+ return content.some((part) => {
747
+ if (part.type === "text") return part.text.trim().length > 0;
748
+ if (part.type === "reasoning") return false;
749
+ return part.result !== undefined;
750
+ });
744
751
  }
745
752
 
746
753
  const COMPLETED_TOOL_TIMEOUT_NAME_RE =
@@ -880,7 +887,9 @@ function lastUnresolvedToolActivity(
880
887
 
881
888
  function snapshotContent(content: ContentPart[]): ContentPart[] {
882
889
  return content.map((part) =>
883
- part.type === "text" ? { ...part } : { ...part, args: { ...part.args } },
890
+ part.type === "text" || part.type === "reasoning"
891
+ ? { ...part }
892
+ : { ...part, args: { ...part.args } },
884
893
  );
885
894
  }
886
895
 
@@ -952,6 +961,22 @@ function contentAfterContinuationPrefix(
952
961
  return content.slice(contentIndex);
953
962
  }
954
963
 
964
+ if (prefixPart.type === "reasoning" && currentPart.type === "reasoning") {
965
+ if (currentPart.text === prefixPart.text) {
966
+ contentIndex += 1;
967
+ continue;
968
+ }
969
+ if (currentPart.text.startsWith(prefixPart.text)) {
970
+ const appendedText = currentPart.text.slice(prefixPart.text.length);
971
+ if (appendedText) {
972
+ delta.push({ type: "reasoning", text: appendedText });
973
+ }
974
+ contentIndex += 1;
975
+ continue;
976
+ }
977
+ return content.slice(contentIndex);
978
+ }
979
+
955
980
  if (
956
981
  prefixPart.type === "tool-call" &&
957
982
  currentPart.type === "tool-call" &&
@@ -10,6 +10,7 @@ import {
10
10
  ActionBarPrimitive,
11
11
  BranchPickerPrimitive,
12
12
  ComposerPrimitive,
13
+ useMessagePartReasoning,
13
14
  } from "@assistant-ui/react";
14
15
  import type { Attachment } from "@assistant-ui/react";
15
16
  import {
@@ -66,6 +67,8 @@ import {
66
67
  ToolCallFallback,
67
68
  FilesChangedSummary,
68
69
  ChatRunningContext,
70
+ ReasoningCell,
71
+ WorkedForSummary,
69
72
  } from "./tool-call-display.js";
70
73
 
71
74
  // ─── Pending selection context key ───────────────────────────────────────────
@@ -793,7 +796,7 @@ function assistantMessageHasRenderableContent(message: {
793
796
  return content.some((part) => {
794
797
  if (!part || typeof part !== "object") return false;
795
798
  const type = (part as { type?: unknown }).type;
796
- if (type === "text") {
799
+ if (type === "text" || type === "reasoning") {
797
800
  const text = (part as { text?: unknown }).text;
798
801
  return typeof text === "string" && text.trim().length > 0;
799
802
  }
@@ -837,6 +840,21 @@ export function shouldShowAssistantMessageFooter({
837
840
  return !chatRunning && statusIsTerminal;
838
841
  }
839
842
 
843
+ function ReasoningMessagePart() {
844
+ const part = useMessagePartReasoning();
845
+ const isStreaming = part.status?.type === "running";
846
+ return <ReasoningCell text={part.text} isStreaming={isStreaming} />;
847
+ }
848
+
849
+ function groupAssistantWorkParts(part: {
850
+ type?: string;
851
+ }): ["group-work"] | null {
852
+ if (part.type === "reasoning" || part.type === "tool-call") {
853
+ return ["group-work"];
854
+ }
855
+ return null;
856
+ }
857
+
840
858
  export function AssistantMessage() {
841
859
  const [restoreState, setRestoreState] = useState<
842
860
  "idle" | "confirming" | "restoring"
@@ -860,6 +878,39 @@ export function AssistantMessage() {
860
878
  });
861
879
  const cpCtx = React.useContext(CheckpointContext);
862
880
 
881
+ // Capture live run duration when this message finishes streaming.
882
+ const runStartedAtRef = useRef<number | null>(null);
883
+ const [capturedDurationMs, setCapturedDurationMs] = useState<number | null>(
884
+ null,
885
+ );
886
+ useEffect(() => {
887
+ if (chatRunning && isLast) {
888
+ if (runStartedAtRef.current == null) {
889
+ runStartedAtRef.current = Date.now();
890
+ }
891
+ return;
892
+ }
893
+ if (
894
+ !chatRunning &&
895
+ isLast &&
896
+ runStartedAtRef.current != null &&
897
+ capturedDurationMs == null
898
+ ) {
899
+ setCapturedDurationMs(Date.now() - runStartedAtRef.current);
900
+ runStartedAtRef.current = null;
901
+ }
902
+ }, [chatRunning, isLast, capturedDurationMs]);
903
+
904
+ // Animate collapse only when this message just finished running in-session.
905
+ const wasRunningRef = useRef(false);
906
+ const [animateCollapse, setAnimateCollapse] = useState(false);
907
+ useEffect(() => {
908
+ if (wasRunningRef.current && !chatRunning && isComplete && isLast) {
909
+ setAnimateCollapse(true);
910
+ }
911
+ wasRunningRef.current = chatRunning && isLast;
912
+ }, [chatRunning, isComplete, isLast]);
913
+
863
914
  const handleRestore = useCallback(async () => {
864
915
  if (restoreState === "idle") {
865
916
  setRestoreState("confirming");
@@ -926,6 +977,13 @@ export function AssistantMessage() {
926
977
  (p.structuredMeta.toolKind === "edit" ||
927
978
  p.structuredMeta.toolKind === "write"),
928
979
  );
980
+ const hasCollapsibleWork =
981
+ Array.isArray(msgContent) &&
982
+ msgContent.some(
983
+ (p) =>
984
+ p.type === "reasoning" ||
985
+ (p.type === "tool-call" && p.activity !== true),
986
+ );
929
987
 
930
988
  if (!hasRenderableContent) return null;
931
989
 
@@ -935,14 +993,33 @@ export function AssistantMessage() {
935
993
  style={{ contentVisibility: isComplete ? "auto" : "visible" }}
936
994
  >
937
995
  <div className="w-full max-w-[95%] text-sm leading-relaxed text-foreground">
938
- <MessagePrimitive.Parts
939
- components={{
940
- Text: MarkdownText,
941
- tools: {
942
- Fallback: ToolCallFallback,
943
- },
996
+ <MessagePrimitive.GroupedParts groupBy={groupAssistantWorkParts}>
997
+ {({ part, children }) => {
998
+ switch (part.type) {
999
+ case "group-work": {
1000
+ const showSummary =
1001
+ isComplete && !chatRunning && hasCollapsibleWork;
1002
+ if (!showSummary) return <>{children}</>;
1003
+ return (
1004
+ <WorkedForSummary
1005
+ durationMs={capturedDurationMs}
1006
+ autoCollapse={animateCollapse}
1007
+ >
1008
+ {children}
1009
+ </WorkedForSummary>
1010
+ );
1011
+ }
1012
+ case "text":
1013
+ return <MarkdownText />;
1014
+ case "reasoning":
1015
+ return <ReasoningMessagePart />;
1016
+ case "tool-call":
1017
+ return part.toolUI ?? <ToolCallFallback {...part} />;
1018
+ default:
1019
+ return null;
1020
+ }
944
1021
  }}
945
- />
1022
+ </MessagePrimitive.GroupedParts>
946
1023
  {isComplete && hasCodeAgentTools && msgContent && (
947
1024
  <FilesChangedSummary parts={msgContent} />
948
1025
  )}