@agent-native/core 0.7.19 → 0.7.21

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 (263) hide show
  1. package/README.md +1 -1
  2. package/dist/agent/engine/builder-engine.d.ts.map +1 -1
  3. package/dist/agent/engine/builder-engine.js +45 -2
  4. package/dist/agent/engine/builder-engine.js.map +1 -1
  5. package/dist/agent/loop-settings.d.ts +37 -0
  6. package/dist/agent/loop-settings.d.ts.map +1 -0
  7. package/dist/agent/loop-settings.js +127 -0
  8. package/dist/agent/loop-settings.js.map +1 -0
  9. package/dist/agent/production-agent.d.ts +8 -0
  10. package/dist/agent/production-agent.d.ts.map +1 -1
  11. package/dist/agent/production-agent.js +268 -29
  12. package/dist/agent/production-agent.js.map +1 -1
  13. package/dist/agent/run-manager.d.ts.map +1 -1
  14. package/dist/agent/run-manager.js +76 -3
  15. package/dist/agent/run-manager.js.map +1 -1
  16. package/dist/agent/run-store.d.ts +1 -1
  17. package/dist/agent/run-store.d.ts.map +1 -1
  18. package/dist/agent/run-store.js +65 -2
  19. package/dist/agent/run-store.js.map +1 -1
  20. package/dist/agent/thread-data-builder.d.ts +3 -0
  21. package/dist/agent/thread-data-builder.d.ts.map +1 -1
  22. package/dist/agent/thread-data-builder.js +52 -10
  23. package/dist/agent/thread-data-builder.js.map +1 -1
  24. package/dist/agent/tool-search.d.ts +37 -0
  25. package/dist/agent/tool-search.d.ts.map +1 -0
  26. package/dist/agent/tool-search.js +201 -0
  27. package/dist/agent/tool-search.js.map +1 -0
  28. package/dist/agent/types.d.ts +8 -1
  29. package/dist/agent/types.d.ts.map +1 -1
  30. package/dist/agent/types.js.map +1 -1
  31. package/dist/cli/create.d.ts.map +1 -1
  32. package/dist/cli/create.js +44 -9
  33. package/dist/cli/create.js.map +1 -1
  34. package/dist/cli/workspacify.d.ts +2 -0
  35. package/dist/cli/workspacify.d.ts.map +1 -1
  36. package/dist/cli/workspacify.js +34 -1
  37. package/dist/cli/workspacify.js.map +1 -1
  38. package/dist/client/AssistantChat.d.ts.map +1 -1
  39. package/dist/client/AssistantChat.js +277 -18
  40. package/dist/client/AssistantChat.js.map +1 -1
  41. package/dist/client/ConnectBuilderCard.d.ts.map +1 -1
  42. package/dist/client/ConnectBuilderCard.js +1 -1
  43. package/dist/client/ConnectBuilderCard.js.map +1 -1
  44. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  45. package/dist/client/MultiTabAssistantChat.js +14 -6
  46. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  47. package/dist/client/NewWorkspaceAppFlow.d.ts +14 -0
  48. package/dist/client/NewWorkspaceAppFlow.d.ts.map +1 -0
  49. package/dist/client/NewWorkspaceAppFlow.js +198 -0
  50. package/dist/client/NewWorkspaceAppFlow.js.map +1 -0
  51. package/dist/client/PoweredByBadge.d.ts +10 -1
  52. package/dist/client/PoweredByBadge.d.ts.map +1 -1
  53. package/dist/client/PoweredByBadge.js +120 -8
  54. package/dist/client/PoweredByBadge.js.map +1 -1
  55. package/dist/client/agent-chat-adapter.d.ts +3 -5
  56. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  57. package/dist/client/agent-chat-adapter.js +26 -19
  58. package/dist/client/agent-chat-adapter.js.map +1 -1
  59. package/dist/client/agent-chat.d.ts.map +1 -1
  60. package/dist/client/agent-chat.js +15 -3
  61. package/dist/client/agent-chat.js.map +1 -1
  62. package/dist/client/analytics.d.ts +1 -1
  63. package/dist/client/analytics.d.ts.map +1 -1
  64. package/dist/client/analytics.js +141 -1
  65. package/dist/client/analytics.js.map +1 -1
  66. package/dist/client/builder-frame.d.ts +10 -0
  67. package/dist/client/builder-frame.d.ts.map +1 -0
  68. package/dist/client/builder-frame.js +94 -0
  69. package/dist/client/builder-frame.js.map +1 -0
  70. package/dist/client/composer/MentionPopover.d.ts.map +1 -1
  71. package/dist/client/composer/MentionPopover.js +5 -1
  72. package/dist/client/composer/MentionPopover.js.map +1 -1
  73. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  74. package/dist/client/composer/TiptapComposer.js +11 -6
  75. package/dist/client/composer/TiptapComposer.js.map +1 -1
  76. package/dist/client/error-format.d.ts +20 -1
  77. package/dist/client/error-format.d.ts.map +1 -1
  78. package/dist/client/error-format.js +53 -5
  79. package/dist/client/error-format.js.map +1 -1
  80. package/dist/client/index.d.ts +3 -1
  81. package/dist/client/index.d.ts.map +1 -1
  82. package/dist/client/index.js +3 -1
  83. package/dist/client/index.js.map +1 -1
  84. package/dist/client/notifications/NotificationsBell.d.ts.map +1 -1
  85. package/dist/client/notifications/NotificationsBell.js +28 -1
  86. package/dist/client/notifications/NotificationsBell.js.map +1 -1
  87. package/dist/client/onboarding/OnboardingPanel.d.ts.map +1 -1
  88. package/dist/client/onboarding/OnboardingPanel.js +88 -6
  89. package/dist/client/onboarding/OnboardingPanel.js.map +1 -1
  90. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  91. package/dist/client/settings/SettingsPanel.js +145 -9
  92. package/dist/client/settings/SettingsPanel.js.map +1 -1
  93. package/dist/client/settings/useBuilderStatus.d.ts +13 -0
  94. package/dist/client/settings/useBuilderStatus.d.ts.map +1 -1
  95. package/dist/client/settings/useBuilderStatus.js +50 -9
  96. package/dist/client/settings/useBuilderStatus.js.map +1 -1
  97. package/dist/client/sse-event-processor.d.ts +3 -0
  98. package/dist/client/sse-event-processor.d.ts.map +1 -1
  99. package/dist/client/sse-event-processor.js +88 -7
  100. package/dist/client/sse-event-processor.js.map +1 -1
  101. package/dist/client/tools/ToolsListPage.d.ts.map +1 -1
  102. package/dist/client/tools/ToolsListPage.js +16 -1
  103. package/dist/client/tools/ToolsListPage.js.map +1 -1
  104. package/dist/client/tools/ToolsSidebarSection.d.ts.map +1 -1
  105. package/dist/client/tools/ToolsSidebarSection.js +63 -8
  106. package/dist/client/tools/ToolsSidebarSection.js.map +1 -1
  107. package/dist/client/tools/tool-order.d.ts +7 -0
  108. package/dist/client/tools/tool-order.d.ts.map +1 -0
  109. package/dist/client/tools/tool-order.js +47 -0
  110. package/dist/client/tools/tool-order.js.map +1 -0
  111. package/dist/client/transcription/BuilderTranscriptionCta.d.ts.map +1 -1
  112. package/dist/client/transcription/BuilderTranscriptionCta.js +71 -6
  113. package/dist/client/transcription/BuilderTranscriptionCta.js.map +1 -1
  114. package/dist/client/use-send-to-agent-chat.d.ts.map +1 -1
  115. package/dist/client/use-send-to-agent-chat.js +11 -3
  116. package/dist/client/use-send-to-agent-chat.js.map +1 -1
  117. package/dist/client/useProductionAgent.d.ts.map +1 -1
  118. package/dist/client/useProductionAgent.js +1 -1
  119. package/dist/client/useProductionAgent.js.map +1 -1
  120. package/dist/db/client.d.ts.map +1 -1
  121. package/dist/db/client.js +5 -1
  122. package/dist/db/client.js.map +1 -1
  123. package/dist/deploy/build.d.ts +1 -0
  124. package/dist/deploy/build.d.ts.map +1 -1
  125. package/dist/deploy/build.js +4 -1
  126. package/dist/deploy/build.js.map +1 -1
  127. package/dist/oauth-tokens/index.d.ts +1 -1
  128. package/dist/oauth-tokens/index.d.ts.map +1 -1
  129. package/dist/oauth-tokens/index.js +1 -1
  130. package/dist/oauth-tokens/index.js.map +1 -1
  131. package/dist/oauth-tokens/store.d.ts.map +1 -1
  132. package/dist/oauth-tokens/store.js +6 -0
  133. package/dist/oauth-tokens/store.js.map +1 -1
  134. package/dist/observability/store.d.ts.map +1 -1
  135. package/dist/observability/store.js +19 -19
  136. package/dist/observability/store.js.map +1 -1
  137. package/dist/onboarding/default-steps.d.ts.map +1 -1
  138. package/dist/onboarding/default-steps.js +95 -61
  139. package/dist/onboarding/default-steps.js.map +1 -1
  140. package/dist/onboarding/plugin.d.ts.map +1 -1
  141. package/dist/onboarding/plugin.js +17 -8
  142. package/dist/onboarding/plugin.js.map +1 -1
  143. package/dist/org/migrations.js +2 -2
  144. package/dist/org/migrations.js.map +1 -1
  145. package/dist/scripts/agent-engines/list-agent-engines.d.ts.map +1 -1
  146. package/dist/scripts/agent-engines/list-agent-engines.js +2 -3
  147. package/dist/scripts/agent-engines/list-agent-engines.js.map +1 -1
  148. package/dist/scripts/db/exec.d.ts +2 -1
  149. package/dist/scripts/db/exec.d.ts.map +1 -1
  150. package/dist/scripts/db/exec.js +264 -61
  151. package/dist/scripts/db/exec.js.map +1 -1
  152. package/dist/scripts/db/schema.d.ts.map +1 -1
  153. package/dist/scripts/db/schema.js +16 -4
  154. package/dist/scripts/db/schema.js.map +1 -1
  155. package/dist/scripts/dev/index.d.ts.map +1 -1
  156. package/dist/scripts/dev/index.js +36 -11
  157. package/dist/scripts/dev/index.js.map +1 -1
  158. package/dist/scripts/manage-agent-loop-settings.d.ts +7 -0
  159. package/dist/scripts/manage-agent-loop-settings.d.ts.map +1 -0
  160. package/dist/scripts/manage-agent-loop-settings.js +63 -0
  161. package/dist/scripts/manage-agent-loop-settings.js.map +1 -0
  162. package/dist/scripts/runner.d.ts.map +1 -1
  163. package/dist/scripts/runner.js +11 -0
  164. package/dist/scripts/runner.js.map +1 -1
  165. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  166. package/dist/server/agent-chat-plugin.js +60 -18
  167. package/dist/server/agent-chat-plugin.js.map +1 -1
  168. package/dist/server/app-url.d.ts +5 -4
  169. package/dist/server/app-url.d.ts.map +1 -1
  170. package/dist/server/app-url.js +8 -4
  171. package/dist/server/app-url.js.map +1 -1
  172. package/dist/server/auth.d.ts +8 -0
  173. package/dist/server/auth.d.ts.map +1 -1
  174. package/dist/server/auth.js +82 -29
  175. package/dist/server/auth.js.map +1 -1
  176. package/dist/server/better-auth-instance.d.ts.map +1 -1
  177. package/dist/server/better-auth-instance.js +16 -5
  178. package/dist/server/better-auth-instance.js.map +1 -1
  179. package/dist/server/builder-browser.d.ts +12 -0
  180. package/dist/server/builder-browser.d.ts.map +1 -1
  181. package/dist/server/builder-browser.js +36 -4
  182. package/dist/server/builder-browser.js.map +1 -1
  183. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  184. package/dist/server/core-routes-plugin.js +350 -53
  185. package/dist/server/core-routes-plugin.js.map +1 -1
  186. package/dist/server/credential-provider.d.ts +21 -3
  187. package/dist/server/credential-provider.d.ts.map +1 -1
  188. package/dist/server/credential-provider.js +51 -21
  189. package/dist/server/credential-provider.js.map +1 -1
  190. package/dist/server/google-oauth.d.ts +3 -0
  191. package/dist/server/google-oauth.d.ts.map +1 -1
  192. package/dist/server/google-oauth.js +27 -3
  193. package/dist/server/google-oauth.js.map +1 -1
  194. package/dist/server/index.d.ts +4 -3
  195. package/dist/server/index.d.ts.map +1 -1
  196. package/dist/server/index.js +4 -3
  197. package/dist/server/index.js.map +1 -1
  198. package/dist/server/onboarding-html.js +2 -2
  199. package/dist/server/onboarding-html.js.map +1 -1
  200. package/dist/server/schema-prompt.d.ts.map +1 -1
  201. package/dist/server/schema-prompt.js +2 -1
  202. package/dist/server/schema-prompt.js.map +1 -1
  203. package/dist/server/security-headers.d.ts +3 -0
  204. package/dist/server/security-headers.d.ts.map +1 -1
  205. package/dist/server/security-headers.js +7 -1
  206. package/dist/server/security-headers.js.map +1 -1
  207. package/dist/server/ssr-handler.d.ts.map +1 -1
  208. package/dist/server/ssr-handler.js +31 -6
  209. package/dist/server/ssr-handler.js.map +1 -1
  210. package/dist/templates/default/_gitignore +5 -1
  211. package/dist/templates/default/app/root.tsx +1 -0
  212. package/dist/templates/default/public/favicon.svg +3 -3
  213. package/dist/templates/default/public/icon-180.svg +3 -3
  214. package/dist/templates/default/public/icon-192.svg +3 -3
  215. package/dist/templates/default/public/icon-512.svg +3 -3
  216. package/dist/templates/workspace-core/AGENTS.md +23 -7
  217. package/dist/templates/workspace-core/package.json +2 -1
  218. package/dist/templates/workspace-core/src/credentials.ts +22 -11
  219. package/dist/templates/workspace-root/.env.example +7 -0
  220. package/dist/templates/workspace-root/README.md +6 -3
  221. package/dist/templates/workspace-root/_gitignore +3 -0
  222. package/dist/templates/workspace-root/package.json +3 -1
  223. package/dist/templates/workspace-root/scripts/workspace-dev.ts +375 -0
  224. package/dist/tools/actions.d.ts.map +1 -1
  225. package/dist/tools/actions.js +2 -0
  226. package/dist/tools/actions.js.map +1 -1
  227. package/dist/tools/html-shell.d.ts.map +1 -1
  228. package/dist/tools/html-shell.js +13 -1
  229. package/dist/tools/html-shell.js.map +1 -1
  230. package/dist/tools/store.d.ts.map +1 -1
  231. package/dist/tools/store.js +10 -10
  232. package/dist/tools/store.js.map +1 -1
  233. package/dist/tracking/providers.d.ts +1 -0
  234. package/dist/tracking/providers.d.ts.map +1 -1
  235. package/dist/tracking/providers.js +72 -0
  236. package/dist/tracking/providers.js.map +1 -1
  237. package/dist/vite/action-types-plugin.d.ts.map +1 -1
  238. package/dist/vite/action-types-plugin.js +106 -9
  239. package/dist/vite/action-types-plugin.js.map +1 -1
  240. package/dist/vite/client.d.ts.map +1 -1
  241. package/dist/vite/client.js +62 -1
  242. package/dist/vite/client.js.map +1 -1
  243. package/docs/content/authentication.md +17 -13
  244. package/docs/content/deployment.md +11 -11
  245. package/docs/content/mcp-clients.md +2 -2
  246. package/docs/content/onboarding.md +32 -30
  247. package/docs/content/security.md +1 -1
  248. package/docs/content/tools.md +4 -0
  249. package/package.json +2 -2
  250. package/src/templates/default/_gitignore +5 -1
  251. package/src/templates/default/app/root.tsx +1 -0
  252. package/src/templates/default/public/favicon.svg +3 -3
  253. package/src/templates/default/public/icon-180.svg +3 -3
  254. package/src/templates/default/public/icon-192.svg +3 -3
  255. package/src/templates/default/public/icon-512.svg +3 -3
  256. package/src/templates/workspace-core/AGENTS.md +23 -7
  257. package/src/templates/workspace-core/package.json +2 -1
  258. package/src/templates/workspace-core/src/credentials.ts +22 -11
  259. package/src/templates/workspace-root/.env.example +7 -0
  260. package/src/templates/workspace-root/README.md +6 -3
  261. package/src/templates/workspace-root/_gitignore +3 -0
  262. package/src/templates/workspace-root/package.json +3 -1
  263. package/src/templates/workspace-root/scripts/workspace-dev.ts +375 -0
@@ -16,8 +16,9 @@ import { useBuilderConnectFlow } from "./settings/useBuilderStatus.js";
16
16
  import { IframeEmbed, parseEmbedBody } from "./IframeEmbed.js";
17
17
  import { useDevMode } from "./use-dev-mode.js";
18
18
  import { agentNativePath } from "./api-path.js";
19
+ import { BUILDER_SPACE_SETTINGS_URL } from "./error-format.js";
19
20
  import { TiptapComposer, } from "./composer/TiptapComposer.js";
20
- import { IconMessage, IconX, IconPlayerStop, IconCheck, IconChevronDown, IconCopy, IconTerminal, IconLoader2, IconCircleX, IconSquareFilled, IconClock, IconFile, IconFolder, IconFileText, IconCheckbox, IconMail, IconUser, IconPresentation, IconStack2, IconMessageChatbot, IconLock, IconArrowBackUp, IconExternalLink, IconDots, IconGitFork, IconId, IconQuote, } from "@tabler/icons-react";
21
+ import { IconMessage, IconX, IconPlayerStop, IconCheck, IconChevronDown, IconCopy, IconTerminal, IconLoader2, IconCircleX, IconSquareFilled, IconClock, IconFile, IconFolder, IconFileText, IconCheckbox, IconMail, IconUser, IconPresentation, IconStack2, IconMessageChatbot, IconLock, IconArrowBackUp, IconExternalLink, IconDots, IconGitFork, IconId, IconQuote, IconGauge, IconArrowRight, IconSettings, IconAlertTriangle, IconRefresh, IconPlayerPlay, } from "@tabler/icons-react";
21
22
  const ThumbsFeedbackLazy = React.lazy(() => import("./observability/ThumbsFeedback.js").then((m) => ({
22
23
  default: m.ThumbsFeedback,
23
24
  })));
@@ -46,6 +47,7 @@ const markdownStyles = `
46
47
  @media (prefers-color-scheme: dark) { :root:not(.light) .agent-markdown-shiki pre { background: var(--shiki-dark-bg); color: var(--shiki-dark); } :root:not(.light) .agent-markdown-shiki pre span { color: var(--shiki-dark); background: var(--shiki-dark-bg); } }
47
48
  .agent-markdown hr { border: none; border-top: 1px solid hsl(var(--border, 0 0% 20%)); margin: 0.75em 0; }
48
49
  .agent-markdown a { text-decoration: underline; text-underline-offset: 2px; }
50
+ .agent-markdown a.agent-markdown-cta { text-decoration: none; }
49
51
  .agent-markdown blockquote { border-left: 2px solid hsl(var(--border, 0 0% 20%)); padding-left: 0.75em; margin: 0.5em 0; opacity: 0.8; }
50
52
  .agent-markdown table { border-collapse: collapse; margin: 0.5em 0; font-size: 0.875em; }
51
53
  .agent-markdown th, .agent-markdown td { border: 1px solid hsl(var(--border, 0 0% 20%)); padding: 0.35em 0.65em; text-align: left; }
@@ -219,6 +221,14 @@ function HighlightedCodeBlock({ code, lang }) {
219
221
  return (_jsx("pre", { children: _jsx("code", { className: lang ? `language-${lang}` : undefined, children: code }) }));
220
222
  }
221
223
  const markdownComponents = {
224
+ a(props) {
225
+ const { href, children, className, rel: _rel, target: _target, ...rest } = props;
226
+ const isBuilderCta = isBuilderErrorCtaHref(href);
227
+ if (!isBuilderCta) {
228
+ return (_jsx("a", { href: href, className: className, ...rest, children: children }));
229
+ }
230
+ return (_jsxs("a", { href: href, target: "_blank", rel: "noreferrer", className: cn("agent-markdown-cta mt-1 inline-flex items-center gap-1.5 rounded-md bg-foreground px-3 py-1.5 text-xs font-medium text-background no-underline shadow-sm transition-colors hover:bg-foreground/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background", className), ...rest, children: [_jsx("span", { children: children }), _jsx(IconExternalLink, { size: 13, strokeWidth: 2, "aria-hidden": "true" })] }));
231
+ },
222
232
  pre(props) {
223
233
  const { children, ...rest } = props;
224
234
  if (React.isValidElement(children)) {
@@ -238,6 +248,22 @@ const markdownComponents = {
238
248
  return _jsx("pre", { ...rest, children: children });
239
249
  },
240
250
  };
251
+ function isBuilderErrorCtaHref(href) {
252
+ if (!href)
253
+ return false;
254
+ try {
255
+ const url = new URL(href);
256
+ if (url.protocol !== "https:" || url.hostname !== "builder.io") {
257
+ return false;
258
+ }
259
+ return (url.href === BUILDER_SPACE_SETTINGS_URL ||
260
+ url.pathname === "/account/billing" ||
261
+ /^\/app\/organizations\/[^/]+\/billing$/.test(url.pathname));
262
+ }
263
+ catch {
264
+ return false;
265
+ }
266
+ }
241
267
  function MarkdownText() {
242
268
  useEffect(() => {
243
269
  injectMarkdownStyles();
@@ -585,10 +611,11 @@ function AssistantMessage() {
585
611
  const [restoreState, setRestoreState] = useState("idle");
586
612
  const messageRuntime = useMessageRuntime();
587
613
  const thread = useThread();
614
+ const chatRunning = React.useContext(ChatRunningContext);
588
615
  const msg = messageRuntime.getState();
589
616
  const isLast = thread.messages.length > 0 &&
590
617
  thread.messages[thread.messages.length - 1].id === msg.id;
591
- const isComplete = !isLast || !thread.isRunning;
618
+ const isComplete = !isLast || !chatRunning;
592
619
  const cpCtx = React.useContext(CheckpointContext);
593
620
  const handleRestore = useCallback(async () => {
594
621
  if (restoreState === "idle") {
@@ -641,14 +668,13 @@ function AssistantMessage() {
641
668
  tools: {
642
669
  Fallback: ToolCallFallback,
643
670
  },
644
- } }) }), _jsxs("div", { className: "mt-1 flex items-center justify-between", children: [_jsx(MessageActionsMenu, { showRevert: showRestore && restoreState === "idle", onRevert: handleRestore }), isComplete &&
645
- (showRestore && restoreState === "confirming" ? (_jsxs("div", { className: "flex items-center gap-1 text-xs", children: [_jsx("button", { onClick: handleRestore, className: "rounded-md bg-destructive px-1.5 py-0.5 text-destructive-foreground hover:bg-destructive/90", children: "Restore to here?" }), _jsx("button", { onClick: cancelRestore, className: "rounded-md px-1.5 py-0.5 text-muted-foreground hover:bg-accent", children: "Cancel" })] })) : showRestore && restoreState === "restoring" ? (_jsxs("span", { className: "flex items-center gap-1 text-xs text-muted-foreground", children: [_jsx(IconLoader2, { className: "h-3 w-3 animate-spin" }), "Restoring..."] })) : (_jsx(React.Suspense, { fallback: null, children: _jsx(ThumbsFeedbackLazy, { threadId: cpCtx?.threadId ?? "", runId: (() => {
646
- const meta = messageRuntime.getState().metadata;
647
- return ((typeof meta?.custom?.runId === "string" &&
648
- meta.custom.runId) ||
649
- (typeof meta?.runId === "string" && meta.runId) ||
650
- "");
651
- })(), messageSeq: thread.messages.findIndex((m) => m.id === msg.id) }) })))] })] }));
671
+ } }) }), isComplete && (_jsxs("div", { className: "mt-1 flex items-center justify-between", children: [_jsx(MessageActionsMenu, { showRevert: showRestore && restoreState === "idle", onRevert: handleRestore }), showRestore && restoreState === "confirming" ? (_jsxs("div", { className: "flex items-center gap-1 text-xs", children: [_jsx("button", { onClick: handleRestore, className: "rounded-md bg-destructive px-1.5 py-0.5 text-destructive-foreground hover:bg-destructive/90", children: "Restore to here?" }), _jsx("button", { onClick: cancelRestore, className: "rounded-md px-1.5 py-0.5 text-muted-foreground hover:bg-accent", children: "Cancel" })] })) : showRestore && restoreState === "restoring" ? (_jsxs("span", { className: "flex items-center gap-1 text-xs text-muted-foreground", children: [_jsx(IconLoader2, { className: "h-3 w-3 animate-spin" }), "Restoring..."] })) : (_jsx(React.Suspense, { fallback: null, children: _jsx(ThumbsFeedbackLazy, { threadId: cpCtx?.threadId ?? "", runId: (() => {
672
+ const meta = messageRuntime.getState().metadata;
673
+ return ((typeof meta?.custom?.runId === "string" &&
674
+ meta.custom.runId) ||
675
+ (typeof meta?.runId === "string" && meta.runId) ||
676
+ "");
677
+ })(), messageSeq: thread.messages.findIndex((m) => m.id === msg.id) }) }))] }))] }));
652
678
  }
653
679
  // ─── Thinking Indicator ─────────────────────────────────────────────────────
654
680
  function ThinkingIndicator({ label = "Thinking" } = {}) {
@@ -730,6 +756,163 @@ function ApiKeySetupCard({ apiUrl }) {
730
756
  handleSave();
731
757
  }, placeholder: "sk-ant-...", className: "w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground/50 outline-none focus:ring-1 focus:ring-ring", autoComplete: "off" }), error && _jsx("p", { className: "text-xs text-destructive", children: error }), apiKey.trim() && (_jsx("button", { onClick: handleSave, disabled: saving, className: "w-full rounded-md bg-primary px-3 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 disabled:opacity-40 disabled:cursor-not-allowed", children: saving ? "Saving..." : "Save API key" })), _jsx("p", { className: "text-[10px] text-muted-foreground/60 text-center", children: _jsx("a", { href: "https://console.anthropic.com/settings/keys", target: "_blank", rel: "noopener noreferrer", className: "underline hover:text-foreground/80", children: "Get an Anthropic key" }) })] })] }));
732
758
  }
759
+ function getLoopLimitMetadata(message) {
760
+ const meta = message?.metadata;
761
+ const loopLimit = meta?.custom?.loopLimit ?? meta?.loopLimit;
762
+ if (!loopLimit || typeof loopLimit !== "object")
763
+ return null;
764
+ return {
765
+ ...(typeof loopLimit.maxIterations === "number"
766
+ ? { maxIterations: loopLimit.maxIterations }
767
+ : {}),
768
+ };
769
+ }
770
+ function getRunErrorMetadata(message) {
771
+ const meta = message?.metadata;
772
+ const runError = meta?.custom?.runError ?? meta?.runError;
773
+ if (!runError || typeof runError !== "object")
774
+ return null;
775
+ const messageText = typeof runError.message === "string" ? runError.message : "";
776
+ if (!messageText)
777
+ return null;
778
+ const runId = typeof runError.runId === "string"
779
+ ? runError.runId
780
+ : typeof meta?.custom?.runId === "string"
781
+ ? meta.custom.runId
782
+ : typeof meta?.runId === "string"
783
+ ? meta.runId
784
+ : undefined;
785
+ return {
786
+ message: messageText,
787
+ ...(typeof runError.details === "string"
788
+ ? { details: runError.details }
789
+ : {}),
790
+ ...(typeof runError.errorCode === "string"
791
+ ? { errorCode: runError.errorCode }
792
+ : {}),
793
+ ...(runId ? { runId } : {}),
794
+ ...(runError.recoverable ? { recoverable: true } : {}),
795
+ };
796
+ }
797
+ function getMessageText(message) {
798
+ const msg = message?.message ?? message;
799
+ const content = msg?.content;
800
+ if (Array.isArray(content)) {
801
+ return content
802
+ .filter((p) => p?.type === "text" && typeof p.text === "string")
803
+ .map((p) => p.text)
804
+ .join("\n")
805
+ .trim();
806
+ }
807
+ return typeof content === "string" ? content.trim() : "";
808
+ }
809
+ function RunErrorRecoveryCard({ info, onContinue, onRetry, onFork, onDismiss, }) {
810
+ const [detailsOpen, setDetailsOpen] = useState(false);
811
+ const [copied, setCopied] = useState(false);
812
+ const copyDetails = useCallback(() => {
813
+ const text = [
814
+ info.message,
815
+ info.errorCode ? `Code: ${info.errorCode}` : "",
816
+ info.runId ? `Run: ${info.runId}` : "",
817
+ info.details ? `Details:\n${info.details}` : "",
818
+ ]
819
+ .filter(Boolean)
820
+ .join("\n\n");
821
+ navigator.clipboard.writeText(text);
822
+ setCopied(true);
823
+ setTimeout(() => setCopied(false), 1200);
824
+ }, [info]);
825
+ return (_jsxs("div", { className: "rounded-lg border border-amber-500/25 bg-amber-500/[0.06] p-3 text-sm", children: [_jsxs("div", { className: "flex items-start gap-2", children: [_jsx("span", { className: "mt-0.5 flex h-6 w-6 shrink-0 items-center justify-center rounded-md bg-amber-500/10 text-amber-700 dark:text-amber-300", children: _jsx(IconAlertTriangle, { size: 14 }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "font-medium text-foreground", children: "The agent stopped before finishing" }), _jsx("p", { className: "mt-1 text-xs leading-relaxed text-muted-foreground", children: info.message }), (info.runId || info.errorCode || info.details) && (_jsxs("button", { type: "button", onClick: () => setDetailsOpen((v) => !v), className: "mt-2 inline-flex items-center gap-1 text-[11px] font-medium text-muted-foreground hover:text-foreground", children: [_jsx(IconChevronDown, { size: 12, className: cn("transition-transform", detailsOpen && "rotate-180") }), "Details"] })), detailsOpen && (_jsxs("div", { className: "mt-2 rounded-md border border-border/60 bg-background/70 p-2 font-mono text-[11px] leading-relaxed text-muted-foreground", children: [info.runId && _jsxs("div", { children: ["run: ", info.runId] }), info.errorCode && _jsxs("div", { children: ["code: ", info.errorCode] }), info.details && (_jsx("pre", { className: "mt-2 max-h-28 overflow-auto whitespace-pre-wrap break-words font-mono", children: info.details }))] }))] }), _jsx("button", { type: "button", onClick: onDismiss, "aria-label": "Dismiss", className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-md text-muted-foreground hover:bg-background/80 hover:text-foreground", children: _jsx(IconX, { size: 14 }) })] }), _jsxs("div", { className: "mt-3 flex flex-wrap items-center gap-2", children: [_jsxs("button", { type: "button", onClick: onContinue, className: "inline-flex h-8 items-center gap-1.5 rounded-md bg-foreground px-3 text-xs font-medium text-background hover:opacity-90", children: [_jsx(IconPlayerPlay, { size: 13 }), "Continue"] }), _jsxs("button", { type: "button", onClick: onRetry, className: "inline-flex h-8 items-center gap-1.5 rounded-md border border-border bg-background px-3 text-xs font-medium text-foreground hover:bg-accent", children: [_jsx(IconRefresh, { size: 13 }), "Retry"] }), onFork && (_jsxs("button", { type: "button", onClick: onFork, className: "inline-flex h-8 items-center gap-1.5 rounded-md border border-border bg-background px-3 text-xs font-medium text-foreground hover:bg-accent", children: [_jsx(IconGitFork, { size: 13 }), "Fork"] })), _jsxs("button", { type: "button", onClick: copyDetails, className: "ml-auto inline-flex h-8 items-center gap-1.5 rounded-md px-2.5 text-xs font-medium text-muted-foreground hover:bg-background/80 hover:text-foreground", children: [copied ? _jsx(IconCheck, { size: 13 }) : _jsx(IconCopy, { size: 13 }), copied ? "Copied" : "Copy"] })] })] }));
826
+ }
827
+ function LoopLimitContinueCard({ info, onContinue, }) {
828
+ const [settings, setSettings] = useState(null);
829
+ const [value, setValue] = useState("");
830
+ const [saving, setSaving] = useState(false);
831
+ const [saved, setSaved] = useState(false);
832
+ const [error, setError] = useState(null);
833
+ const load = useCallback(() => {
834
+ let cancelled = false;
835
+ fetch(agentNativePath("/_agent-native/agent-loop-settings"))
836
+ .then((r) => (r.ok ? r.json() : null))
837
+ .then((data) => {
838
+ if (cancelled || !data)
839
+ return;
840
+ setSettings(data);
841
+ setValue(String(data.maxIterations));
842
+ })
843
+ .catch(() => {
844
+ if (!cancelled)
845
+ setValue(String(info.maxIterations ?? ""));
846
+ });
847
+ return () => {
848
+ cancelled = true;
849
+ };
850
+ }, [info.maxIterations]);
851
+ useEffect(() => load(), [load]);
852
+ const currentLimit = settings?.maxIterations ?? info.maxIterations;
853
+ const numericValue = Number(value);
854
+ const hasPendingChange = !!settings &&
855
+ settings.canUpdate &&
856
+ Number.isInteger(numericValue) &&
857
+ numericValue !== settings.maxIterations;
858
+ const scopeLabel = settings?.scope === "org"
859
+ ? settings.orgName
860
+ ? `${settings.orgName} org`
861
+ : "org"
862
+ : "your account";
863
+ const saveLimit = useCallback(async () => {
864
+ if (!settings?.canUpdate)
865
+ return false;
866
+ setSaving(true);
867
+ setSaved(false);
868
+ setError(null);
869
+ try {
870
+ const res = await fetch(agentNativePath("/_agent-native/agent-loop-settings"), {
871
+ method: "PUT",
872
+ headers: { "Content-Type": "application/json" },
873
+ body: JSON.stringify({ maxIterations: numericValue }),
874
+ });
875
+ const body = await res.json().catch(() => ({}));
876
+ if (!res.ok) {
877
+ throw new Error(body?.error ?? `Save failed (${res.status})`);
878
+ }
879
+ setSettings(body);
880
+ setValue(String(body.maxIterations));
881
+ setSaved(true);
882
+ window.dispatchEvent(new CustomEvent("agent-loop-settings:changed", { detail: body }));
883
+ setTimeout(() => setSaved(false), 2000);
884
+ return true;
885
+ }
886
+ catch (err) {
887
+ setError(err instanceof Error ? err.message : "Save failed");
888
+ return false;
889
+ }
890
+ finally {
891
+ setSaving(false);
892
+ }
893
+ }, [numericValue, settings?.canUpdate]);
894
+ const handleContinue = useCallback(async () => {
895
+ if (hasPendingChange) {
896
+ const ok = await saveLimit();
897
+ if (!ok)
898
+ return;
899
+ }
900
+ onContinue();
901
+ }, [hasPendingChange, onContinue, saveLimit]);
902
+ const openSettings = useCallback(() => {
903
+ try {
904
+ window.location.hash = "agent-limits";
905
+ }
906
+ catch { }
907
+ window.dispatchEvent(new CustomEvent("agent-panel:open-settings"));
908
+ }, []);
909
+ return (_jsxs("div", { className: "rounded-lg border border-amber-500/25 bg-amber-500/[0.06] px-3 py-3 shadow-sm", children: [_jsxs("div", { className: "flex items-start gap-2.5", children: [_jsx("span", { className: "mt-0.5 flex h-6 w-6 shrink-0 items-center justify-center rounded-md bg-amber-500/10 text-amber-600 dark:text-amber-400", children: _jsx(IconGauge, { size: 14 }) }), _jsxs("div", { className: "min-w-0", children: [_jsx("p", { className: "text-sm font-medium text-foreground", children: "Step limit reached" }), _jsxs("p", { className: "mt-0.5 text-xs leading-relaxed text-muted-foreground", children: ["The agent used", " ", currentLimit
910
+ ? `${currentLimit.toLocaleString()} steps`
911
+ : "all available steps", ". Keep going in a fresh turn, or raise the ", scopeLabel, " limit first."] })] })] }), _jsxs("div", { className: "mt-3 flex flex-wrap items-end gap-2", children: [_jsxs("label", { className: "min-w-[116px] flex-1 space-y-1", children: [_jsx("span", { className: "text-[10px] font-medium uppercase tracking-wide text-muted-foreground", children: "Max steps" }), _jsx("input", { type: "number", min: settings?.minMaxIterations ?? 1, max: settings?.maxMaxIterations ?? 1000, value: value, disabled: !settings?.canUpdate || saving, onChange: (e) => {
912
+ setValue(e.target.value);
913
+ setError(null);
914
+ }, className: "h-8 w-full rounded-md border border-border bg-background px-2 text-xs text-foreground outline-none focus:ring-1 focus:ring-ring disabled:opacity-60" })] }), _jsx("button", { type: "button", onClick: saveLimit, disabled: !hasPendingChange || saving, className: "inline-flex h-8 items-center gap-1 rounded-md border border-border px-2.5 text-xs font-medium text-foreground hover:bg-accent disabled:opacity-50", children: saving ? (_jsx(IconLoader2, { size: 12, className: "animate-spin" })) : saved ? (_jsx(IconCheck, { size: 12 })) : ("Save") }), _jsxs("button", { type: "button", onClick: openSettings, className: "inline-flex h-8 items-center gap-1 rounded-md border border-border px-2.5 text-xs font-medium text-muted-foreground hover:bg-accent hover:text-foreground", children: [_jsx(IconSettings, { size: 12 }), "Settings"] }), _jsxs("button", { type: "button", onClick: handleContinue, disabled: saving, className: "ml-auto inline-flex h-8 items-center gap-1 rounded-md bg-foreground px-3 text-xs font-medium text-background hover:opacity-90 disabled:opacity-60", children: [hasPendingChange ? "Save and keep going" : "Keep going", _jsx(IconArrowRight, { size: 12 })] })] }), settings && !settings.canUpdate && (_jsx("p", { className: "mt-2 text-[11px] text-muted-foreground", children: "Only organization owners and admins can change this limit." })), error && _jsx("p", { className: "mt-2 text-[11px] text-destructive", children: error })] }));
915
+ }
733
916
  export const CHAT_STORAGE_PREFIX = "agent-chat:";
734
917
  /** Remove persisted chat for a given tabId (or "default"). */
735
918
  export function clearChatStorage(tabId) {
@@ -778,6 +961,9 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
778
961
  // on mount, or queue state that hasn't actually changed).
779
962
  const lastPersistedQueueRef = useRef("[]");
780
963
  const [showContinue, setShowContinue] = useState(false);
964
+ const [loopLimitInfo, setLoopLimitInfo] = useState(null);
965
+ const [runErrorInfo, setRunErrorInfo] = useState(null);
966
+ const [dismissedRunErrorKey, setDismissedRunErrorKey] = useState(null);
781
967
  const [isReconnecting, setIsReconnecting] = useState(false);
782
968
  const [reconnectContent, setReconnectContent] = useState([]);
783
969
  // When stop is clicked during reconnect, keep content visible (don't wipe it)
@@ -1212,12 +1398,36 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
1212
1398
  const handler = (e) => {
1213
1399
  const detail = e.detail;
1214
1400
  if (!tabId || detail?.tabId === tabId) {
1401
+ setLoopLimitInfo({
1402
+ ...(typeof detail?.maxIterations === "number"
1403
+ ? { maxIterations: detail.maxIterations }
1404
+ : {}),
1405
+ });
1215
1406
  setShowContinue(true);
1216
1407
  }
1217
1408
  };
1218
1409
  window.addEventListener("agent-chat:loop-limit", handler);
1219
1410
  return () => window.removeEventListener("agent-chat:loop-limit", handler);
1220
1411
  }, [tabId]);
1412
+ useEffect(() => {
1413
+ const handler = (e) => {
1414
+ const detail = e.detail;
1415
+ if (tabId && detail?.tabId && detail.tabId !== tabId)
1416
+ return;
1417
+ if (!detail?.message)
1418
+ return;
1419
+ setRunErrorInfo({
1420
+ message: detail.message,
1421
+ ...(detail.details ? { details: detail.details } : {}),
1422
+ ...(detail.errorCode ? { errorCode: detail.errorCode } : {}),
1423
+ ...(detail.runId ? { runId: detail.runId } : {}),
1424
+ ...(detail.recoverable ? { recoverable: detail.recoverable } : {}),
1425
+ });
1426
+ setDismissedRunErrorKey(null);
1427
+ };
1428
+ window.addEventListener("agent-chat:run-error", handler);
1429
+ return () => window.removeEventListener("agent-chat:run-error", handler);
1430
+ }, [tabId]);
1221
1431
  // Auto-dequeue: when agent finishes running, send the next queued message
1222
1432
  useEffect(() => {
1223
1433
  if (wasRunningRef.current && !isRunning && queuedMessages.length > 0) {
@@ -1273,6 +1483,9 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
1273
1483
  }, [isReconnecting, forceStopped]);
1274
1484
  const addToQueue = useCallback((text, images, references) => {
1275
1485
  setShowContinue(false);
1486
+ setLoopLimitInfo(null);
1487
+ setRunErrorInfo(null);
1488
+ setDismissedRunErrorKey(null);
1276
1489
  // Selection context attached via Cmd+I is one-shot — clear it as soon
1277
1490
  // as the user actually sends a message so it can't be re-used.
1278
1491
  clearPendingSelection();
@@ -1374,6 +1587,35 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
1374
1587
  const { isDevMode: cpDevMode } = useDevMode(apiUrl);
1375
1588
  const checkpointCtx = useMemo(() => ({ apiUrl, devMode: cpDevMode, threadId }), [apiUrl, cpDevMode, threadId]);
1376
1589
  const messageActionsCtx = useMemo(() => ({ onForkChat }), [onForkChat]);
1590
+ const lastMessageLoopLimit = useMemo(() => {
1591
+ const last = messages[messages.length - 1];
1592
+ if (!last || last.role !== "assistant")
1593
+ return null;
1594
+ return getLoopLimitMetadata(last);
1595
+ }, [messages]);
1596
+ const lastMessageRunError = useMemo(() => {
1597
+ const last = messages[messages.length - 1];
1598
+ if (!last || last.role !== "assistant")
1599
+ return null;
1600
+ return getRunErrorMetadata(last);
1601
+ }, [messages]);
1602
+ const lastUserText = useMemo(() => {
1603
+ for (let i = messages.length - 1; i >= 0; i--) {
1604
+ if (messages[i]?.role === "user")
1605
+ return getMessageText(messages[i]);
1606
+ }
1607
+ return "";
1608
+ }, [messages]);
1609
+ const visibleLoopLimit = showContinue
1610
+ ? (loopLimitInfo ?? lastMessageLoopLimit ?? {})
1611
+ : lastMessageLoopLimit;
1612
+ const visibleRunError = runErrorInfo ?? lastMessageRunError;
1613
+ const visibleRunErrorKey = visibleRunError
1614
+ ? `${visibleRunError.runId ?? ""}:${visibleRunError.errorCode ?? ""}:${visibleRunError.message}`
1615
+ : null;
1616
+ const shouldShowRunError = !!visibleRunError &&
1617
+ !showRunningInUI &&
1618
+ visibleRunErrorKey !== dismissedRunErrorKey;
1377
1619
  return (_jsx(CheckpointContext.Provider, { value: checkpointCtx, children: _jsx(MessageActionsContext.Provider, { value: messageActionsCtx, children: _jsx(ChatRunningContext.Provider, { value: isRunning, children: _jsxs("div", { className: cn("flex flex-1 flex-col h-full min-h-0 text-foreground", className), children: [showHeader && (_jsxs("div", { className: "flex h-11 shrink-0 items-center justify-between border-b border-border px-4", children: [_jsx("span", { className: "text-[13px] font-medium text-muted-foreground", children: "Agent" }), _jsx("div", { className: "flex items-center gap-1", children: onSwitchToCli && (_jsxs("button", { onClick: onSwitchToCli, className: "flex items-center gap-1 text-[12px] text-muted-foreground hover:text-foreground px-2 py-1 rounded-md hover:bg-accent", title: "Switch to CLI", children: [_jsx(IconTerminal, { className: "h-3.5 w-3.5" }), "CLI"] })) })] })), _jsx("div", { ref: scrollRef, className: "flex-1 overflow-y-auto overflow-x-hidden min-h-0", children: authError ? (_jsxs("div", { className: "flex flex-col items-center justify-center h-full px-4 gap-3", children: [_jsx("div", { className: "flex h-10 w-10 items-center justify-center rounded-full bg-destructive/10", children: _jsx(IconLock, { className: "h-5 w-5 text-destructive" }) }), _jsxs("div", { className: "text-center max-w-[280px]", children: [_jsx("p", { className: "text-sm font-medium text-foreground mb-1", children: authError.sessionExpired
1378
1620
  ? "Session expired"
1379
1621
  : "Authentication required" }), _jsx("p", { className: "text-xs text-muted-foreground leading-relaxed", children: authError.sessionExpired ? ("Your session may have expired. Log out and log back in to reconnect.") : (_jsxs(_Fragment, { children: ["You need to log in to use the agent. If you're running locally, add", " ", _jsx("code", { className: "bg-muted px-1 py-0.5 rounded text-[10px]", children: "AUTH_MODE=local" }), " ", "to your", " ", _jsx("code", { className: "bg-muted px-1 py-0.5 rounded text-[10px]", children: ".env" }), " ", "file and restart the dev server."] })) })] }), _jsxs("div", { className: "flex gap-2", children: [authError.sessionExpired && (_jsx("button", { onClick: async () => {
@@ -1395,16 +1637,31 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
1395
1637
  }, className: "w-full rounded-lg border border-border px-3 py-2 text-left text-[13px] text-muted-foreground hover:bg-accent hover:text-foreground", children: suggestion }, suggestion))) }))] })) : (_jsxs("div", { className: "agent-thread-content flex flex-col gap-4 px-4 py-4", children: [_jsx(ThreadPrimitive.Messages, { components: {
1396
1638
  UserMessage,
1397
1639
  AssistantMessage,
1398
- } }), showContinue && !showRunningInUI && (_jsx("div", { className: "flex justify-center py-2", children: _jsx("button", { type: "button", onClick: () => {
1399
- setShowContinue(false);
1400
- addToQueue("Continue from where you left off.");
1401
- }, className: "rounded-lg border border-border bg-background px-4 py-2 text-sm font-medium text-foreground hover:bg-accent", children: "Continue" }) })), (isReconnecting || reconnectFrozen) &&
1640
+ } }), visibleLoopLimit && !showRunningInUI && (_jsx(LoopLimitContinueCard, { info: visibleLoopLimit, onContinue: () => {
1641
+ setShowContinue(false);
1642
+ setLoopLimitInfo(null);
1643
+ addToQueue("Continue from where you left off.");
1644
+ } })), shouldShowRunError && visibleRunError && (_jsx(RunErrorRecoveryCard, { info: visibleRunError, onContinue: () => {
1645
+ setRunErrorInfo(null);
1646
+ addToQueue("Continue from where you stopped. Use the partial work above, verify what succeeded, and finish the original request. Prefer dedicated app actions over raw database edits when they exist.");
1647
+ }, onRetry: () => {
1648
+ setRunErrorInfo(null);
1649
+ addToQueue(lastUserText
1650
+ ? `Retry the previous request from a clean approach. Original request:\n\n${lastUserText}`
1651
+ : "Retry the previous request from a clean approach.");
1652
+ }, onFork: onForkChat, onDismiss: () => {
1653
+ if (visibleRunErrorKey) {
1654
+ setDismissedRunErrorKey(visibleRunErrorKey);
1655
+ }
1656
+ setRunErrorInfo(null);
1657
+ } })), (isReconnecting || reconnectFrozen) &&
1402
1658
  reconnectContent.length > 0 && (_jsx(ReconnectStreamMessage, { content: reconnectContent })), showRunningInUI && (_jsx(ThinkingIndicator, { label: isReconnecting ? "Reconnecting" : "Thinking" })), queuedMessages.map((msg) => {
1403
1659
  const displayText = msg.text
1404
1660
  .replace(/<context>[\s\S]*?<\/context>\n?/g, "")
1405
1661
  .trim();
1406
1662
  return (_jsx("div", { className: "flex justify-end group", children: _jsxs("div", { className: "relative max-w-[85%] rounded-lg bg-accent/50 text-foreground/60 px-3 py-2 text-sm leading-relaxed whitespace-pre-wrap break-words", children: [_jsxs("div", { className: "flex items-center gap-1.5 text-[10px] text-muted-foreground mb-1 font-medium uppercase tracking-wide", children: [_jsx(IconClock, { className: "h-3 w-3" }), "Queued"] }), displayText, msg.images && msg.images.length > 0 && (_jsx("div", { className: "flex flex-wrap gap-1.5 mt-1.5", children: msg.images.map((img, j) => (_jsx("img", { src: img, alt: "", className: "h-12 w-12 rounded object-cover border border-border/50" }, j))) })), _jsx("button", { type: "button", onClick: () => setQueuedMessages((prev) => prev.filter((m) => m.id !== msg.id)), "aria-label": "Remove from queue", className: "absolute -top-2 -right-2 flex h-5 w-5 items-center justify-center rounded-full border border-border bg-background text-muted-foreground opacity-0 group-hover:opacity-100 focus-visible:opacity-100 hover:text-foreground hover:bg-accent shadow-sm", children: _jsx(IconX, { className: "h-3 w-3" }) })] }) }, msg.id));
1407
- })] })) }), showScrollToBottom && (_jsx("div", { className: "shrink-0 flex justify-center -mb-1", children: _jsx("button", { type: "button", onClick: scrollToBottom, className: "flex h-7 w-7 items-center justify-center rounded-full border border-border bg-background shadow-sm hover:bg-accent", "aria-label": "Scroll to bottom", children: _jsx(IconChevronDown, { className: "h-3.5 w-3.5 text-muted-foreground" }) }) })), composerSlot, _jsx(SelectionAttachedPill, {}), _jsx("div", { className: "agent-composer-area shrink-0 px-3 py-2", children: _jsxs(ComposerPrimitive.Root, { className: "flex flex-col rounded-lg border border-input bg-background focus-within:ring-1 focus-within:ring-ring", children: [_jsx(ComposerAttachmentPreviewStrip, {}), _jsx(TiptapComposer, { focusRef: tiptapRef, disabled: missingApiKey, placeholder: missingApiKey
1663
+ })] })) }), showScrollToBottom && (_jsx("div", { className: "shrink-0 flex justify-center -mb-1", children: _jsx("button", { type: "button", onClick: scrollToBottom, className: "flex h-7 w-7 items-center justify-center rounded-full border border-border bg-background shadow-sm hover:bg-accent", "aria-label": "Scroll to bottom", children: _jsx(IconChevronDown, { className: "h-3.5 w-3.5 text-muted-foreground" }) }) })), composerSlot, _jsx(SelectionAttachedPill, {}), _jsx("div", { className: "agent-composer-area shrink-0 px-3 py-2", children: _jsxs(ComposerPrimitive.Root, { className: cn("flex flex-col rounded-lg border border-input bg-background focus-within:ring-1 focus-within:ring-ring", execMode === "plan" &&
1664
+ "border-amber-500/50 bg-amber-500/[0.03] focus-within:ring-amber-500/30"), children: [_jsx(ComposerAttachmentPreviewStrip, {}), _jsx(TiptapComposer, { focusRef: tiptapRef, disabled: missingApiKey, placeholder: missingApiKey
1408
1665
  ? "Connect an AI engine above to start chatting…"
1409
1666
  : isRunning
1410
1667
  ? queuedMessages.length > 0
@@ -1417,10 +1674,12 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
1417
1674
  // immediately. This unblocks submission even if the
1418
1675
  // runtime or reconnect state is stuck.
1419
1676
  setForceStopped(true);
1677
+ const activeRun = getActiveRun();
1678
+ const runIdToAbort = reconnectRunIdRef.current ?? activeRun?.runId;
1679
+ if (runIdToAbort) {
1680
+ fetch(`${apiUrl}/runs/${encodeURIComponent(runIdToAbort)}/abort`, { method: "POST" }).catch(() => { });
1681
+ }
1420
1682
  if (isReconnecting) {
1421
- if (reconnectRunIdRef.current) {
1422
- fetch(`${apiUrl}/runs/${encodeURIComponent(reconnectRunIdRef.current)}/abort`, { method: "POST" });
1423
- }
1424
1683
  reconnectAbortRef.current?.abort();
1425
1684
  reconnectAbortRef.current = null;
1426
1685
  reconnectRunIdRef.current = null;