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

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 (63) 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/design/changelog/2026-09-26-builder-is-the-primary-first-run-setup.md +6 -0
  8. package/corpus/templates/slides/changelog/2026-09-26-builder-is-the-primary-first-run-setup.md +6 -0
  9. package/dist/client/agent-chat/index.d.ts +1 -1
  10. package/dist/client/agent-chat/index.js +1 -1
  11. package/dist/client/chat/agentkit-protocol.js +18 -1
  12. package/dist/client/chat/run-recovery.d.ts +1 -0
  13. package/dist/client/chat/run-recovery.js +1 -1
  14. package/dist/client/onboarding/FirstRunOnboarding.js +59 -22
  15. package/dist/collab/awareness.d.ts +2 -2
  16. package/dist/collab/routes.d.ts +1 -1
  17. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  18. package/dist/localization/core-messages/ar-SA.js +1 -0
  19. package/dist/localization/core-messages/de-DE.js +1 -0
  20. package/dist/localization/core-messages/en-US.d.ts +1 -0
  21. package/dist/localization/core-messages/en-US.js +1 -0
  22. package/dist/localization/core-messages/es-ES.js +1 -0
  23. package/dist/localization/core-messages/fr-FR.js +1 -0
  24. package/dist/localization/core-messages/hi-IN.js +1 -0
  25. package/dist/localization/core-messages/ja-JP.js +1 -0
  26. package/dist/localization/core-messages/ko-KR.js +1 -0
  27. package/dist/localization/core-messages/pt-BR.js +1 -0
  28. package/dist/localization/core-messages/zh-CN.js +1 -0
  29. package/dist/localization/core-messages/zh-TW.js +1 -0
  30. package/dist/localization/core-messages.d.ts +1 -0
  31. package/dist/notifications/routes.d.ts +3 -3
  32. package/dist/observability/routes.d.ts +1 -1
  33. package/dist/secrets/routes.d.ts +9 -9
  34. package/dist/server/agent-engine-ollama-models-route.d.ts +1 -1
  35. package/dist/server/transcribe-voice.d.ts +1 -1
  36. package/dist/sharing/actions/list-resource-shares.d.ts +1 -1
  37. package/dist/templates/chat/app/components/chat/ChatRouteContent.tsx +93 -0
  38. package/dist/templates/chat/app/i18n/ar-SA.ts +1 -0
  39. package/dist/templates/chat/app/i18n/de-DE.ts +2 -0
  40. package/dist/templates/chat/app/i18n/en-US.ts +2 -0
  41. package/dist/templates/chat/app/i18n/es-ES.ts +2 -0
  42. package/dist/templates/chat/app/i18n/fr-FR.ts +2 -0
  43. package/dist/templates/chat/app/i18n/hi-IN.ts +2 -0
  44. package/dist/templates/chat/app/i18n/ja-JP.ts +2 -0
  45. package/dist/templates/chat/app/i18n/ko-KR.ts +2 -0
  46. package/dist/templates/chat/app/i18n/pt-BR.ts +2 -0
  47. package/dist/templates/chat/app/i18n/zh-CN.ts +1 -0
  48. package/dist/templates/chat/app/i18n/zh-TW.ts +1 -0
  49. package/dist/templates/chat/changelog/2026-09-26-builder-setup-retry.md +6 -0
  50. package/package.json +1 -1
  51. package/src/templates/chat/app/components/chat/ChatRouteContent.tsx +93 -0
  52. package/src/templates/chat/app/i18n/ar-SA.ts +1 -0
  53. package/src/templates/chat/app/i18n/de-DE.ts +2 -0
  54. package/src/templates/chat/app/i18n/en-US.ts +2 -0
  55. package/src/templates/chat/app/i18n/es-ES.ts +2 -0
  56. package/src/templates/chat/app/i18n/fr-FR.ts +2 -0
  57. package/src/templates/chat/app/i18n/hi-IN.ts +2 -0
  58. package/src/templates/chat/app/i18n/ja-JP.ts +2 -0
  59. package/src/templates/chat/app/i18n/ko-KR.ts +2 -0
  60. package/src/templates/chat/app/i18n/pt-BR.ts +2 -0
  61. package/src/templates/chat/app/i18n/zh-CN.ts +1 -0
  62. package/src/templates/chat/app/i18n/zh-TW.ts +1 -0
  63. 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: 10200
@@ -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.
@@ -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.
@@ -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.
@@ -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);
@@ -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
@@ -62,11 +62,11 @@ export declare const postAwareness: import("h3").EventHandlerWithFetch<import("h
62
62
  error: string;
63
63
  states?: undefined;
64
64
  } | {
65
- error?: undefined;
66
65
  states: {
67
66
  clientId: number;
68
67
  state: string;
69
68
  }[];
69
+ error?: undefined;
70
70
  }>>;
71
71
  /**
72
72
  * GET /_agent-native/collab/:docId/users
@@ -77,9 +77,9 @@ export declare const getActiveUsers: import("h3").EventHandlerWithFetch<import("
77
77
  error: string;
78
78
  users?: undefined;
79
79
  } | {
80
- error?: undefined;
81
80
  users: {
82
81
  clientId: number;
83
82
  lastSeen: number;
84
83
  }[];
84
+ error?: undefined;
85
85
  }>>;
@@ -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;
@@ -44,9 +44,9 @@ declare const _default: import("../../action.js").ActionDefinition<{
44
44
  url: string;
45
45
  id: string;
46
46
  provider: string;
47
+ error?: undefined;
47
48
  configured?: undefined;
48
49
  connectPath?: undefined;
49
- error?: undefined;
50
50
  } | {
51
51
  url?: undefined;
52
52
  id?: undefined;
@@ -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 账户登录",