@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
@@ -1,5 +1,6 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Badge } from "@agent-native/toolkit/ui/badge";
3
+ import { Button } from "@agent-native/toolkit/ui/button";
3
4
  import { Skeleton } from "@agent-native/toolkit/ui/skeleton";
4
5
  import { IconArrowRight, IconCheck, IconInfoCircle, IconKey, IconLoader2, IconX, } from "@tabler/icons-react";
5
6
  import { useCallback, useEffect, useMemo, useRef, useState, } from "react";
@@ -10,6 +11,7 @@ import { Tooltip, TooltipContent, TooltipTrigger, } from "../components/ui/toolt
10
11
  import { useT } from "../i18n.js";
11
12
  import { useBuilderConnectFlow } from "../settings/useBuilderStatus.js";
12
13
  import { cn } from "../utils.js";
14
+ import { resolveFirstRunOnboardingMode } from "./first-run-enabled.js";
13
15
  import { listFirstRunOnboardingExtensions } from "./first-run-registry.js";
14
16
  import { saveFirstRunOnboardingRole } from "./first-run-status.js";
15
17
  import { trackOnboardingEvent, useOnboarding } from "./use-onboarding.js";
@@ -70,6 +72,7 @@ const BUILDER_MORE_SERVICES = [
70
72
  ];
71
73
  export function FirstRunOnboarding({ initialFirstRun = false, } = {}) {
72
74
  const t = useT();
75
+ const connectFirstRun = resolveFirstRunOnboardingMode() === "connect";
73
76
  const { pathname } = useLocation();
74
77
  const previewMode = useOnboardingPreviewMode();
75
78
  const previewStep = useOnboardingPreviewStep();
@@ -108,17 +111,27 @@ export function FirstRunOnboarding({ initialFirstRun = false, } = {}) {
108
111
  const completionInFlightRef = useRef(false);
109
112
  const onboardingTerminalRef = useRef(false);
110
113
  const abandonmentTrackedRef = useRef(false);
111
- const setupAttemptRef = useRef(null);
112
114
  const builderSetupAttemptRef = useRef(null);
115
+ const pendingHandoffFailureRef = useRef(null);
116
+ const flushPendingHandoffFailure = useCallback(() => {
117
+ const attempt = pendingHandoffFailureRef.current;
118
+ if (!attempt)
119
+ return;
120
+ pendingHandoffFailureRef.current = null;
121
+ trackFirstRunSetupOutcome(attempt, "handoff_failed", "onboarding_completion_error");
122
+ }, []);
113
123
  const startSetupMethod = useCallback((methodId, methodKind) => {
114
124
  if (previewMode || typeof window === "undefined")
115
125
  return null;
126
+ flushPendingHandoffFailure();
116
127
  const attempt = {
117
128
  id: window.crypto.randomUUID(),
118
129
  methodId,
119
130
  outcomeTracked: false,
120
131
  };
121
- setupAttemptRef.current = attempt;
132
+ if (methodKind !== "builder") {
133
+ pendingHandoffFailureRef.current = attempt;
134
+ }
122
135
  const properties = {
123
136
  flow: "first_run",
124
137
  step_id: "choice",
@@ -129,20 +142,23 @@ export function FirstRunOnboarding({ initialFirstRun = false, } = {}) {
129
142
  trackOnboardingEvent("onboarding_method_clicked", properties);
130
143
  trackOnboardingEvent("onboarding_method_started", properties);
131
144
  return attempt;
132
- }, [previewMode]);
133
- const finishOnboarding = useCallback(async (completedScreen, completedExtensionIndex = extensionIndex) => {
134
- completionAttemptRef.current = completedScreen
135
- ? { screen: completedScreen, extensionIndex: completedExtensionIndex }
136
- : { screen: null, extensionIndex: completedExtensionIndex };
145
+ }, [flushPendingHandoffFailure, previewMode]);
146
+ const finishOnboarding = useCallback(async (completedScreen, completedExtensionIndex = extensionIndex, onSuccess) => {
147
+ completionAttemptRef.current = {
148
+ screen: completedScreen,
149
+ extensionIndex: completedExtensionIndex,
150
+ ...(onSuccess ? { onSuccess } : {}),
151
+ };
137
152
  completionInFlightRef.current = true;
153
+ let onSuccessAfterCompletion;
138
154
  try {
139
155
  await completeFirstRun();
140
156
  if (completedScreen) {
141
157
  trackFirstRunStepCompleted(completedScreen, completedExtensionIndex);
142
158
  }
143
159
  onboardingTerminalRef.current = true;
160
+ onSuccessAfterCompletion = completionAttemptRef.current?.onSuccess;
144
161
  completionAttemptRef.current = null;
145
- return true;
146
162
  }
147
163
  catch {
148
164
  // coercion-ok: completeFirstRun exposes this failure as the inline retry state.
@@ -151,6 +167,8 @@ export function FirstRunOnboarding({ initialFirstRun = false, } = {}) {
151
167
  finally {
152
168
  completionInFlightRef.current = false;
153
169
  }
170
+ onSuccessAfterCompletion?.();
171
+ return true;
154
172
  }, [completeFirstRun, extensionIndex, trackFirstRunStepCompleted]);
155
173
  useEffect(() => {
156
174
  if (!previewMode && firstRun && !loading && profile) {
@@ -182,6 +200,7 @@ export function FirstRunOnboarding({ initialFirstRun = false, } = {}) {
182
200
  completionInFlightRef.current)
183
201
  return;
184
202
  abandonmentTrackedRef.current = true;
203
+ flushPendingHandoffFailure();
185
204
  trackOnboardingEvent("onboarding_abandoned", {
186
205
  ...firstRunStepProperties(screen, extensions, extensionIndex),
187
206
  reason: "page_exit",
@@ -197,6 +216,7 @@ export function FirstRunOnboarding({ initialFirstRun = false, } = {}) {
197
216
  previewMode,
198
217
  profile,
199
218
  screen,
219
+ flushPendingHandoffFailure,
200
220
  ]);
201
221
  const handleFinish = useCallback((completedScreen, track = true) => {
202
222
  if (extensions.length === 0) {
@@ -211,7 +231,6 @@ export function FirstRunOnboarding({ initialFirstRun = false, } = {}) {
211
231
  const handleBuilderConnected = useCallback(() => {
212
232
  trackFirstRunSetupOutcome(builderSetupAttemptRef.current, "connected");
213
233
  builderSetupAttemptRef.current = null;
214
- setupAttemptRef.current = null;
215
234
  trackFirstRunStepCompleted("choice");
216
235
  trackFirstRunStepCompleted("connecting");
217
236
  handleFinish(null);
@@ -238,7 +257,7 @@ export function FirstRunOnboarding({ initialFirstRun = false, } = {}) {
238
257
  const canActivateBuilderFreeCredits = connectFlow.agentNativeProvisioningEnabled;
239
258
  const retryOnboardingCompletion = useCallback(() => {
240
259
  const attempt = completionAttemptRef.current;
241
- void finishOnboarding(attempt?.screen ?? null, attempt?.extensionIndex ?? extensionIndex);
260
+ void finishOnboarding(attempt?.screen ?? null, attempt?.extensionIndex ?? extensionIndex, attempt?.onSuccess);
242
261
  }, [extensionIndex, finishOnboarding]);
243
262
  const completionErrorProps = {
244
263
  completionError: completeFirstRunError,
@@ -263,7 +282,6 @@ export function FirstRunOnboarding({ initialFirstRun = false, } = {}) {
263
282
  if (connectFlow.hasFetchedStatus && connectFlow.configured) {
264
283
  trackFirstRunSetupOutcome(attempt, "already_connected");
265
284
  builderSetupAttemptRef.current = null;
266
- setupAttemptRef.current = null;
267
285
  trackFirstRunStepCompleted("choice");
268
286
  handleFinish(null);
269
287
  return;
@@ -278,16 +296,7 @@ export function FirstRunOnboarding({ initialFirstRun = false, } = {}) {
278
296
  provisionAccount,
279
297
  });
280
298
  };
281
- const handleOpenSettings = async () => {
282
- if (completionInFlightRef.current)
283
- return;
284
- const attempt = startSetupMethod("custom_keys", "manual");
285
- const completed = await finishOnboarding("choice");
286
- if (!completed) {
287
- trackFirstRunSetupOutcome(attempt, "handoff_failed", "onboarding_completion_error");
288
- return;
289
- }
290
- trackFirstRunSetupOutcome(attempt, "settings_opened");
299
+ const navigateToKeySettings = () => {
291
300
  if (typeof window === "undefined")
292
301
  return;
293
302
  // Drop the onboarding preview params — useOnboardingPreviewMode() reads
@@ -300,6 +309,31 @@ export function FirstRunOnboarding({ initialFirstRun = false, } = {}) {
300
309
  window.history.pushState(null, "", `${appMountedPath(buildSettingsRoute("keys"), pathname || STANDARD_APP_ROUTES.home)}${query ? `?${query}` : ""}`);
301
310
  window.dispatchEvent(new Event("popstate"));
302
311
  };
312
+ const handleOpenSettings = async () => {
313
+ if (completionInFlightRef.current)
314
+ return;
315
+ const attempt = startSetupMethod("custom_keys", "manual");
316
+ await finishOnboarding("choice", extensionIndex, () => {
317
+ if (pendingHandoffFailureRef.current === attempt) {
318
+ pendingHandoffFailureRef.current = null;
319
+ }
320
+ trackFirstRunSetupOutcome(attempt, "settings_opened");
321
+ navigateToKeySettings();
322
+ });
323
+ };
324
+ const handleSkipToApp = async () => {
325
+ if (completionInFlightRef.current)
326
+ return;
327
+ const attempt = startSetupMethod("skip_to_app", "skip");
328
+ await finishOnboarding(null, extensionIndex, () => {
329
+ if (pendingHandoffFailureRef.current === attempt) {
330
+ pendingHandoffFailureRef.current = null;
331
+ }
332
+ trackFirstRunStepSkipped("choice", "skip_to_app");
333
+ trackFirstRunSetupOutcome(attempt, "skipped_to_app");
334
+ });
335
+ };
336
+ const builderStatusPending = !previewMode && !connectFlow.statusResolved;
303
337
  const handleRoleContinue = async () => {
304
338
  const roleToSave = selectedRole === "other" ? customRole.trim() : selectedRole;
305
339
  if (!roleToSave || savingRole)
@@ -348,6 +382,9 @@ export function FirstRunOnboarding({ initialFirstRun = false, } = {}) {
348
382
  void finishOnboarding(null);
349
383
  } }) }));
350
384
  }
385
+ if (screen === "choice" && connectFirstRun) {
386
+ return (_jsx(OnboardingShell, { profile: profile, screen: "choice", ...completionErrorProps, children: _jsxs("div", { className: "mx-auto flex w-full max-w-md flex-col items-center gap-6", children: [_jsx("h1", { className: "text-xl font-semibold tracking-[-0.03em] text-foreground", children: t("agentChat.setup.connectBuilder") }), _jsxs("div", { className: "flex w-full flex-col items-center gap-3", children: [_jsxs(Button, { type: "button", "data-testid": "first-run-builder-continue", className: cn(primaryButtonClass, "w-full"), onClick: () => handleBuilder(canActivateBuilderFreeCredits), disabled: builderStatusPending || connectFlow.connecting, children: [t("agentChat.common.continue"), builderStatusPending || connectFlow.connecting ? (_jsx(IconLoader2, { size: 15, className: "animate-spin" })) : (_jsx(IconArrowRight, { size: 15 }))] }), _jsxs("p", { className: "text-center text-xs leading-5 text-muted-foreground", children: [t("agentChat.onboarding.builderConsentPrefix"), " ", _jsx("a", { href: "https://www.builder.io/legal/terms", target: "_blank", rel: "noreferrer", className: "text-foreground underline decoration-border underline-offset-2 hover:decoration-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", children: t("agentChat.onboarding.builderTerms") }), " ", t("agentChat.onboarding.builderConsentAnd"), " ", _jsx("a", { href: "https://www.builder.io/legal/privacy", target: "_blank", rel: "noreferrer", className: "text-foreground underline decoration-border underline-offset-2 hover:decoration-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", children: t("agentChat.onboarding.builderPrivacy") }), "."] })] }), connectFlow.error && !connectFlow.statusResolved && !previewMode && (_jsxs("div", { className: "flex flex-col items-center gap-2", children: [_jsx("p", { role: "status", "data-testid": "first-run-builder-status-error", className: "text-center text-xs text-destructive", children: t("agentChat.setup.providerStatusUnavailable") }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", className: "min-h-8 rounded-lg px-2.5 text-xs font-medium text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", onClick: () => connectFlow.retry(), children: t("agentChat.common.retry") })] })), _jsxs("div", { className: "flex flex-col items-center gap-2", children: [_jsx(Button, { type: "button", variant: "ghost", size: "sm", "data-testid": "first-run-open-key-settings", className: "min-h-9 rounded-lg px-2.5 text-sm font-medium text-muted-foreground underline underline-offset-4 transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", onClick: () => void handleOpenSettings(), children: t("agentChat.onboarding.useOwnApiKeys") }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", "data-testid": "first-run-skip-to-app", className: "min-h-8 rounded-lg px-2.5 text-xs font-medium text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", onClick: () => void handleSkipToApp(), children: t("agentChat.onboarding.skipForNow") })] })] }) }));
387
+ }
351
388
  if (screen === "choice") {
352
389
  return (_jsx(OnboardingShell, { profile: profile, screen: "choice", ...completionErrorProps, children: _jsxs("div", { className: "mx-auto flex w-full max-w-3xl flex-col gap-9", children: [_jsxs("div", { className: "flex flex-col gap-6", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx("h1", { className: "text-[28px] font-bold leading-tight tracking-[-0.02em] text-foreground", children: "Choose your setup" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "We recommend starting with Builder.io for the fastest setup." })] }), _jsxs("div", { className: "grid gap-6 sm:grid-cols-2", children: [_jsxs("section", { className: "flex flex-col gap-5 rounded-2xl border border-border bg-card p-6", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("h2", { className: "text-lg font-bold text-foreground", children: "Use Builder.io" }), _jsx(Badge, { variant: "secondary", className: "font-medium", children: "Recommended" })] }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Configure using Builder.io and use your account credits to power the app\u2019s services." })] }), _jsxs("div", { className: "flex flex-col gap-1 rounded-[10px] bg-emerald-50 px-4 py-3 dark:bg-emerald-950/30", children: [_jsx("p", { className: "text-[13px] font-semibold text-foreground", children: "Included free with a Builder.io account" }), _jsx("p", { className: "text-xs font-medium text-emerald-700 dark:text-emerald-400", children: "60 monthly Agent Credits" })] }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("p", { className: "text-sm text-muted-foreground/70", children: "What\u2019s included" }), builderCapabilities.map((capability) => {
353
390
  const copy = getCapabilityCopy(t, capability);
@@ -355,7 +392,7 @@ export function FirstRunOnboarding({ initialFirstRun = false, } = {}) {
355
392
  defaultValue: "About {{label}}",
356
393
  label: copy.label,
357
394
  }) }))] }, capability.id));
358
- }), BUILDER_MORE_SERVICES.filter((service) => !builderCapabilities.some((capability) => getCapabilityCopy(t, capability).label.toLowerCase() === service.toLowerCase())).map((service) => (_jsxs("div", { className: "flex items-center gap-2 rounded-md px-2 py-1", children: [_jsx(IconCheck, { className: "shrink-0 text-muted-foreground", size: 15 }), _jsx("span", { className: "text-xs text-foreground", children: service })] }, service)))] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx("button", { type: "button", "data-testid": "first-run-builder-create-account", className: cn(primaryButtonClass, "w-full"), onClick: () => handleBuilder(true), disabled: connectFlow.connecting, children: t("agentChat.onboarding.builderCreateAccount") }), _jsx("button", { type: "button", "data-testid": "first-run-builder-sign-in", className: cn(mutedButtonClass, "w-full"), onClick: () => handleBuilder(false), disabled: connectFlow.connecting, children: t("agentChat.onboarding.builderSignInWithAccount") })] }), connectFlow.error && !connectFlow.statusResolved && (_jsx("p", { role: "status", "data-testid": "first-run-builder-status-error", className: "text-center text-xs text-destructive", children: connectFlow.error }))] }), _jsxs("section", { className: "flex flex-col gap-5 rounded-2xl border border-border bg-card p-6", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx("h2", { className: "text-lg font-bold text-foreground", children: "Configure manually" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Configure your own API keys and credentials to power the app\u2019s services." })] }), _jsxs("div", { className: "flex flex-col gap-1 rounded-xl bg-muted px-4 py-3", children: [_jsx("p", { className: "text-[13px] font-semibold text-foreground", children: "You configure and maintain everything" }), _jsx("p", { className: "text-xs text-muted-foreground", children: "Full control over your infrastructure" })] }), _jsx(CapabilityList, { capabilities: profile.capabilities, className: "flex-1" }), _jsx("button", { type: "button", "data-testid": "first-run-open-key-settings", className: cn(secondaryButtonClass, "w-full"), onClick: () => void handleOpenSettings(), children: "Skip and configure manually" })] })] })] }), _jsxs("p", { className: "text-center text-xs leading-5 text-muted-foreground", children: [t("agentChat.onboarding.builderConsentPrefix"), " ", _jsx("a", { href: "https://www.builder.io/legal/terms", target: "_blank", rel: "noreferrer", className: "text-foreground underline decoration-border underline-offset-2 hover:decoration-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", children: t("agentChat.onboarding.builderTerms") }), " ", t("agentChat.onboarding.builderConsentAnd"), " ", _jsx("a", { href: "https://www.builder.io/legal/privacy", target: "_blank", rel: "noreferrer", className: "text-foreground underline decoration-border underline-offset-2 hover:decoration-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", children: t("agentChat.onboarding.builderPrivacy") }), "."] })] }) }));
395
+ }), BUILDER_MORE_SERVICES.filter((service) => !builderCapabilities.some((capability) => getCapabilityCopy(t, capability).label.toLowerCase() === service.toLowerCase())).map((service) => (_jsxs("div", { className: "flex items-center gap-2 rounded-md px-2 py-1", children: [_jsx(IconCheck, { className: "shrink-0 text-muted-foreground", size: 15 }), _jsx("span", { className: "text-xs text-foreground", children: service })] }, service)))] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx("button", { type: "button", "data-testid": "first-run-builder-create-account", className: cn(primaryButtonClass, "w-full"), onClick: () => handleBuilder(true), disabled: connectFlow.connecting, children: t("agentChat.onboarding.builderCreateAccount") }), _jsx("button", { type: "button", "data-testid": "first-run-builder-sign-in", className: cn(mutedButtonClass, "w-full"), onClick: () => handleBuilder(false), disabled: connectFlow.connecting, children: t("agentChat.onboarding.builderSignInWithAccount") })] }), connectFlow.error && !connectFlow.statusResolved && (_jsx("p", { role: "status", "data-testid": "first-run-builder-status-error", className: "text-center text-xs text-destructive", children: t("agentChat.setup.providerStatusUnavailable") }))] }), _jsxs("section", { className: "flex flex-col gap-5 rounded-2xl border border-border bg-card p-6", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx("h2", { className: "text-lg font-bold text-foreground", children: "Configure manually" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Configure your own API keys and credentials to power the app\u2019s services." })] }), _jsxs("div", { className: "flex flex-col gap-1 rounded-xl bg-muted px-4 py-3", children: [_jsx("p", { className: "text-[13px] font-semibold text-foreground", children: "You configure and maintain everything" }), _jsx("p", { className: "text-xs text-muted-foreground", children: "Full control over your infrastructure" })] }), _jsx(CapabilityList, { capabilities: profile.capabilities, className: "flex-1" }), _jsx("button", { type: "button", "data-testid": "first-run-open-key-settings", className: cn(secondaryButtonClass, "w-full"), onClick: () => void handleOpenSettings(), children: "Skip and configure manually" })] })] })] }), _jsxs("p", { className: "text-center text-xs leading-5 text-muted-foreground", children: [t("agentChat.onboarding.builderConsentPrefix"), " ", _jsx("a", { href: "https://www.builder.io/legal/terms", target: "_blank", rel: "noreferrer", className: "text-foreground underline decoration-border underline-offset-2 hover:decoration-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", children: t("agentChat.onboarding.builderTerms") }), " ", t("agentChat.onboarding.builderConsentAnd"), " ", _jsx("a", { href: "https://www.builder.io/legal/privacy", target: "_blank", rel: "noreferrer", className: "text-foreground underline decoration-border underline-offset-2 hover:decoration-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", children: t("agentChat.onboarding.builderPrivacy") }), "."] })] }) }));
359
396
  }
360
397
  if (screen === "role") {
361
398
  return (_jsx(OnboardingShell, { profile: profile, screen: "role", ...completionErrorProps, children: _jsxs("div", { className: "mx-auto flex w-full max-w-2xl flex-col", "data-testid": "first-run-role", children: [_jsxs("div", { className: "flex flex-col gap-2 pt-2", children: [_jsx("h1", { className: "text-[28px] font-bold leading-tight tracking-[-0.02em] text-foreground", children: t("agentChat.onboarding.roleQuestion") }), _jsx("p", { className: "text-sm text-muted-foreground", children: t("agentChat.onboarding.roleHelperText") })] }), _jsxs("fieldset", { className: "mt-7 flex flex-col gap-3", children: [_jsx("legend", { className: "sr-only", children: t("agentChat.onboarding.chooseRole") }), FIRST_RUN_ROLE_OPTIONS.map(({ value, labelKey }) => (_jsxs("label", { "data-testid": `first-run-role-${value}`, className: cn("flex cursor-pointer items-center gap-3 rounded-lg border border-border bg-card p-3 text-sm transition-colors focus-within:ring-2 focus-within:ring-ring", selectedRole === value
@@ -1,4 +1,5 @@
1
- import { type AppSidebarProps as ToolkitAppSidebarProps, type AppSidebarHeaderProps as ToolkitAppSidebarHeaderProps, type AppSidebarFooterProps as ToolkitAppSidebarFooterProps } from "@agent-native/toolkit/app-shell";
1
+ import { type AppSidebarLinkProps, type AppSidebarProps as ToolkitAppSidebarProps, type AppSidebarHeaderProps as ToolkitAppSidebarHeaderProps, type AppSidebarFooterProps as ToolkitAppSidebarFooterProps } from "@agent-native/toolkit/app-shell";
2
+ export declare const RouterSidebarLink: import("react").ForwardRefExoticComponent<AppSidebarLinkProps & import("react").RefAttributes<HTMLAnchorElement>>;
2
3
  export interface AppSidebarHeaderProps extends ToolkitAppSidebarHeaderProps {
3
4
  appId?: string;
4
5
  badgeText?: string;
@@ -1,11 +1,20 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { AppSidebar as ToolkitAppSidebar, AppSidebarHeader as ToolkitAppSidebarHeader, AppSidebarFooter as ToolkitAppSidebarFooter, useAppSidebar, } from "@agent-native/toolkit/app-shell";
3
3
  import { forwardRef } from "react";
4
- import { Link } from "react-router";
4
+ import { useHref, useLinkClickHandler } from "react-router";
5
5
  import { AgentNativeIcon } from "../components/icons/AgentNativeIcon.js";
6
6
  import { EnvironmentBadge } from "../EnvironmentBadge.js";
7
7
  import { FeedbackButton } from "../FeedbackButton.js";
8
- const RouterSidebarLink = forwardRef(({ to, href, children, ...props }, ref) => (_jsx(Link, { ref: ref, to: to ?? href ?? "/", ...props, children: children })));
8
+ export const RouterSidebarLink = forwardRef(({ to, href, children, onClick, target, ...props }, ref) => {
9
+ const destination = to ?? href ?? "/";
10
+ const resolvedHref = useHref(destination);
11
+ const handleRouterClick = useLinkClickHandler(destination, { target });
12
+ return (_jsx("a", { ref: ref, href: resolvedHref, target: target, ...props, onClick: (event) => {
13
+ onClick?.(event);
14
+ if (!event.defaultPrevented)
15
+ handleRouterClick(event);
16
+ }, children: children }));
17
+ });
9
18
  RouterSidebarLink.displayName = "RouterSidebarLink";
10
19
  export const AppSidebarHeader = forwardRef(({ brandIcon, badge, appId, badgeText, showBadge = true, brandLink, brandHref = "/", collapsed: propCollapsed, ...props }, ref) => {
11
20
  const context = useAppSidebar();
@@ -19,4 +19,4 @@ export { applyEmbeddedThemeUpdate, buildEmbeddedThemeUpdate, EMBEDDED_THEME_CHAN
19
19
  export { APPEARANCE_PRESETS, applyAppearance, getStoredAppearance, useAppearance, useAppearanceSync, type AppearancePresetId, } from "../appearance.js";
20
20
  export { AppearancePicker, type AppearancePickerProps, } from "../AppearancePicker.js";
21
21
  export { AgentNativeIcon } from "../components/icons/AgentNativeIcon.js";
22
- export { AppSidebar, AppSidebarHeader, AppSidebarNavItem, AppSidebarNavGroup, AppSidebarSection, AppSidebarFeedbackButton, AppSidebarFooter, useAppSidebar, type AppSidebarProps, type AppSidebarHeaderProps, type AppSidebarNavItemProps, type AppSidebarNavGroupProps, type AppSidebarSectionProps, type AppSidebarFeedbackButtonProps, type AppSidebarFooterProps, type AppSidebarItemDefinition, type AppSidebarContextValue, } from "./AppSidebar.js";
22
+ export { AppSidebar, RouterSidebarLink, AppSidebarHeader, AppSidebarNavItem, AppSidebarNavGroup, AppSidebarSection, AppSidebarFeedbackButton, AppSidebarFooter, useAppSidebar, type AppSidebarProps, type AppSidebarHeaderProps, type AppSidebarNavItemProps, type AppSidebarNavGroupProps, type AppSidebarSectionProps, type AppSidebarFeedbackButtonProps, type AppSidebarFooterProps, type AppSidebarItemDefinition, type AppSidebarContextValue, } from "./AppSidebar.js";
@@ -19,4 +19,4 @@ export { applyEmbeddedThemeUpdate, buildEmbeddedThemeUpdate, EMBEDDED_THEME_CHAN
19
19
  export { APPEARANCE_PRESETS, applyAppearance, getStoredAppearance, useAppearance, useAppearanceSync, } from "../appearance.js";
20
20
  export { AppearancePicker, } from "../AppearancePicker.js";
21
21
  export { AgentNativeIcon } from "../components/icons/AgentNativeIcon.js";
22
- export { AppSidebar, AppSidebarHeader, AppSidebarNavItem, AppSidebarNavGroup, AppSidebarSection, AppSidebarFeedbackButton, AppSidebarFooter, useAppSidebar, } from "./AppSidebar.js";
22
+ export { AppSidebar, RouterSidebarLink, AppSidebarHeader, AppSidebarNavItem, AppSidebarNavGroup, AppSidebarSection, AppSidebarFeedbackButton, AppSidebarFooter, useAppSidebar, } from "./AppSidebar.js";
@@ -26,8 +26,8 @@ export declare const getCollabState: import("h3").EventHandlerWithFetch<import("
26
26
  * Body: { update: string (base64), requestSource?: string }
27
27
  */
28
28
  export declare const postCollabUpdate: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
29
- error: string;
30
29
  ok?: undefined;
30
+ error: string;
31
31
  } | {
32
32
  error?: undefined;
33
33
  ok: boolean;
@@ -70,6 +70,7 @@ const messages = {
70
70
  "onboarding.roleOther": "أخرى",
71
71
  "onboarding.roleOtherInputLabel": "صف دورك",
72
72
  "onboarding.skipForNow": "تخطي الآن",
73
+ "onboarding.useOwnApiKeys": "استخدام مفاتيح API الخاصة بي",
73
74
  "onboarding.saveRoleError": "تعذر حفظ دورك.",
74
75
  "onboarding.builderCreateAccount": "إنشاء حساب Builder.io",
75
76
  "onboarding.builderSignInWithAccount": "تسجيل الدخول بحساب Builder.io",
@@ -70,6 +70,7 @@ const messages = {
70
70
  "onboarding.roleOther": "Andere",
71
71
  "onboarding.roleOtherInputLabel": "Beschreibe deine Rolle",
72
72
  "onboarding.skipForNow": "Vorerst überspringen",
73
+ "onboarding.useOwnApiKeys": "Meine eigenen API-Schlüssel verwenden",
73
74
  "onboarding.saveRoleError": "Deine Rolle konnte nicht gespeichert werden.",
74
75
  "onboarding.builderCreateAccount": "Builder.io-Konto erstellen",
75
76
  "onboarding.builderSignInWithAccount": "Mit Builder.io-Konto anmelden",
@@ -70,6 +70,7 @@ declare const messages: {
70
70
  readonly "onboarding.roleOther": "Other";
71
71
  readonly "onboarding.roleOtherInputLabel": "Describe your role";
72
72
  readonly "onboarding.skipForNow": "Skip for now";
73
+ readonly "onboarding.useOwnApiKeys": "Use my own API keys";
73
74
  readonly "onboarding.saveRoleError": "Could not save your role.";
74
75
  readonly "onboarding.builderCreateAccount": "Create Builder.io account";
75
76
  readonly "onboarding.builderSignInWithAccount": "Sign in with Builder.io account";
@@ -70,6 +70,7 @@ const messages = {
70
70
  "onboarding.roleOther": "Other",
71
71
  "onboarding.roleOtherInputLabel": "Describe your role",
72
72
  "onboarding.skipForNow": "Skip for now",
73
+ "onboarding.useOwnApiKeys": "Use my own API keys",
73
74
  "onboarding.saveRoleError": "Could not save your role.",
74
75
  "onboarding.builderCreateAccount": "Create Builder.io account",
75
76
  "onboarding.builderSignInWithAccount": "Sign in with Builder.io account",
@@ -70,6 +70,7 @@ const messages = {
70
70
  "onboarding.roleOther": "Otro",
71
71
  "onboarding.roleOtherInputLabel": "Describe tu función",
72
72
  "onboarding.skipForNow": "Omitir por ahora",
73
+ "onboarding.useOwnApiKeys": "Usar mis propias claves de API",
73
74
  "onboarding.saveRoleError": "No se pudo guardar tu rol.",
74
75
  "onboarding.builderCreateAccount": "Crear cuenta de Builder.io",
75
76
  "onboarding.builderSignInWithAccount": "Iniciar sesión con una cuenta de Builder.io",
@@ -70,6 +70,7 @@ const messages = {
70
70
  "onboarding.roleOther": "Autre",
71
71
  "onboarding.roleOtherInputLabel": "Décrivez votre rôle",
72
72
  "onboarding.skipForNow": "Ignorer pour l’instant",
73
+ "onboarding.useOwnApiKeys": "Utiliser mes propres clés API",
73
74
  "onboarding.saveRoleError": "Impossible d’enregistrer votre rôle.",
74
75
  "onboarding.builderCreateAccount": "Créer un compte Builder.io",
75
76
  "onboarding.builderSignInWithAccount": "Se connecter avec un compte Builder.io",
@@ -70,6 +70,7 @@ const messages = {
70
70
  "onboarding.roleOther": "अन्य",
71
71
  "onboarding.roleOtherInputLabel": "अपनी भूमिका बताएं",
72
72
  "onboarding.skipForNow": "अभी छोड़ें",
73
+ "onboarding.useOwnApiKeys": "मेरी अपनी API कुंजियाँ इस्तेमाल करें",
73
74
  "onboarding.saveRoleError": "आपकी भूमिका सहेजी नहीं जा सकी।",
74
75
  "onboarding.builderCreateAccount": "Builder.io खाता बनाएँ",
75
76
  "onboarding.builderSignInWithAccount": "Builder.io खाते से साइन इन करें",
@@ -70,6 +70,7 @@ const messages = {
70
70
  "onboarding.roleOther": "その他",
71
71
  "onboarding.roleOtherInputLabel": "役割を入力してください",
72
72
  "onboarding.skipForNow": "今はスキップ",
73
+ "onboarding.useOwnApiKeys": "自分の API キーを使う",
73
74
  "onboarding.saveRoleError": "役割を保存できませんでした。",
74
75
  "onboarding.builderCreateAccount": "Builder.io アカウントを作成",
75
76
  "onboarding.builderSignInWithAccount": "Builder.io アカウントでサインイン",
@@ -70,6 +70,7 @@ const messages = {
70
70
  "onboarding.roleOther": "기타",
71
71
  "onboarding.roleOtherInputLabel": "역할을 입력해 주세요",
72
72
  "onboarding.skipForNow": "지금 건너뛰기",
73
+ "onboarding.useOwnApiKeys": "내 API 키 사용",
73
74
  "onboarding.saveRoleError": "역할을 저장하지 못했습니다.",
74
75
  "onboarding.builderCreateAccount": "Builder.io 계정 만들기",
75
76
  "onboarding.builderSignInWithAccount": "Builder.io 계정으로 로그인",
@@ -70,6 +70,7 @@ const messages = {
70
70
  "onboarding.roleOther": "Outro",
71
71
  "onboarding.roleOtherInputLabel": "Descreva sua função",
72
72
  "onboarding.skipForNow": "Pular por enquanto",
73
+ "onboarding.useOwnApiKeys": "Usar minhas próprias chaves de API",
73
74
  "onboarding.saveRoleError": "Não foi possível salvar sua função.",
74
75
  "onboarding.builderCreateAccount": "Criar conta do Builder.io",
75
76
  "onboarding.builderSignInWithAccount": "Entrar com uma conta do Builder.io",
@@ -70,6 +70,7 @@ const messages = {
70
70
  "onboarding.roleOther": "其他",
71
71
  "onboarding.roleOtherInputLabel": "描述你的角色",
72
72
  "onboarding.skipForNow": "暂时跳过",
73
+ "onboarding.useOwnApiKeys": "使用我自己的 API 密钥",
73
74
  "onboarding.saveRoleError": "无法保存你的角色。",
74
75
  "onboarding.builderCreateAccount": "创建 Builder.io 账户",
75
76
  "onboarding.builderSignInWithAccount": "使用 Builder.io 账户登录",
@@ -70,6 +70,7 @@ const messages = {
70
70
  "onboarding.roleOther": "其他",
71
71
  "onboarding.roleOtherInputLabel": "描述你的角色",
72
72
  "onboarding.skipForNow": "暫時略過",
73
+ "onboarding.useOwnApiKeys": "使用我自己的 API 金鑰",
73
74
  "onboarding.saveRoleError": "無法儲存你的角色。",
74
75
  "onboarding.builderCreateAccount": "建立 Builder.io 帳戶",
75
76
  "onboarding.builderSignInWithAccount": "使用 Builder.io 帳戶登入",
@@ -72,6 +72,7 @@ export declare const englishAgentChatMessages: {
72
72
  readonly "onboarding.roleOther": "Other";
73
73
  readonly "onboarding.roleOtherInputLabel": "Describe your role";
74
74
  readonly "onboarding.skipForNow": "Skip for now";
75
+ readonly "onboarding.useOwnApiKeys": "Use my own API keys";
75
76
  readonly "onboarding.saveRoleError": "Could not save your role.";
76
77
  readonly "onboarding.builderCreateAccount": "Create Builder.io account";
77
78
  readonly "onboarding.builderSignInWithAccount": "Sign in with Builder.io account";
@@ -62,6 +62,6 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
62
62
  summary?: undefined;
63
63
  spans?: undefined;
64
64
  id?: undefined;
65
- ok: boolean;
66
65
  error?: undefined;
66
+ ok: boolean;
67
67
  }>>;
@@ -48,8 +48,8 @@ export declare function handleUpdateResource(event: any): Promise<import("./stor
48
48
  }>;
49
49
  /** DELETE /_agent-native/resources/:id — delete a resource */
50
50
  export declare function handleDeleteResource(event: any): Promise<{
51
- error: string;
52
51
  ok?: undefined;
52
+ error: string;
53
53
  } | {
54
54
  error?: undefined;
55
55
  ok: boolean;
@@ -9,7 +9,7 @@ export declare function createAgentEngineOllamaModelsHandler(): import("h3").Eve
9
9
  ok?: undefined;
10
10
  models?: undefined;
11
11
  } | {
12
- error?: undefined;
13
12
  ok: boolean;
14
13
  models: string[];
14
+ error?: undefined;
15
15
  }>>;
@@ -419,8 +419,8 @@ export declare function createPublicRemoteAgentsHandler(discover?: PublicAgentDi
419
419
  error: string;
420
420
  agents?: undefined;
421
421
  } | {
422
- agents: Omit<import("./agent-discovery.js").DiscoveredAgent, "auth" | "kind">[];
423
422
  error?: undefined;
423
+ agents: Omit<import("./agent-discovery.js").DiscoveredAgent, "auth" | "kind">[];
424
424
  }>>;
425
425
  export declare function getBuilderConnectErrorDisposition(error: unknown, connectAttemptId: string | null): "correlated" | "legacy" | null;
426
426
  export declare function getBuilderConnectErrorKey(ownerEmail: string, connectAttemptId?: string | null): string;
@@ -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({
@@ -32,6 +32,7 @@ const messages = {
32
32
  pinChat: "تثبيت المحادثة",
33
33
  pinned: "المثبتة",
34
34
  recents: "الأخيرة",
35
+ retryPreviousRequest: "أعِد محاولة طلبي السابق الآن بعد توصيل مزود النموذج.",
35
36
  renameChat: "إعادة تسمية المحادثة",
36
37
  renameFailed: "فشلت إعادة التسمية",
37
38
  renameThread: "إعادة تسمية السلسلة",
@@ -34,6 +34,8 @@ const messages = {
34
34
  pinChat: "Chat anheften",
35
35
  pinned: "Angepinnt",
36
36
  recents: "Kürzlich",
37
+ retryPreviousRequest:
38
+ "Wiederhole meine vorherige Anfrage, jetzt wo der KI-Anbieter verbunden ist.",
37
39
  renameChat: "Chat umbenennen",
38
40
  renameFailed: "Umbenennen fehlgeschlagen",
39
41
  renameThread: "Thread umbenennen",
@@ -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",
@@ -34,6 +34,8 @@ const messages = {
34
34
  pinChat: "Fijar chat",
35
35
  pinned: "Fijados",
36
36
  recents: "Recientes",
37
+ retryPreviousRequest:
38
+ "Reintenta mi solicitud anterior ahora que el proveedor del modelo está conectado.",
37
39
  renameChat: "Renombrar chat",
38
40
  renameFailed: "No se pudo renombrar",
39
41
  renameThread: "Renombrar hilo",
@@ -34,6 +34,8 @@ const messages = {
34
34
  pinChat: "Épingler le chat",
35
35
  pinned: "Épinglés",
36
36
  recents: "Récents",
37
+ retryPreviousRequest:
38
+ "Réessaie ma demande précédente maintenant que le fournisseur du modèle est connecté.",
37
39
  renameChat: "Renommer le chat",
38
40
  renameFailed: "Échec du renommage",
39
41
  renameThread: "Renommer le fil",
@@ -32,6 +32,8 @@ const messages = {
32
32
  pinChat: "चैट पिन करें",
33
33
  pinned: "पिन की गई",
34
34
  recents: "हाल की",
35
+ retryPreviousRequest:
36
+ "मेरा पिछला अनुरोध फिर से आज़माएँ, अब जबकि मॉडल प्रदाता कनेक्ट हो गया है।",
35
37
  renameChat: "चैट का नाम बदलें",
36
38
  renameFailed: "नाम बदलना विफल",
37
39
  renameThread: "थ्रेड का नाम बदलें",