@agent-native/core 0.155.0 → 0.157.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.
Files changed (192) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/server/jobs/analytics-bigquery-backfill.ts +19 -4
  3. package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +7 -2
  4. package/corpus/templates/assets/app/components/asset/AssetPreviewDialog.tsx +3 -1
  5. package/corpus/templates/assets/app/global.css +4 -0
  6. package/corpus/templates/assets/app/i18n-data.ts +21 -1
  7. package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +18 -15
  8. package/corpus/templates/brain/app/routes/sources.tsx +1 -2
  9. package/corpus/templates/calendar/app/hooks/use-bookings.ts +12 -2
  10. package/corpus/templates/calendar/app/pages/BookingLinksPage.tsx +64 -2
  11. package/corpus/templates/calendar/server/handlers/bookings.ts +219 -93
  12. package/corpus/templates/calendar/server/plugins/auth.ts +0 -2
  13. package/corpus/templates/clips/actions/create-folder.ts +7 -1
  14. package/corpus/templates/clips/actions/create-meeting.ts +6 -2
  15. package/corpus/templates/clips/actions/create-recording.ts +5 -3
  16. package/corpus/templates/clips/actions/finalize-recording.ts +97 -65
  17. package/corpus/templates/clips/actions/import-loom-recording.ts +5 -3
  18. package/corpus/templates/clips/actions/request-recording-access.ts +272 -0
  19. package/corpus/templates/clips/actions/stitch-recordings.ts +5 -3
  20. package/corpus/templates/clips/app/components/meetings/share-meeting-dialog.tsx +38 -63
  21. package/corpus/templates/clips/app/components/player/share-dialog.tsx +177 -134
  22. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +3 -21
  23. package/corpus/templates/clips/app/components/sharing/share-ui.tsx +13 -30
  24. package/corpus/templates/clips/app/i18n/en-US.ts +10 -0
  25. package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +5 -5
  26. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +24 -17
  27. package/corpus/templates/clips/app/routes/share.$shareId.tsx +151 -20
  28. package/corpus/templates/clips/changelog/2026-08-14-long-resumable-uploads-now-abort-cleanly-and-show-errors.md +6 -0
  29. package/corpus/templates/clips/changelog/2026-08-14-standardized-share-popovers.md +6 -0
  30. package/corpus/templates/clips/chrome-extension/public/manifest.json +11 -3
  31. package/corpus/templates/clips/chrome-extension/src/github-preview-content.ts +37 -8
  32. package/corpus/templates/clips/chrome-extension/src/github-preview.ts +3 -3
  33. package/corpus/templates/clips/chrome-extension/src/offscreen.ts +8 -25
  34. package/corpus/templates/clips/desktop/src/app.tsx +24 -0
  35. package/corpus/templates/clips/desktop/src/lib/media-capture-constraints.ts +42 -13
  36. package/corpus/templates/clips/desktop/src/lib/recorder.ts +11 -18
  37. package/corpus/templates/clips/desktop/src/overlays/onboarding.tsx +1 -0
  38. package/corpus/templates/clips/desktop/src/shared/config.ts +1 -0
  39. package/corpus/templates/clips/desktop/src/styles.css +24 -9
  40. package/corpus/templates/clips/desktop/src-tauri/Cargo.toml +3 -0
  41. package/corpus/templates/clips/desktop/src-tauri/src/config.rs +8 -0
  42. package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +154 -176
  43. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +115 -31
  44. package/corpus/templates/clips/desktop/src-tauri/src/rewind_clip.rs +7 -0
  45. package/corpus/templates/clips/server/db/index.ts +1 -0
  46. package/corpus/templates/clips/server/db/schema.ts +1 -0
  47. package/corpus/templates/clips/server/lib/calendar-event-meetings.ts +6 -1
  48. package/corpus/templates/clips/server/lib/emails.ts +23 -0
  49. package/corpus/templates/clips/server/lib/public-agent-context.ts +55 -0
  50. package/corpus/templates/clips/server/lib/recordings.ts +2 -1
  51. package/corpus/templates/clips/server/lib/resumable-upload-cleanup.ts +49 -0
  52. package/corpus/templates/clips/server/lib/s3-upload-provider.ts +34 -7
  53. package/corpus/templates/clips/server/lib/upload-interruption.ts +15 -1
  54. package/corpus/templates/clips/server/lib/upload-lease.ts +94 -9
  55. package/corpus/templates/clips/server/routes/api/agent-context.json.get.ts +82 -7
  56. package/corpus/templates/clips/server/routes/api/public-recording.get.ts +1 -0
  57. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +71 -12
  58. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/interrupt.post.ts +4 -3
  59. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/reset-chunks.post.ts +19 -0
  60. package/corpus/templates/clips/server/routes/api/uploads/reap.post.ts +8 -1
  61. package/corpus/templates/clips/shared/recording-link.ts +4 -0
  62. package/corpus/templates/clips/shared/share-loader-response.ts +2 -1
  63. package/corpus/templates/content/app/components/editor/DocumentToolbar.tsx +7 -16
  64. package/corpus/templates/factory/AGENTS.md +5 -1
  65. package/corpus/templates/factory/README.md +6 -2
  66. package/corpus/templates/factory/actions/view-screen.ts +15 -0
  67. package/corpus/templates/factory/app/components/factory/FactoryAgentsView.tsx +58 -189
  68. package/corpus/templates/factory/app/components/layout/Header.tsx +1 -0
  69. package/corpus/templates/factory/app/components/layout/Layout.tsx +1 -1
  70. package/corpus/templates/factory/app/components/layout/Sidebar.tsx +7 -0
  71. package/corpus/templates/factory/app/hooks/use-navigation-state.ts +3 -0
  72. package/corpus/templates/factory/app/i18n/en-US.ts +3 -1
  73. package/corpus/templates/factory/app/routes/agents.tsx +9 -0
  74. package/corpus/templates/mail/server/plugins/auth.ts +0 -2
  75. package/corpus/templates/plan/app/components/plan/LocalCodebasePicker.tsx +50 -14
  76. package/corpus/templates/plan/app/pages/PlansPage.tsx +9 -19
  77. package/corpus/templates/slides/app/components/editor/AddSlidePopover.tsx +98 -29
  78. package/corpus/templates/slides/app/components/editor/EditorActionCluster.tsx +45 -91
  79. package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +94 -2
  80. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +17 -29
  81. package/corpus/templates/slides/app/components/editor/HistoryPanel.tsx +7 -1
  82. package/corpus/templates/slides/app/components/editor/SlideContextToolbar.tsx +1 -1
  83. package/corpus/templates/slides/app/context/DeckContext.tsx +108 -19
  84. package/corpus/templates/slides/app/global.css +7 -40
  85. package/corpus/templates/slides/app/i18n/en-US.ts +4 -0
  86. package/corpus/templates/slides/app/lib/editor-shortcuts.ts +46 -0
  87. package/corpus/templates/slides/app/pages/DeckEditor.tsx +143 -45
  88. package/dist/agent/index.d.ts +1 -1
  89. package/dist/agent/production-agent.d.ts +30 -0
  90. package/dist/agent/production-agent.js +100 -8
  91. package/dist/agent/types.d.ts +9 -0
  92. package/dist/client/AgentPanel.d.ts +13 -1
  93. package/dist/client/AgentPanel.js +22 -17
  94. package/dist/client/AssistantChat.d.ts +15 -1
  95. package/dist/client/AssistantChat.js +135 -48
  96. package/dist/client/HighlightedCodeBlock.js +12 -2
  97. package/dist/client/MultiTabAssistantChat.js +44 -27
  98. package/dist/client/agent-chat/index.d.ts +1 -0
  99. package/dist/client/agent-chat/index.js +1 -0
  100. package/dist/client/chat/markdown-renderer.js +20 -5
  101. package/dist/client/chat/message-components.d.ts +2 -2
  102. package/dist/client/chat/message-components.js +69 -35
  103. package/dist/client/chat/run-recovery.d.ts +4 -1
  104. package/dist/client/chat/run-recovery.js +62 -30
  105. package/dist/client/chat/tool-call-display.d.ts +12 -3
  106. package/dist/client/chat/tool-call-display.js +79 -40
  107. package/dist/client/chat/widgets/DataChartRenderer.js +3 -1
  108. package/dist/client/chat/widgets/DataChartWidget.js +8 -2
  109. package/dist/client/chat/widgets/DataInsightsWidget.js +3 -1
  110. package/dist/client/chat/widgets/DataTableWidget.js +23 -9
  111. package/dist/client/chat/widgets/builtin-tool-renderers.js +3 -1
  112. package/dist/client/chat-first/apps-rail.js +1 -1
  113. package/dist/client/components/ui/message-scroller.d.ts +1 -1
  114. package/dist/client/components/ui/message-scroller.js +7 -3
  115. package/dist/client/composer/runtime-adapters.js +3 -2
  116. package/dist/client/context-xray/ContextMeter.js +5 -1
  117. package/dist/client/context-xray/ContextXRayPanel.js +5 -5
  118. package/dist/client/error-format.d.ts +4 -0
  119. package/dist/client/error-format.js +93 -5
  120. package/dist/client/i18n.js +83 -17
  121. package/dist/client/observability/ThumbsFeedback.js +10 -8
  122. package/dist/client/settings/AccountSettingsCard.js +48 -19
  123. package/dist/client/sharing/ShareButton.d.ts +1 -2
  124. package/dist/client/sharing/ShareButton.js +151 -81
  125. package/dist/client/sharing/ShareDialog.js +5 -4
  126. package/dist/client/use-chat-threads.js +10 -14
  127. package/dist/coding-tools/run-code.js +2 -1
  128. package/dist/coding-tools/sandbox/background.d.ts +1 -0
  129. package/dist/coding-tools/sandbox/background.js +8 -1
  130. package/dist/coding-tools/sandbox/executions-store.d.ts +2 -0
  131. package/dist/coding-tools/sandbox/executions-store.js +41 -3
  132. package/dist/collab/routes.d.ts +1 -1
  133. package/dist/collab/struct-routes.d.ts +1 -1
  134. package/dist/index.d.ts +1 -1
  135. package/dist/localization/core-messages/ar-SA.d.ts +3 -0
  136. package/dist/localization/core-messages/ar-SA.js +541 -0
  137. package/dist/localization/core-messages/de-DE.d.ts +3 -0
  138. package/dist/localization/core-messages/de-DE.js +513 -0
  139. package/dist/localization/core-messages/en-US.d.ts +513 -0
  140. package/dist/localization/core-messages/en-US.js +513 -0
  141. package/dist/localization/core-messages/es-ES.d.ts +3 -0
  142. package/dist/localization/core-messages/es-ES.js +520 -0
  143. package/dist/localization/core-messages/fr-FR.d.ts +3 -0
  144. package/dist/localization/core-messages/fr-FR.js +520 -0
  145. package/dist/localization/core-messages/hi-IN.d.ts +3 -0
  146. package/dist/localization/core-messages/hi-IN.js +513 -0
  147. package/dist/localization/core-messages/ja-JP.d.ts +3 -0
  148. package/dist/localization/core-messages/ja-JP.js +506 -0
  149. package/dist/localization/core-messages/ko-KR.d.ts +3 -0
  150. package/dist/localization/core-messages/ko-KR.js +506 -0
  151. package/dist/localization/core-messages/pt-BR.d.ts +3 -0
  152. package/dist/localization/core-messages/pt-BR.js +520 -0
  153. package/dist/localization/core-messages/zh-CN.d.ts +3 -0
  154. package/dist/localization/core-messages/zh-CN.js +506 -0
  155. package/dist/localization/core-messages/zh-TW.d.ts +3 -0
  156. package/dist/localization/core-messages/zh-TW.js +506 -0
  157. package/dist/localization/core-messages.d.ts +524 -0
  158. package/dist/localization/core-messages.js +124 -0
  159. package/dist/localization/default-messages.d.ts +3 -0
  160. package/dist/localization/default-messages.js +3 -0
  161. package/dist/notifications/routes.d.ts +1 -1
  162. package/dist/observability/routes.d.ts +5 -5
  163. package/dist/progress/routes.d.ts +1 -1
  164. package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
  165. package/dist/provider-api/actions/provider-api.d.ts +15 -15
  166. package/dist/resources/handlers.d.ts +1 -1
  167. package/dist/secrets/routes.d.ts +9 -9
  168. package/dist/server/agent-chat/plugin-options.d.ts +7 -2
  169. package/dist/server/agent-chat-plugin.d.ts +10 -0
  170. package/dist/server/agent-chat-plugin.js +144 -41
  171. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  172. package/dist/server/agent-run-context.d.ts +7 -1
  173. package/dist/server/agent-run-context.js +9 -2
  174. package/dist/server/agent-teams-run-queue.d.ts +3 -0
  175. package/dist/server/agent-teams.js +38 -9
  176. package/dist/server/auth-marketing.d.ts +1 -0
  177. package/dist/server/auth-marketing.js +0 -2
  178. package/dist/server/auth.d.ts +1 -0
  179. package/dist/server/auth.js +18 -0
  180. package/dist/server/index.d.ts +1 -1
  181. package/dist/server/onboarding-html.d.ts +1 -0
  182. package/dist/server/onboarding-html.js +2 -88
  183. package/dist/server/realtime-token.d.ts +1 -1
  184. package/dist/server/request-context.d.ts +7 -0
  185. package/dist/server/request-context.js +15 -0
  186. package/dist/shared/markdown-block-split.d.ts +16 -0
  187. package/dist/shared/markdown-block-split.js +81 -5
  188. package/dist/styles/agent-native.css +13 -0
  189. package/dist/voice/voice-cleanup-prompt.js +1 -0
  190. package/docs/content/agent-surfaces.mdx +30 -0
  191. package/package.json +2 -2
  192. package/corpus/templates/clips/shared/mic-audio-cleanup.ts +0 -350
@@ -12,6 +12,7 @@ import { fetchBuilderStatus, fetchEnvironmentStatus, } from "./client-status-req
12
12
  import { Popover, PopoverAnchor, PopoverContent, } from "./components/ui/popover.js";
13
13
  import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "./components/ui/tooltip.js";
14
14
  import { isTrustedFrameMessage } from "./frame.js";
15
+ import { DEFAULT_LOCALE, useOptionalLocale, useT } from "./i18n.js";
15
16
  import { RunStuckBanner } from "./RunStuckBanner.js";
16
17
  import { callAction } from "./use-action.js";
17
18
  import { useChangeVersion } from "./use-change-version.js";
@@ -118,20 +119,25 @@ function formatScopeType(type) {
118
119
  return type.replace(/[-_]+/g, " ");
119
120
  }
120
121
  // ─── History Popover ─────────────────────────────────────────────────────────
121
- function formatThreadTime(ts) {
122
+ function formatThreadTime(ts, locale, yesterdayLabel) {
122
123
  const d = new Date(ts);
123
124
  const now = new Date();
124
125
  const diffMs = now.getTime() - d.getTime();
125
126
  const diffDays = Math.floor(diffMs / 86400000);
126
127
  if (diffDays === 0)
127
- return d.toLocaleTimeString([], { hour: "numeric", minute: "2-digit" });
128
+ return d.toLocaleTimeString(locale, {
129
+ hour: "numeric",
130
+ minute: "2-digit",
131
+ });
128
132
  if (diffDays === 1)
129
- return "Yesterday";
133
+ return yesterdayLabel;
130
134
  if (diffDays < 7)
131
- return d.toLocaleDateString([], { weekday: "short" });
132
- return d.toLocaleDateString([], { month: "short", day: "numeric" });
135
+ return d.toLocaleDateString(locale, { weekday: "short" });
136
+ return d.toLocaleDateString(locale, { month: "short", day: "numeric" });
133
137
  }
134
138
  function HistoryPopover({ threads, openTabIds, activeThreadId, hasMoreThreads = false, isLoadingMoreThreads = false, loadError, onSelect, onClose, onLoadMore, onSearch, onTogglePin, onRename, }) {
139
+ const t = useT();
140
+ const locale = useOptionalLocale()?.locale ?? DEFAULT_LOCALE;
135
141
  const [search, setSearch] = useState("");
136
142
  const [searchResults, setSearchResults] = useState(null);
137
143
  const [isSearching, setIsSearching] = useState(false);
@@ -189,7 +195,7 @@ function HistoryPopover({ threads, openTabIds, activeThreadId, hasMoreThreads =
189
195
  const unpinnedThreads = filtered.filter((t) => t.pinnedAt == null);
190
196
  const toHistoryItem = (thread) => {
191
197
  const isActive = thread.id === activeThreadId;
192
- const title = thread.title || thread.preview || "Chat";
198
+ const title = thread.title || thread.preview || t("agentChat.history.untitledChat");
193
199
  return {
194
200
  id: thread.id,
195
201
  title,
@@ -198,10 +204,10 @@ function HistoryPopover({ threads, openTabIds, activeThreadId, hasMoreThreads =
198
204
  ? thread.preview
199
205
  : undefined,
200
206
  timestamp: isActive
201
- ? "Active"
207
+ ? t("agentChat.history.active")
202
208
  : openTabIds.has(thread.id)
203
- ? "Open"
204
- : formatThreadTime(thread.updatedAt),
209
+ ? t("agentChat.history.open")
210
+ : formatThreadTime(thread.updatedAt, locale, t("agentChat.history.yesterday")),
205
211
  pinned: thread.pinnedAt != null,
206
212
  };
207
213
  };
@@ -210,7 +216,7 @@ function HistoryPopover({ threads, openTabIds, activeThreadId, hasMoreThreads =
210
216
  ? [
211
217
  {
212
218
  id: "pinned",
213
- label: "Pinned",
219
+ label: t("agentChat.history.pinned"),
214
220
  items: pinnedThreads.map(toHistoryItem),
215
221
  },
216
222
  ]
@@ -228,10 +234,13 @@ function HistoryPopover({ threads, openTabIds, activeThreadId, hasMoreThreads =
228
234
  const isPinned = threads.find((t) => t.id === id)?.pinnedAt != null;
229
235
  onTogglePin(id, !isPinned);
230
236
  }
231
- : undefined, onRename: onRename, searchValue: search, onSearchChange: setSearch, searchPlaceholder: "Search chats...", searchInputRef: inputRef, loading: isSearching, loadingLabel: "Searching...", error: loadError && !search.trim() ? loadError : undefined, emptyLabel: "No chats yet", emptySearchLabel: "No matching chats", footer: !search.trim() && hasMoreThreads ? (_jsx("button", { type: "button", onClick: () => onLoadMore?.(), disabled: isLoadingMoreThreads, className: "mx-1 mt-1 flex w-[calc(100%-0.5rem)] items-center justify-center rounded-md px-3 py-2 text-xs text-muted-foreground hover:bg-accent hover:text-foreground disabled:cursor-default disabled:opacity-60", children: isLoadingMoreThreads ? "Loading..." : "Load older chats" })) : undefined }) })] }));
237
+ : undefined, onRename: onRename, searchValue: search, onSearchChange: setSearch, searchPlaceholder: t("agentChat.history.search"), searchInputRef: inputRef, loading: isSearching, loadingLabel: t("agentChat.history.searching"), error: loadError && !search.trim() ? loadError : undefined, emptyLabel: t("agentChat.history.empty"), emptySearchLabel: t("agentChat.history.noMatches"), footer: !search.trim() && hasMoreThreads ? (_jsx("button", { type: "button", onClick: () => onLoadMore?.(), disabled: isLoadingMoreThreads, className: "mx-1 mt-1 flex w-[calc(100%-0.5rem)] items-center justify-center rounded-md px-3 py-2 text-xs text-muted-foreground hover:bg-accent hover:text-foreground disabled:cursor-default disabled:opacity-60", children: isLoadingMoreThreads
238
+ ? t("agentChat.common.loading")
239
+ : t("agentChat.history.loadOlder") })) : undefined }) })] }));
232
240
  }
233
241
  // ─── Help Popover ────────────────────────────────────────────────────────────
234
242
  function HelpPopover({ onClose }) {
243
+ const t = useT();
235
244
  useEffect(() => {
236
245
  const handler = (e) => {
237
246
  if (e.key === "Escape")
@@ -243,16 +252,16 @@ function HelpPopover({ onClose }) {
243
252
  const commands = [
244
253
  {
245
254
  name: "/clear",
246
- description: "Start a new chat (keeps current chat in history)",
255
+ description: t("agentChat.commands.clear"),
247
256
  },
248
- { name: "/new", description: "Same as /clear" },
249
- { name: "/history", description: "Browse all chats" },
250
- { name: "/plan", description: "Switch to read-only planning" },
251
- { name: "/act", description: "Switch back to acting" },
252
- { name: "/help", description: "Show this list of commands" },
253
- { name: "@", description: "Mention files, agents, or resources" },
257
+ { name: "/new", description: t("agentChat.commands.new") },
258
+ { name: "/history", description: t("agentChat.commands.history") },
259
+ { name: "/plan", description: t("agentChat.commands.plan") },
260
+ { name: "/act", description: t("agentChat.commands.act") },
261
+ { name: "/help", description: t("agentChat.commands.help") },
262
+ { name: "@", description: t("agentChat.commands.mention") },
254
263
  ];
255
- return (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40", onClick: onClose }), _jsxs("div", { className: "absolute end-2 top-0 z-50 w-72 rounded-lg border border-border bg-popover shadow-lg", children: [_jsxs("div", { className: "flex items-center justify-between px-3 py-2 border-b border-border", children: [_jsx("span", { className: "text-xs font-medium text-foreground", children: "Available Commands" }), _jsx("button", { onClick: onClose, "aria-label": "Close help", className: "flex h-5 w-5 items-center justify-center rounded text-muted-foreground hover:text-foreground", children: _jsx(IconX, { size: 12 }) })] }), _jsx("div", { className: "py-1", children: commands.map((cmd) => (_jsxs("div", { className: "px-3 py-1.5", children: [_jsx("div", { className: "text-xs font-medium text-foreground", children: cmd.name }), _jsx("div", { className: "text-[11px] text-muted-foreground", children: cmd.description })] }, cmd.name))) })] })] }));
264
+ return (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40", onClick: onClose }), _jsxs("div", { className: "absolute end-2 top-0 z-50 w-72 rounded-lg border border-border bg-popover shadow-lg", children: [_jsxs("div", { className: "flex items-center justify-between px-3 py-2 border-b border-border", children: [_jsx("span", { className: "text-xs font-medium text-foreground", children: t("agentChat.commands.available") }), _jsx("button", { onClick: onClose, "aria-label": t("agentChat.commands.closeHelp"), className: "flex h-5 w-5 items-center justify-center rounded text-muted-foreground hover:text-foreground", children: _jsx(IconX, { size: 12 }) })] }), _jsx("div", { className: "py-1", children: commands.map((cmd) => (_jsxs("div", { className: "px-3 py-1.5", children: [_jsx("div", { className: "text-xs font-medium text-foreground", children: cmd.name }), _jsx("div", { className: "text-[11px] text-muted-foreground", children: cmd.description })] }, cmd.name))) })] })] }));
256
265
  }
257
266
  function readString(value) {
258
267
  return typeof value === "string" ? value.trim() : "";
@@ -376,6 +385,7 @@ function runToAgentTeamTabInfo(run) {
376
385
  };
377
386
  }
378
387
  export function MultiTabAssistantChat({ showTabBar = true, renderHeader, renderOverlay, contentHidden = false, apiUrl = agentNativePath("/_agent-native/agent-chat"), storageKey, restoreActiveThread = true, browserTabId, threadUrlSync = false, scope = null, agentTeamPollMs = DEFAULT_AGENT_TEAM_POLL_MS, ...props }) {
388
+ const translate = useT();
379
389
  const { enabled: threadUrlSyncEnabled, paramName: threadUrlParamName, routeThreadId, getPath: getThreadPath, navigate: navigateThreadUrl, } = resolveThreadUrlSync(threadUrlSync);
380
390
  const threadRouteControlsActiveThread = threadUrlSyncEnabled &&
381
391
  threadUrlSync !== true &&
@@ -1661,7 +1671,9 @@ export function MultiTabAssistantChat({ showTabBar = true, renderHeader, renderO
1661
1671
  const agentTeamStatus = chatTabStatusFromAgentTeamStatus(subAgentStatuses[id]);
1662
1672
  return {
1663
1673
  id,
1664
- label: t?.title || t?.preview?.slice(0, 30) || "New chat",
1674
+ label: t?.title ||
1675
+ t?.preview?.slice(0, 30) ||
1676
+ translate("agentChat.tabs.newChat"),
1665
1677
  status: agentTeamStatus ??
1666
1678
  (runningThreads.has(id)
1667
1679
  ? "running"
@@ -1677,7 +1689,10 @@ export function MultiTabAssistantChat({ showTabBar = true, renderHeader, renderO
1677
1689
  if (!tabs.some((t) => t.id === id)) {
1678
1690
  tabs.push({
1679
1691
  id,
1680
- label: subAgentNames[id] || (parentMap[id] ? "Sub-agent..." : "New chat"),
1692
+ label: subAgentNames[id] ||
1693
+ (parentMap[id]
1694
+ ? translate("agentChat.tabs.subAgent")
1695
+ : translate("agentChat.tabs.newChat")),
1681
1696
  status: chatTabStatusFromAgentTeamStatus(subAgentStatuses[id]) ??
1682
1697
  "running",
1683
1698
  parentThreadId: parentMap[id],
@@ -1726,7 +1741,7 @@ export function MultiTabAssistantChat({ showTabBar = true, renderHeader, renderO
1726
1741
  activeTab?.parentThreadId === tab.id);
1727
1742
  return (_jsxs("div", { ref: isActive ? activeTabRefCb : undefined, className: cn("agent-tab relative flex items-center rounded-md text-[11px] font-medium shrink-0 max-w-[130px]", isActive
1728
1743
  ? "bg-accent text-foreground ring-1 ring-inset ring-border/60 shadow-sm"
1729
- : "text-muted-foreground hover:text-foreground hover:bg-accent/50"), children: [_jsxs("button", { type: "button", onClick: () => switchThread(tab.id), className: "flex items-center gap-1 px-2.5 py-1.5 min-w-0 flex-1 text-start", children: [_jsx("span", { className: "truncate pe-1", children: tab.label }), tab.status === "running" && (_jsx("span", { className: "w-1.5 h-1.5 rounded-full bg-muted-foreground/50 shrink-0 animate-pulse" }))] }), _jsx("button", { type: "button", "aria-label": "Close tab", onClick: (e) => {
1744
+ : "text-muted-foreground hover:text-foreground hover:bg-accent/50"), children: [_jsxs("button", { type: "button", onClick: () => switchThread(tab.id), className: "flex items-center gap-1 px-2.5 py-1.5 min-w-0 flex-1 text-start", children: [_jsx("span", { className: "truncate pe-1", children: tab.label }), tab.status === "running" && (_jsx("span", { className: "w-1.5 h-1.5 rounded-full bg-muted-foreground/50 shrink-0 animate-pulse" }))] }), _jsx("button", { type: "button", "aria-label": translate("agentChat.tabs.closeTab"), onClick: (e) => {
1730
1745
  e.stopPropagation();
1731
1746
  e.preventDefault();
1732
1747
  closeTab(tab.id);
@@ -1740,13 +1755,13 @@ export function MultiTabAssistantChat({ showTabBar = true, renderHeader, renderO
1740
1755
  borderRadius: "0 6px 6px 0",
1741
1756
  background: "linear-gradient(to right, transparent, hsl(var(--accent)) 40%)",
1742
1757
  }, children: _jsx(IconX, { size: 12 }) })] }, tab.id));
1743
- }) }), _jsx(TooltipProvider, { delayDuration: 200, children: _jsxs("div", { className: "flex items-center gap-px shrink-0 ms-auto", children: [_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { onClick: addTab, "aria-label": "New chat", className: "flex h-6 w-6 items-center justify-center rounded text-muted-foreground/60 hover:text-foreground hover:bg-accent/50", children: _jsx(IconPlus, { size: 12 }) }) }), _jsx(TooltipContent, { children: "New chat" })] }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { onClick: () => setShowHistory(!showHistory), "aria-label": "All chats", className: cn("flex h-6 w-6 items-center justify-center rounded text-muted-foreground/60 hover:text-foreground hover:bg-accent/50", showHistory && "bg-accent text-foreground"), children: _jsx(IconHistory, { size: 12 }) }) }), _jsx(TooltipContent, { children: "All chats" })] })] }) })] }), hasSubTabs && (_jsx("div", { className: "flex items-center px-1 py-0.5 border-b border-border shrink-0 gap-0.5 bg-muted/30", children: _jsxs("div", { className: "agent-tabs-scroll flex items-center gap-0.5 min-w-0 overflow-x-auto flex-1", children: [_jsx("button", { onClick: () => switchThread(focusParentId), className: cn("flex shrink-0 items-center gap-1 rounded-md px-2 py-1 text-[10px] font-medium cursor-pointer", activeThreadId === focusParentId
1758
+ }) }), _jsx(TooltipProvider, { delayDuration: 200, children: _jsxs("div", { className: "flex items-center gap-px shrink-0 ms-auto", children: [_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { onClick: addTab, "aria-label": translate("agentChat.tabs.newChat"), className: "flex h-6 w-6 items-center justify-center rounded text-muted-foreground/60 hover:text-foreground hover:bg-accent/50", children: _jsx(IconPlus, { size: 12 }) }) }), _jsx(TooltipContent, { children: translate("agentChat.tabs.newChat") })] }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { onClick: () => setShowHistory(!showHistory), "aria-label": translate("agentChat.tabs.allChats"), className: cn("flex h-6 w-6 items-center justify-center rounded text-muted-foreground/60 hover:text-foreground hover:bg-accent/50", showHistory && "bg-accent text-foreground"), children: _jsx(IconHistory, { size: 12 }) }) }), _jsx(TooltipContent, { children: translate("agentChat.tabs.allChats") })] })] }) })] }), hasSubTabs && (_jsx("div", { className: "flex items-center px-1 py-0.5 border-b border-border shrink-0 gap-0.5 bg-muted/30", children: _jsxs("div", { className: "agent-tabs-scroll flex items-center gap-0.5 min-w-0 overflow-x-auto flex-1", children: [_jsx("button", { onClick: () => switchThread(focusParentId), className: cn("flex shrink-0 items-center gap-1 rounded-md px-2 py-1 text-[10px] font-medium cursor-pointer", activeThreadId === focusParentId
1744
1759
  ? "bg-accent text-foreground"
1745
- : "text-muted-foreground hover:bg-accent hover:text-foreground"), children: "Main" }), childTabs.map((tab) => (_jsxs("div", { ref: tab.id === activeThreadId
1760
+ : "text-muted-foreground hover:bg-accent hover:text-foreground"), children: translate("agentChat.tabs.main") }), childTabs.map((tab) => (_jsxs("div", { ref: tab.id === activeThreadId
1746
1761
  ? activeTabRefCb
1747
1762
  : undefined, className: cn("agent-tab relative flex shrink-0 items-center rounded-md text-[10px] font-medium max-w-[130px]", tab.id === activeThreadId
1748
1763
  ? "bg-accent text-foreground"
1749
- : "text-muted-foreground hover:bg-accent hover:text-foreground"), children: [_jsxs("button", { type: "button", onClick: () => switchThread(tab.id), className: "flex items-center gap-1 px-2 py-1 min-w-0 flex-1 text-start", children: [_jsx("span", { className: "truncate pe-1", children: tab.subAgentName || tab.label }), tab.status === "running" && (_jsx("span", { className: "w-1 h-1 rounded-full bg-muted-foreground/50 shrink-0 animate-pulse" }))] }), _jsx("button", { type: "button", "aria-label": "Close tab", onClick: (e) => {
1764
+ : "text-muted-foreground hover:bg-accent hover:text-foreground"), children: [_jsxs("button", { type: "button", onClick: () => switchThread(tab.id), className: "flex items-center gap-1 px-2 py-1 min-w-0 flex-1 text-start", children: [_jsx("span", { className: "truncate pe-1", children: tab.subAgentName || tab.label }), tab.status === "running" && (_jsx("span", { className: "w-1 h-1 rounded-full bg-muted-foreground/50 shrink-0 animate-pulse" }))] }), _jsx("button", { type: "button", "aria-label": translate("agentChat.tabs.closeTab"), onClick: (e) => {
1750
1765
  e.stopPropagation();
1751
1766
  e.preventDefault();
1752
1767
  closeTab(tab.id);
@@ -1772,7 +1787,9 @@ export function MultiTabAssistantChat({ showTabBar = true, renderHeader, renderO
1772
1787
  display: contentHidden || tabId !== activeThreadId ? "none" : "flex",
1773
1788
  }, children: [_jsx(RunStuckBanner, { threadId: tabId, enabled: tabId === activeThreadId, apiUrl: apiUrl, autoRetry: true, autoRetryOwnerId: browserTabId, hasInFlightWork: () => chatRefs.current.get(tabId)?.hasInFlightWork() ?? false, isAwaitingResponse: () => chatRefs.current.get(tabId)?.isRunning() ?? false, onRetry: () => {
1774
1789
  const handle = chatRefs.current.get(tabId);
1775
- handle?.sendRecoveryMessage("Continue from where you left off and finish my last request. Do not repeat completed work.", "continue");
1790
+ handle?.sendRecoveryMessage(
1791
+ // i18n-ignore -- stable hidden agent instruction.
1792
+ "Continue from where you left off and finish my last request. Do not repeat completed work.", "continue");
1776
1793
  } }), _jsx(AssistantChat, { ...props, dynamicSuggestions: tabDynamicSuggestions, ref: (handle) => {
1777
1794
  if (handle) {
1778
1795
  chatRefs.current.set(tabId, handle);
@@ -1788,7 +1805,7 @@ export function MultiTabAssistantChat({ showTabBar = true, renderHeader, renderO
1788
1805
  // the in-flight team chunk. Disable the composer and show a
1789
1806
  // hint so users know to send via the orchestrator chat instead.
1790
1807
  composerDisabled: Boolean(parentMap[tabId]), composerDisabledPlaceholder: parentMap[tabId]
1791
- ? "Send messages to the orchestrator chat — this sub-agent runs automatically"
1808
+ ? translate("agentChat.composer.subAgentReadOnly")
1792
1809
  : undefined })] }, tabId));
1793
1810
  })] })] }));
1794
1811
  }
@@ -1,3 +1,4 @@
1
+ export { MemoryRouter as AgentChatMemoryRouter } from "react-router";
1
2
  export { AgentAskPopover, type AgentAskPopoverProps, } from "../AgentAskPopover.js";
2
3
  export { addContextToAgentChat, appendAgentChatContextToMessage, clearAgentChatContext, formatAgentChatContextItemsForPrompt, insertAgentComposerReference, listAgentChatContext, normalizeAgentComposerReference, refreshAgentChatContext, removeAgentChatContextItem, requestAgentChatThreadOpen, requestAgentTaskOpen, sendToAgentChat, sendToAgentChatAndConfirm, reportAgentChatSubmitResult, AGENT_CHAT_SUBMIT_RESULT_EVENT, parseSubmitChatMessage, setAgentChatContextItem, setContextToAgentChat, generateTabId, type ParsedSubmitChat, type AgentChatOpenTaskRequest, type AgentChatOpenThreadRequest, type AgentChatContextItem, type AgentChatContextMessage, type AgentChatContextMutationOptions, type AgentChatContextRemoveOptions, type AgentChatContextSetOptions, type AgentChatContextState, type AgentChatMessage, type AgentChatSubmitResult, type SendToAgentChatAndConfirmResult, type AgentComposerReference, type AgentComposerReferenceInsertOptions, type AgentComposerReferenceInsertPayload, } from "../agent-chat.js";
3
4
  export { saveAgentEngineApiKey, saveAgentEngineProviderSettings, type AgentEngineProvider, type SaveAgentEngineApiKeyOptions, type SaveAgentEngineProviderSettingsOptions, } from "../agent-engine-key.js";
@@ -1,3 +1,4 @@
1
+ export { MemoryRouter as AgentChatMemoryRouter } from "react-router";
1
2
  export { AgentAskPopover, } from "../AgentAskPopover.js";
2
3
  export { addContextToAgentChat, appendAgentChatContextToMessage, clearAgentChatContext, formatAgentChatContextItemsForPrompt, insertAgentComposerReference, listAgentChatContext, normalizeAgentComposerReference, refreshAgentChatContext, removeAgentChatContextItem, requestAgentChatThreadOpen, requestAgentTaskOpen, sendToAgentChat, sendToAgentChatAndConfirm, reportAgentChatSubmitResult, AGENT_CHAT_SUBMIT_RESULT_EVENT, parseSubmitChatMessage, setAgentChatContextItem, setContextToAgentChat, generateTabId, } from "../agent-chat.js";
3
4
  export { saveAgentEngineApiKey, saveAgentEngineProviderSettings, } from "../agent-engine-key.js";
@@ -1,4 +1,4 @@
1
- import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  // Owns: lazy react-markdown/shiki loaders, SmoothMarkdownText, MarkdownText,
3
3
  // HighlightedCodeBlock wrapper, and the markdownComponents/markdownUrlTransform
4
4
  // used by every markdown render path in AssistantChat.
@@ -7,8 +7,9 @@ import { IconPlus, IconExternalLink } from "@tabler/icons-react";
7
7
  import React, { useState, useEffect, useCallback, useMemo, useRef, } from "react";
8
8
  import { splitMarkdownBlocks } from "../../shared/markdown-block-split.js";
9
9
  import { initialSmoothStreamingGraphemeCount, SMOOTH_STREAMING_COMMIT_INTERVAL_MS, smoothStreamingPunctuationDelayMs, smoothStreamingRevealCount, splitStreamingTextGraphemes, } from "../../shared/streaming-text-smoothing.js";
10
- import { NEW_CHAT_ACTION_HREF } from "../error-format.js";
10
+ import { localizeKnownChatErrorText, NEW_CHAT_ACTION_HREF, } from "../error-format.js";
11
11
  import { HighlightedCodeBlock as SharedHighlightedCodeBlock } from "../HighlightedCodeBlock.js";
12
+ import { useT } from "../i18n.js";
12
13
  import { IframeEmbed, parseEmbedBody } from "../IframeEmbed.js";
13
14
  import { cn } from "../utils.js";
14
15
  import { LEGACY_CHART_SHORTHAND_LANG, LegacyChartShorthandChart, LegacyChartShorthandFallback, parseLegacyChartShorthand, wrapLegacyChartShorthandLines, } from "./legacy-chart-shorthand.js";
@@ -475,21 +476,35 @@ export function SmoothMarkdownText({ text, streaming, resetKey, statusType = "co
475
476
  const visibleText = useSmoothStreamingText(text, shouldAnimate, resetKey);
476
477
  const ReactMarkdown = markdownModule?.default;
477
478
  const gfm = remarkGfmFn;
478
- const markdownBlocks = useMemo(() => (streaming ? splitMarkdownBlocks(visibleText) : null), [streaming, visibleText]);
479
+ // Split whether or not the turn is still streaming. Rendering the finished
480
+ // message as one whole-document ReactMarkdown instead swapped the element
481
+ // tree the instant `streaming` went false, so React unmounted every block and
482
+ // rebuilt it: code blocks re-highlighted, heights collapsed for a frame, and
483
+ // the scroll jumped — the "flash at the end" report. The split is faithful to
484
+ // a whole-document parse (see markdown-block-split.ts), so one tree serves
485
+ // both phases and nothing is rebuilt when streaming stops.
486
+ const markdownBlocks = useMemo(() => splitMarkdownBlocks(visibleText), [visibleText]);
487
+ // The tail renders through the same component as completed blocks, so when it
488
+ // is promoted to a completed block React matches the same type at the same
489
+ // key and keeps its DOM instead of remounting that paragraph.
490
+ const renderedBlocks = useMemo(() => markdownBlocks.tail
491
+ ? [...markdownBlocks.completedBlocks, markdownBlocks.tail]
492
+ : markdownBlocks.completedBlocks, [markdownBlocks]);
479
493
  useEffect(() => {
480
494
  if (!onRevealComplete || !shouldAnimate || visibleText !== text)
481
495
  return;
482
496
  onRevealComplete();
483
497
  }, [onRevealComplete, shouldAnimate, text, visibleText]);
484
- return (_jsx("div", { className: "agent-markdown break-words", "data-status": statusType, "data-streaming": streaming ? "true" : undefined, children: mdReady && ReactMarkdown && gfm ? (markdownBlocks ? (_jsxs(_Fragment, { children: [markdownBlocks.completedBlocks.map((blockText, index) => (_jsx(MemoizedMarkdownBlock, { blockText: blockText }, index))), markdownBlocks.tail ? (_jsx(ReactMarkdown, { remarkPlugins: [gfm], components: markdownComponents, urlTransform: markdownUrlTransform, children: wrapLegacyChartShorthandLines(markdownBlocks.tail) })) : null] })) : (_jsx(ReactMarkdown, { remarkPlugins: [gfm], components: markdownComponents, urlTransform: markdownUrlTransform, children: wrapLegacyChartShorthandLines(visibleText) }))) : (_jsx("span", { style: { whiteSpace: "pre-wrap" }, children: visibleText })) }));
498
+ return (_jsx("div", { className: "agent-markdown break-words", "data-status": statusType, "data-streaming": streaming ? "true" : undefined, children: mdReady && ReactMarkdown && gfm ? (renderedBlocks.map((blockText, index) => (_jsx(MemoizedMarkdownBlock, { blockText: blockText }, index)))) : (_jsx("span", { style: { whiteSpace: "pre-wrap" }, children: visibleText })) }));
485
499
  }
486
500
  // ─── MarkdownText ──────────────────────────────────────────────────────────────
487
501
  export function MarkdownText() {
502
+ const t = useT();
488
503
  const textPart = useMessagePartText();
489
504
  const messageRuntime = useMessageRuntime();
490
505
  const message = messageRuntime.getState();
491
506
  const textStreaming = React.useContext(TextStreamingContext);
492
507
  const isLastAssistantMessage = message.role === "assistant" && message.isLast;
493
508
  const statusType = textPart.status?.type ?? message.status?.type ?? "complete";
494
- return (_jsx(SmoothMarkdownText, { text: textPart.text, streaming: textStreaming && isLastAssistantMessage, resetKey: message.id, statusType: statusType }));
509
+ return (_jsx(SmoothMarkdownText, { text: localizeKnownChatErrorText(textPart.text, t), streaming: textStreaming && isLastAssistantMessage, resetKey: message.id, statusType: statusType }));
495
510
  }
@@ -9,7 +9,7 @@ interface FormattedMessageTimestamp {
9
9
  short: string;
10
10
  full: string;
11
11
  }
12
- export declare function formatMessageTimestamp(value: unknown): FormattedMessageTimestamp | null;
12
+ export declare function formatMessageTimestamp(value: unknown, locale?: string, yesterdayLabel?: string): FormattedMessageTimestamp | null;
13
13
  export declare function MessageTimestamp({ timestamp, className, }: {
14
14
  timestamp: FormattedMessageTimestamp;
15
15
  className?: string;
@@ -184,6 +184,6 @@ export declare function AssistantMessage(): React.JSX.Element | null;
184
184
  export declare function RunningActivityStatus({ label }: {
185
185
  label: string;
186
186
  }): React.JSX.Element;
187
- export declare function ThinkingIndicator({ label, }?: {
187
+ export declare function ThinkingIndicator({ label }?: {
188
188
  label?: string;
189
189
  }): React.JSX.Element;