@agent-native/core 0.193.0 → 0.193.1-nightly-20260926224948

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 (70) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/assets/changelog/2026-09-26-builder-is-the-primary-first-run-setup.md +6 -0
  3. package/corpus/templates/chat/app/components/chat/ChatRouteContent.tsx +93 -0
  4. package/corpus/templates/chat/app/i18n/en-US.ts +2 -0
  5. package/corpus/templates/chat/changelog/2026-09-26-builder-setup-retry.md +6 -0
  6. package/corpus/templates/clips/changelog/2026-09-26-builder-is-the-primary-first-run-setup.md +6 -0
  7. package/corpus/templates/content/app/hooks/use-content-recent.ts +137 -16
  8. package/corpus/templates/content/changelog/2026-09-26-empty-recent-list.md +6 -0
  9. package/corpus/templates/design/changelog/2026-09-26-builder-is-the-primary-first-run-setup.md +6 -0
  10. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +9 -8
  11. package/corpus/templates/mail/app/components/layout/HeaderActions.tsx +2 -2
  12. package/corpus/templates/mail/changelog/2026-09-26-fixed-an-inbox-crash-when-the-sidebar-is-pinned.md +6 -0
  13. package/corpus/templates/slides/changelog/2026-09-26-builder-is-the-primary-first-run-setup.md +6 -0
  14. package/dist/automation/index.d.ts +1 -1
  15. package/dist/client/AgentPanel.js +3 -2
  16. package/dist/client/agent-chat/index.d.ts +1 -1
  17. package/dist/client/agent-chat/index.js +1 -1
  18. package/dist/client/chat/agentkit-protocol.js +18 -1
  19. package/dist/client/chat/run-recovery.d.ts +1 -0
  20. package/dist/client/chat/run-recovery.js +1 -1
  21. package/dist/client/onboarding/FirstRunOnboarding.js +59 -22
  22. package/dist/client/ui/AppSidebar.d.ts +2 -1
  23. package/dist/client/ui/AppSidebar.js +11 -2
  24. package/dist/client/ui/index.d.ts +1 -1
  25. package/dist/client/ui/index.js +1 -1
  26. package/dist/collab/routes.d.ts +1 -1
  27. package/dist/localization/core-messages/ar-SA.js +1 -0
  28. package/dist/localization/core-messages/de-DE.js +1 -0
  29. package/dist/localization/core-messages/en-US.d.ts +1 -0
  30. package/dist/localization/core-messages/en-US.js +1 -0
  31. package/dist/localization/core-messages/es-ES.js +1 -0
  32. package/dist/localization/core-messages/fr-FR.js +1 -0
  33. package/dist/localization/core-messages/hi-IN.js +1 -0
  34. package/dist/localization/core-messages/ja-JP.js +1 -0
  35. package/dist/localization/core-messages/ko-KR.js +1 -0
  36. package/dist/localization/core-messages/pt-BR.js +1 -0
  37. package/dist/localization/core-messages/zh-CN.js +1 -0
  38. package/dist/localization/core-messages/zh-TW.js +1 -0
  39. package/dist/localization/core-messages.d.ts +1 -0
  40. package/dist/observability/routes.d.ts +1 -1
  41. package/dist/resources/handlers.d.ts +1 -1
  42. package/dist/server/agent-engine-ollama-models-route.d.ts +1 -1
  43. package/dist/server/core-routes-plugin.d.ts +1 -1
  44. package/dist/templates/chat/app/components/chat/ChatRouteContent.tsx +93 -0
  45. package/dist/templates/chat/app/i18n/ar-SA.ts +1 -0
  46. package/dist/templates/chat/app/i18n/de-DE.ts +2 -0
  47. package/dist/templates/chat/app/i18n/en-US.ts +2 -0
  48. package/dist/templates/chat/app/i18n/es-ES.ts +2 -0
  49. package/dist/templates/chat/app/i18n/fr-FR.ts +2 -0
  50. package/dist/templates/chat/app/i18n/hi-IN.ts +2 -0
  51. package/dist/templates/chat/app/i18n/ja-JP.ts +2 -0
  52. package/dist/templates/chat/app/i18n/ko-KR.ts +2 -0
  53. package/dist/templates/chat/app/i18n/pt-BR.ts +2 -0
  54. package/dist/templates/chat/app/i18n/zh-CN.ts +1 -0
  55. package/dist/templates/chat/app/i18n/zh-TW.ts +1 -0
  56. package/dist/templates/chat/changelog/2026-09-26-builder-setup-retry.md +6 -0
  57. package/package.json +1 -1
  58. package/src/templates/chat/app/components/chat/ChatRouteContent.tsx +93 -0
  59. package/src/templates/chat/app/i18n/ar-SA.ts +1 -0
  60. package/src/templates/chat/app/i18n/de-DE.ts +2 -0
  61. package/src/templates/chat/app/i18n/en-US.ts +2 -0
  62. package/src/templates/chat/app/i18n/es-ES.ts +2 -0
  63. package/src/templates/chat/app/i18n/fr-FR.ts +2 -0
  64. package/src/templates/chat/app/i18n/hi-IN.ts +2 -0
  65. package/src/templates/chat/app/i18n/ja-JP.ts +2 -0
  66. package/src/templates/chat/app/i18n/ko-KR.ts +2 -0
  67. package/src/templates/chat/app/i18n/pt-BR.ts +2 -0
  68. package/src/templates/chat/app/i18n/zh-CN.ts +1 -0
  69. package/src/templates/chat/app/i18n/zh-TW.ts +1 -0
  70. package/src/templates/chat/changelog/2026-09-26-builder-setup-retry.md +6 -0
package/corpus/README.md CHANGED
@@ -31,4 +31,4 @@ rg -n "defineAction|useActionQuery" node_modules/@agent-native/core/corpus
31
31
 
32
32
  ## Generated Counts
33
33
 
34
- - template files: 10195
34
+ - template files: 10202
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-09-26
4
+ ---
5
+
6
+ New users can continue with Builder, choose their own API keys, or skip setup and start using Assets.
@@ -3,6 +3,8 @@ import type {
3
3
  AgentMessage,
4
4
  } from "@agent-native/agentkit";
5
5
  import {
6
+ AgentMessageView,
7
+ AgentRunFailure,
6
8
  AgentConnectionRequestCard,
7
9
  AgentKitChat,
8
10
  } from "@agent-native/agentkit/react/components";
@@ -10,9 +12,14 @@ import {
10
12
  useAgentKit,
11
13
  useAgentKitControl,
12
14
  useAgentThread,
15
+ type AgentRunFailureRenderProps,
13
16
  type AgentKitRenderProps,
14
17
  } from "@agent-native/agentkit/react/context";
15
18
  import { AgentKitRoot } from "@agent-native/agentkit/react/root";
19
+ import {
20
+ BuilderSetupCard,
21
+ isMissingLlmProviderRunError,
22
+ } from "@agent-native/core/client/agent-chat";
16
23
  import { CoreComposerRuntimeProvider } from "@agent-native/core/client/agentkit-chat/composer";
17
24
  import {
18
25
  McpAgentKitConnectionRequestCard,
@@ -120,7 +127,9 @@ function ChatThreadRouteContent({
120
127
  labels={{ composerPlaceholder: t("chat.composerPlaceholder") }}
121
128
  slots={{
122
129
  emptyState: ChatEmptyState,
130
+ message: ChatMessage,
123
131
  messageSupplement: ChatMcpConnectionSuggestion,
132
+ runFailure: ChatRunFailure,
124
133
  connectionRequest: ChatMcpConnectionRequest,
125
134
  footer: ChatAgentFooter,
126
135
  }}
@@ -153,6 +162,90 @@ function ChatThreadRouteContent({
153
162
  );
154
163
  }
155
164
 
165
+ function ChatMessage({ value, threadId }: AgentKitRenderProps<AgentMessage>) {
166
+ const metadata = value.metadata as
167
+ | { custom?: { agentNativeRecoveryAction?: unknown } }
168
+ | undefined;
169
+ const recoveryAction = metadata?.custom?.agentNativeRecoveryAction;
170
+ if (
171
+ value.role === "user" &&
172
+ (recoveryAction === "continue" || recoveryAction === "retry")
173
+ ) {
174
+ return null;
175
+ }
176
+ return <AgentMessageView value={value} threadId={threadId} />;
177
+ }
178
+
179
+ function ChatRunFailure({
180
+ error,
181
+ runId,
182
+ threadId,
183
+ }: AgentRunFailureRenderProps) {
184
+ const thread = useAgentThread(threadId);
185
+ const { controller } = useAgentKit();
186
+ const t = useT();
187
+ const recoveryMetadata = (message: (typeof thread.messages)[number]) =>
188
+ (
189
+ message.metadata as
190
+ | {
191
+ custom?: {
192
+ agentNativeRecoveryAction?: unknown;
193
+ agentNativeRecoveryOfRunId?: unknown;
194
+ };
195
+ }
196
+ | undefined
197
+ )?.custom;
198
+ const userRequests = thread.messages.filter((message) => {
199
+ if (message.role !== "user") return false;
200
+ const action = recoveryMetadata(message)?.agentNativeRecoveryAction;
201
+ return action !== "continue" && action !== "retry";
202
+ });
203
+ const originalRequest = userRequests[0];
204
+ const hasRetryForThisRun = thread.messages.some(
205
+ (message) =>
206
+ recoveryMetadata(message)?.agentNativeRecoveryAction === "retry" &&
207
+ recoveryMetadata(message)?.agentNativeRecoveryOfRunId === runId,
208
+ );
209
+ const retryFirstMessage = useCallback(() => {
210
+ const prompt =
211
+ originalRequest?.parts
212
+ .filter((part) => part.type === "text")
213
+ .map((part) => part.text)
214
+ .join("\n") ?? "";
215
+ const attachments =
216
+ originalRequest?.parts.filter((part) => part.type === "file") ?? [];
217
+ void controller.sendMessage({
218
+ threadId,
219
+ text: prompt || t("chat.retryPreviousRequest"),
220
+ ...(attachments.length ? { attachments } : {}),
221
+ metadata: {
222
+ custom: {
223
+ agentNativeRecoveryAction: "retry",
224
+ agentNativeRecoveryOfRunId: runId,
225
+ },
226
+ },
227
+ });
228
+ }, [controller, originalRequest, runId, t, threadId]);
229
+ const isFirstMessage = userRequests.length === 1 && !hasRetryForThisRun;
230
+ if (
231
+ isFirstMessage &&
232
+ isMissingLlmProviderRunError({
233
+ message: error.message,
234
+ details: typeof error.details === "string" ? error.details : undefined,
235
+ errorCode: error.code,
236
+ })
237
+ ) {
238
+ return (
239
+ <BuilderSetupCard
240
+ fullWidth
241
+ layout="sidebar"
242
+ onRetry={retryFirstMessage}
243
+ />
244
+ );
245
+ }
246
+ return <AgentRunFailure error={error} runId={runId} threadId={threadId} />;
247
+ }
248
+
156
249
  function ChatLifecycleTracking({ threadId }: { threadId: string }) {
157
250
  const thread = useAgentThread(threadId);
158
251
  const lifecycleRef = useRef({
@@ -33,6 +33,8 @@ const messages = {
33
33
  pinChat: "Pin Chat",
34
34
  pinned: "Pinned",
35
35
  recents: "Recents",
36
+ retryPreviousRequest:
37
+ "Retry my previous request now that the model provider is connected.",
36
38
  renameChat: "Rename Chat",
37
39
  renameFailed: "Rename Failed",
38
40
  renameThread: "Rename Thread",
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: added
3
+ date: 2026-09-26
4
+ ---
5
+
6
+ Chat can connect Builder when model credentials are missing and retry the original request with its files.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-09-26
4
+ ---
5
+
6
+ New users can continue with Builder, choose their own API keys, or skip setup and start using Clips.
@@ -11,9 +11,51 @@ import {
11
11
  type ContentRecentTarget,
12
12
  } from "@shared/content-personal-navigation";
13
13
  import { useQueryClient } from "@tanstack/react-query";
14
- import { useCallback, useEffect, useRef } from "react";
14
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
15
15
  import { toast } from "sonner";
16
16
 
17
+ const contentRecentRecoveries = new WeakMap<
18
+ ReturnType<typeof useQueryClient>,
19
+ Map<string, Promise<void>>
20
+ >();
21
+
22
+ function recoverContentRecentScope(
23
+ queryClient: ReturnType<typeof useQueryClient>,
24
+ scopeKey: string,
25
+ refresh: () => Promise<void>,
26
+ ) {
27
+ let recoveries = contentRecentRecoveries.get(queryClient);
28
+ if (!recoveries) {
29
+ recoveries = new Map();
30
+ contentRecentRecoveries.set(queryClient, recoveries);
31
+ }
32
+ const recovery = recoveries.get(scopeKey);
33
+ if (recovery) return recovery;
34
+
35
+ let nextRecovery: Promise<void>;
36
+ nextRecovery = Promise.resolve()
37
+ .then(refresh)
38
+ .finally(() => {
39
+ if (recoveries.get(scopeKey) === nextRecovery) {
40
+ recoveries.delete(scopeKey);
41
+ }
42
+ });
43
+ recoveries.set(scopeKey, nextRecovery);
44
+ return nextRecovery;
45
+ }
46
+
47
+ function contentRecentScopeKey(
48
+ org: ReturnType<typeof useOrg>["data"],
49
+ spaceId?: string,
50
+ ) {
51
+ if (!org) return undefined;
52
+ return JSON.stringify([
53
+ org.email.trim().toLowerCase(),
54
+ org.orgId ?? null,
55
+ spaceId ?? null,
56
+ ]);
57
+ }
58
+
17
59
  export function contentRecentQueryArgs(
18
60
  scopeKey: string | undefined,
19
61
  spaceId?: string,
@@ -22,31 +64,110 @@ export function contentRecentQueryArgs(
22
64
  return { scopeKey, ...(spaceId ? { spaceId } : {}) };
23
65
  }
24
66
 
67
+ export function isContentRecentContextChanged(error: unknown): boolean {
68
+ return (
69
+ !!error &&
70
+ typeof error === "object" &&
71
+ (error as { errorCode?: unknown }).errorCode === "context_changed"
72
+ );
73
+ }
74
+
25
75
  export function useContentRecent(spaceId?: string) {
26
76
  const org = useOrg();
27
- const scopeKey = org.data
28
- ? JSON.stringify([
29
- org.data.email.trim().toLowerCase(),
30
- org.data.orgId ?? null,
31
- spaceId ?? null,
32
- ])
33
- : undefined;
34
- const query = useActionQuery(
35
- "get-content-recent",
36
- contentRecentQueryArgs(scopeKey, spaceId),
37
- {
38
- enabled: Boolean(scopeKey) && !org.isFetching,
39
- placeholderData: undefined,
77
+ const queryClient = useQueryClient();
78
+ const scopeKey = contentRecentScopeKey(org.data, spaceId);
79
+ const args = useMemo(
80
+ () => contentRecentQueryArgs(scopeKey, spaceId),
81
+ [scopeKey, spaceId],
82
+ );
83
+ const query = useActionQuery("get-content-recent", args, {
84
+ enabled: Boolean(scopeKey) && !org.isFetching,
85
+ placeholderData: undefined,
86
+ });
87
+ const [refreshingScopes, setRefreshingScopes] = useState<Set<string>>(
88
+ () => new Set(),
89
+ );
90
+ const resyncedScopesRef = useRef(new Set<string>());
91
+ const contextChanged = isContentRecentContextChanged(query.error);
92
+
93
+ useEffect(() => {
94
+ if (!contextChanged) {
95
+ if (scopeKey) {
96
+ resyncedScopesRef.current.delete(scopeKey);
97
+ }
98
+ return;
99
+ }
100
+ if (!scopeKey) return;
101
+ if (resyncedScopesRef.current.has(scopeKey)) return;
102
+
103
+ resyncedScopesRef.current.add(scopeKey);
104
+ setRefreshingScopes((current) => new Set(current).add(scopeKey));
105
+ void recoverContentRecentScope(queryClient, scopeKey, async () => {
106
+ try {
107
+ const refreshedOrg = await org.refetch({ cancelRefetch: false });
108
+ if (refreshedOrg.isError) return;
109
+ const refreshedArgs = contentRecentQueryArgs(
110
+ contentRecentScopeKey(refreshedOrg.data, spaceId),
111
+ spaceId,
112
+ );
113
+ if (!refreshedArgs) return;
114
+ await queryClient.invalidateQueries(
115
+ {
116
+ queryKey: ["action", "get-content-recent", refreshedArgs],
117
+ exact: true,
118
+ },
119
+ { cancelRefetch: false },
120
+ );
121
+ } catch (error) {
122
+ console.warn(
123
+ "Could not refresh the Content Recent context after a scope mismatch.",
124
+ error,
125
+ );
126
+ }
127
+ }).finally(() => {
128
+ setRefreshingScopes((current) => {
129
+ if (!current.has(scopeKey)) return current;
130
+ const next = new Set(current);
131
+ next.delete(scopeKey);
132
+ return next;
133
+ });
134
+ });
135
+ }, [
136
+ contextChanged,
137
+ org.refetch,
138
+ query.error,
139
+ query.isError,
140
+ queryClient,
141
+ scopeKey,
142
+ spaceId,
143
+ ]);
144
+
145
+ const refetch = useCallback(
146
+ (...args: Parameters<typeof query.refetch>) => {
147
+ if (contextChanged && scopeKey) {
148
+ resyncedScopesRef.current.delete(scopeKey);
149
+ contentRecentRecoveries.get(queryClient)?.delete(scopeKey);
150
+ }
151
+ return query.refetch(...args);
40
152
  },
153
+ [contextChanged, query.refetch, scopeKey],
41
154
  );
155
+
156
+ const recoveringContext =
157
+ contextChanged &&
158
+ (!scopeKey ||
159
+ refreshingScopes.has(scopeKey) ||
160
+ !resyncedScopesRef.current.has(scopeKey));
42
161
  return {
43
162
  ...query,
163
+ refetch,
44
164
  data:
45
165
  !org.isFetching && query.data?.scopeKey === scopeKey
46
166
  ? query.data
47
167
  : undefined,
48
- isLoading: org.isLoading || org.isFetching || query.isLoading,
49
- isError: org.isError || query.isError,
168
+ isLoading:
169
+ org.isLoading || org.isFetching || query.isLoading || recoveringContext,
170
+ isError: org.isError || (query.isError && !recoveringContext),
50
171
  };
51
172
  }
52
173
 
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-09-26
4
+ ---
5
+
6
+ An empty Recent list now loads without an error after first run.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-09-26
4
+ ---
5
+
6
+ New users can continue with Builder, choose their own API keys, or skip setup and start using Design.
@@ -16,6 +16,7 @@ import {
16
16
  AppSidebarHeader,
17
17
  EnvironmentBadge,
18
18
  FeedbackButton,
19
+ RouterSidebarLink,
19
20
  } from "@agent-native/core/client/ui";
20
21
  import { SidebarFooterActions } from "@agent-native/toolkit/app-shell";
21
22
  import {
@@ -1458,7 +1459,7 @@ function AppLayoutInner({ children }: AppLayoutProps) {
1458
1459
  dropIndicator?.tabIndex === tabIndex &&
1459
1460
  dropIndicator.side === "right";
1460
1461
  const link = (
1461
- <Link
1462
+ <RouterSidebarLink
1462
1463
  to={tab.href}
1463
1464
  aria-current={tab.isActive ? "page" : undefined}
1464
1465
  draggable={canDrag}
@@ -1492,7 +1493,7 @@ function AppLayoutInner({ children }: AppLayoutProps) {
1492
1493
  {count}
1493
1494
  </span>
1494
1495
  )}
1495
- </Link>
1496
+ </RouterSidebarLink>
1496
1497
  );
1497
1498
  return (
1498
1499
  <div
@@ -1900,7 +1901,7 @@ function AppLayoutInner({ children }: AppLayoutProps) {
1900
1901
  return (
1901
1902
  <Tooltip key={item.id}>
1902
1903
  <TooltipTrigger asChild>
1903
- <Link
1904
+ <RouterSidebarLink
1904
1905
  to={item.href}
1905
1906
  aria-label={item.label}
1906
1907
  className={cn(
@@ -1913,7 +1914,7 @@ function AppLayoutInner({ children }: AppLayoutProps) {
1913
1914
  {item.count && item.count > 0 ? (
1914
1915
  <span className="absolute end-1 top-1 h-1.5 w-1.5 rounded-full bg-primary" />
1915
1916
  ) : null}
1916
- </Link>
1917
+ </RouterSidebarLink>
1917
1918
  </TooltipTrigger>
1918
1919
  <TooltipContent side="right">
1919
1920
  {item.label}
@@ -2134,14 +2135,14 @@ function AppLayoutInner({ children }: AppLayoutProps) {
2134
2135
  <DevDatabaseLink />
2135
2136
  <Tooltip>
2136
2137
  <TooltipTrigger asChild>
2137
- <Link
2138
+ <RouterSidebarLink
2138
2139
  to="/settings"
2139
2140
  onClick={closeSidebar}
2140
2141
  aria-label={t("mail.toolbar.settings")}
2141
2142
  className="flex size-9 shrink-0 items-center justify-center rounded-md text-primary hover:bg-accent/60 hover:text-primary"
2142
2143
  >
2143
2144
  <IconSettings className="size-4" />
2144
- </Link>
2145
+ </RouterSidebarLink>
2145
2146
  </TooltipTrigger>
2146
2147
  <TooltipContent side="right">
2147
2148
  {t("mail.toolbar.settings")}
@@ -2625,14 +2626,14 @@ function StandardLayout({ children }: AppLayoutProps) {
2625
2626
  <DevDatabaseLink />
2626
2627
  <Tooltip>
2627
2628
  <TooltipTrigger asChild>
2628
- <Link
2629
+ <RouterSidebarLink
2629
2630
  to="/settings"
2630
2631
  onClick={() => setSidebarOpen(false)}
2631
2632
  aria-label={t("mail.toolbar.settings")}
2632
2633
  className="flex size-9 shrink-0 items-center justify-center rounded-md text-primary hover:bg-accent/60 hover:text-primary"
2633
2634
  >
2634
2635
  <IconSettings className="size-4" />
2635
- </Link>
2636
+ </RouterSidebarLink>
2636
2637
  </TooltipTrigger>
2637
2638
  <TooltipContent side="right">
2638
2639
  {t("mail.toolbar.settings")}
@@ -51,7 +51,7 @@ export function useSetPageTitle(node: ReactNode) {
51
51
  currentTitle = null;
52
52
  notify();
53
53
  };
54
- });
54
+ }, [node]);
55
55
  }
56
56
 
57
57
  export function useSetHeaderActions(node: ReactNode) {
@@ -70,5 +70,5 @@ export function useSetHeaderActions(node: ReactNode) {
70
70
  notify();
71
71
  }
72
72
  };
73
- });
73
+ }, [node]);
74
74
  }
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-09-26
4
+ ---
5
+
6
+ Fixed an inbox crash when the sidebar is pinned
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-09-26
4
+ ---
5
+
6
+ New users can continue with Builder, choose their own API keys, or skip setup and start using Slides.
@@ -186,8 +186,8 @@ export declare function createAutomationCallbackHandler(runtime: AutomationRunti
186
186
  duplicate?: undefined;
187
187
  eventId?: undefined;
188
188
  } | {
189
- error?: undefined;
190
189
  accepted: boolean;
191
190
  duplicate: boolean;
192
191
  eventId: string;
192
+ error?: undefined;
193
193
  }>;
@@ -40,7 +40,7 @@ const loadMultiTabAssistantChat = () => import("./MultiTabAssistantChat.js").the
40
40
  default: m.MultiTabAssistantChat,
41
41
  }));
42
42
  const MultiTabAssistantChatLazy = lazy(loadMultiTabAssistantChat);
43
- import { Link, useLocation, useNavigate } from "react-router";
43
+ import { useLocation, useNavigate } from "react-router";
44
44
  import { withBuilderUtmTrackingParams } from "../shared/builder-link-tracking.js";
45
45
  import { AGENT_PANEL_OPEN_SETTINGS_EVENT, AGENT_PANEL_SET_MODE_EVENT, } from "./agent-sidebar-events.js";
46
46
  export { shouldHandleAgentPanelChatShortcut, shouldHandleAgentSidebarToggle, } from "./agent-sidebar-events.js";
@@ -59,6 +59,7 @@ import { useFirstRunOnboardingGateOwnsSurface } from "./onboarding/first-run-sta
59
59
  import { useOnboardingPreviewMode } from "./onboarding/use-preview-mode.js";
60
60
  import { recoverFromStaleChunkError } from "./route-chunk-recovery.js";
61
61
  import { withBuilderConnectTrackingParams } from "./settings/useBuilderStatus.js";
62
+ import { RouterSidebarLink } from "./ui/AppSidebar.js";
62
63
  import { useDevMode } from "./use-dev-mode.js";
63
64
  import { cn } from "./utils.js";
64
65
  function parentFrameTargetOrigin() {
@@ -786,7 +787,7 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
786
787
  // A sibling overlay owns focus next; restoring it to the menu
787
788
  // trigger would dismiss that overlay as an outside interaction.
788
789
  consumeAgentPanelOverlayFocusRestore(preventHeaderMenuFocusRestoreRef, event);
789
- }, children: [onCollapse && (_jsxs(_Fragment, { children: [_jsxs(DropdownMenuItem, { onSelect: onCollapse, children: [_jsx(IconLayoutSidebarRightCollapse, { size: 14, className: "shrink-0" }), t("agentPanel.collapseSidebar"), _jsx(DropdownMenuShortcut, { children: toggleSidebarHint })] }), _jsx(DropdownMenuSeparator, {})] })), onCollapse && mode === "chat" && wideDrawerAction ? (_jsxs(DropdownMenuItem, { onSelect: wideDrawerAction, children: [_jsx(IconArrowsHorizontal, { size: 14, className: "shrink-0" }), wideDrawerLabel, _jsx(DropdownMenuShortcut, { children: widenChatHint })] })) : null, fullViewAction?.kind === "callback" && onFullViewRequest ? (_jsxs(DropdownMenuItem, { onSelect: onFullViewRequest, "aria-label": t("agentPanel.openFullView"), children: [_jsx(IconArrowsMaximize, { size: 14, className: "shrink-0" }), t("agentPanel.openFullView")] })) : fullViewAction?.kind === "link" ? (_jsx(DropdownMenuItem, { asChild: true, children: _jsxs(Link, { to: fullViewAction.href, "aria-label": t("agentPanel.openFullView"), children: [_jsx(IconArrowsMaximize, { size: 14, className: "shrink-0" }), t("agentPanel.openFullView")] }) })) : null, (onCollapse && mode === "chat" && wideDrawerAction) ||
790
+ }, children: [onCollapse && (_jsxs(_Fragment, { children: [_jsxs(DropdownMenuItem, { onSelect: onCollapse, children: [_jsx(IconLayoutSidebarRightCollapse, { size: 14, className: "shrink-0" }), t("agentPanel.collapseSidebar"), _jsx(DropdownMenuShortcut, { children: toggleSidebarHint })] }), _jsx(DropdownMenuSeparator, {})] })), onCollapse && mode === "chat" && wideDrawerAction ? (_jsxs(DropdownMenuItem, { onSelect: wideDrawerAction, children: [_jsx(IconArrowsHorizontal, { size: 14, className: "shrink-0" }), wideDrawerLabel, _jsx(DropdownMenuShortcut, { children: widenChatHint })] })) : null, fullViewAction?.kind === "callback" && onFullViewRequest ? (_jsxs(DropdownMenuItem, { onSelect: onFullViewRequest, "aria-label": t("agentPanel.openFullView"), children: [_jsx(IconArrowsMaximize, { size: 14, className: "shrink-0" }), t("agentPanel.openFullView")] })) : fullViewAction?.kind === "link" ? (_jsx(DropdownMenuItem, { asChild: true, children: _jsxs(RouterSidebarLink, { to: fullViewAction.href, "aria-label": t("agentPanel.openFullView"), children: [_jsx(IconArrowsMaximize, { size: 14, className: "shrink-0" }), t("agentPanel.openFullView")] }) })) : null, (onCollapse && mode === "chat" && wideDrawerAction) ||
790
791
  fullViewAction ? (_jsx(DropdownMenuSeparator, {})) : null, onCollapse &&
791
792
  (newTabMode === "cli" || (mode === "cli" && renderCliTab)) && (_jsxs(_Fragment, { children: [_jsxs(DropdownMenuItem, { onSelect: () => openNewUiTab(addTab), children: [_jsx(IconPlus, { size: 14, className: "shrink-0" }), newUiTabLabel ?? t("agentPanel.newChat")] }), _jsxs(DropdownMenuItem, { onSelect: openNewCliTab, children: [_jsx(IconTerminal2, { size: 14, className: "shrink-0" }), newCliTabLabel ?? t("agentPanel.newTerminal")] }), mode === "chat" ? _jsx(DropdownMenuSeparator, {}) : null] })), onCollapse && mode === "chat" && newTabMode !== "cli" && (_jsxs(DropdownMenuItem, { onSelect: () => openNewUiTab(addTab), children: [_jsx(IconPlus, { size: 14, className: "shrink-0" }), newUiTabLabel ?? t("agentPanel.newChat")] })), onCollapse &&
792
793
  mode === "chat" &&
@@ -18,7 +18,7 @@ export { CodeRequiredDialog, type CodeRequiredDialogProps, } from "../components
18
18
  export { ChatFirstAgentActivityPanel, type ChatFirstAgentActivityPanelProps, } from "../chat-first-agent-activity.js";
19
19
  export { ChatFirstSurfacePanelToggle } from "../chat-first-surface-panel-toggle.js";
20
20
  export { useAgentEngineConfigured, type AgentEngineConfiguredState, type UseAgentEngineConfiguredResult, } from "../use-agent-engine-configured.js";
21
- export { BuilderSetupCard } from "../chat/run-recovery.js";
21
+ export { BuilderSetupCard, isMissingLlmProviderRunError, type RunErrorInfo, } from "../chat/run-recovery.js";
22
22
  export { AgentConversation, AgentConversationMessageView, normalizeCodeAgentTranscriptForConversation, useNearBottomAutoscroll, type CodeAgentConversationTranscriptEvent, type CodeAgentConversationTranscriptEventType, type NormalizeCodeAgentTranscriptOptions, type AgentConversationArtifact, type AgentConversationAttachment, type AgentConversationMessage, type AgentConversationMessagePart, type AgentConversationMessageRole, type AgentConversationNotice, type AgentConversationNoticeTone, type AgentConversationToolCall, type AgentConversationToolState, } from "../conversation/index.js";
23
23
  export { McpAppRenderer } from "../mcp-apps/McpAppRenderer.js";
24
24
  export { AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES, getMcpAppHostContext, initializeMcpAppHost, openMcpAppHostLink, requestMcpAppDisplayMode, sendMcpAppHostMessage, updateMcpAppModelContext, useMcpAppHostContext, type AgentNativeMcpAppHostMessageType, type McpAppDisplayMode, type McpAppHostChatMessage, type McpAppHostCapabilities, type McpAppHostContext, type McpAppHostInfo, type McpAppHostContextSnapshot, type McpAppModelContextContentPart, type McpAppModelContextUpdate, } from "../mcp-app-host.js";
@@ -18,7 +18,7 @@ export { CodeRequiredDialog, } from "../components/CodeRequiredDialog.js";
18
18
  export { ChatFirstAgentActivityPanel, } from "../chat-first-agent-activity.js";
19
19
  export { ChatFirstSurfacePanelToggle } from "../chat-first-surface-panel-toggle.js";
20
20
  export { useAgentEngineConfigured, } from "../use-agent-engine-configured.js";
21
- export { BuilderSetupCard } from "../chat/run-recovery.js";
21
+ export { BuilderSetupCard, isMissingLlmProviderRunError, } from "../chat/run-recovery.js";
22
22
  export { AgentConversation, AgentConversationMessageView, normalizeCodeAgentTranscriptForConversation, useNearBottomAutoscroll, } from "../conversation/index.js";
23
23
  export { McpAppRenderer } from "../mcp-apps/McpAppRenderer.js";
24
24
  export { AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES, getMcpAppHostContext, initializeMcpAppHost, openMcpAppHostLink, requestMcpAppDisplayMode, sendMcpAppHostMessage, updateMcpAppModelContext, useMcpAppHostContext, } from "../mcp-app-host.js";
@@ -1852,12 +1852,29 @@ export function createAgentKitProtocolAdapter(runtime, options = {}) {
1852
1852
  if (input.resume !== undefined) {
1853
1853
  throw new AgentProtocolValidationError("startRun.resume", "Core requires approval continuations to use resumeRun");
1854
1854
  }
1855
- const turnMetadata = mergeTrustedProtocolMetadata(options.metadata, input.metadata, input.options?.metadata, input.options?.agentId ? { agentId: input.options.agentId } : undefined, input.options?.locale ? { locale: input.options.locale } : undefined, input.options?.mode ? { mode: input.options.mode } : undefined);
1855
+ const latestUserMessage = [...input.messages]
1856
+ .reverse()
1857
+ .find((message) => message.role === "user");
1858
+ const latestUserMetadata = asRecord(latestUserMessage?.metadata);
1859
+ const recoveryMetadata = asRecord(latestUserMetadata?.custom);
1860
+ const isRecoveryRetry = recoveryMetadata?.agentNativeRecoveryAction === "retry";
1861
+ const turnMetadata = mergeTrustedProtocolMetadata(options.metadata, input.metadata, input.options?.metadata, input.options?.agentId ? { agentId: input.options.agentId } : undefined, input.options?.locale ? { locale: input.options.locale } : undefined, input.options?.mode ? { mode: input.options.mode } : undefined, isRecoveryRetry ? { agentNativeInternalContinuation: true } : undefined);
1856
1862
  const session = await getSession(input.threadId, turnMetadata);
1857
1863
  const messages = input.messages.map(protocolMessageToRuntimeMessage);
1864
+ const attachments = latestUserMessage?.parts.flatMap((part) => part.type === "file"
1865
+ ? [
1866
+ {
1867
+ name: part.name,
1868
+ ...(part.fileId ? { id: part.fileId } : {}),
1869
+ ...(part.mediaType ? { mediaType: part.mediaType } : {}),
1870
+ ...(part.url ? { url: part.url } : {}),
1871
+ },
1872
+ ]
1873
+ : []) ?? [];
1858
1874
  const turn = await session.startTurn({
1859
1875
  prompt: latestUserPrompt(input.messages),
1860
1876
  messages,
1877
+ ...(attachments.length ? { attachments } : {}),
1861
1878
  model: input.options?.model,
1862
1879
  reasoningEffort: input.options?.reasoningEffort,
1863
1880
  temperature: input.options?.temperature,
@@ -22,6 +22,7 @@ export declare function runErrorHeadline(info: RunErrorInfo, labels?: {
22
22
  }): string;
23
23
  export declare function getRequestModeMetadata(message: unknown): "act" | "plan" | null;
24
24
  export declare function isBuilderReconnectRunError(info: RunErrorInfo): boolean;
25
+ export declare function isMissingLlmProviderRunError(info: RunErrorInfo): boolean;
25
26
  export declare function BuilderConnectCta({ variant, onConnected, reconnect, }: {
26
27
  variant?: "primary" | "compact";
27
28
  onConnected?: () => void;
@@ -119,7 +119,7 @@ function isConnectionRecoveryRunError(info) {
119
119
  message.includes("connection kept failing") ||
120
120
  message.includes("automatic recovery attempts"));
121
121
  }
122
- function isMissingLlmProviderRunError(info) {
122
+ export function isMissingLlmProviderRunError(info) {
123
123
  const code = (info.errorCode ?? "").toLowerCase();
124
124
  const text = [info.message, info.details].filter(Boolean).join("\n");
125
125
  const hasCredentialSetupText = /no llm provider(?: key)? (?:is connected|was found)|missing credentials|missing api key|missing_api_key|(?:api[_ -]?key|auth[_ -]?token)\s*(?:(?:is|was)\s+)?(?:not\s+(?:set|configured|available|present|provided|found)|missing|unavailable|empty|unset|unconfigured)/i.test(text);