@agent-native/toolkit 0.207.0-nightly-20261011153008 → 0.207.0

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 (118) hide show
  1. package/agent-native.eject.json +1 -0
  2. package/dist/app/auth/AuthPage.d.ts.map +1 -1
  3. package/dist/app/auth/AuthPage.js +24 -55
  4. package/dist/app/auth/AuthPage.js.map +1 -1
  5. package/dist/app/chat/chat/run-recovery.d.ts.map +1 -1
  6. package/dist/app/chat/chat/run-recovery.js +21 -5
  7. package/dist/app/chat/chat/run-recovery.js.map +1 -1
  8. package/dist/app/chat/chat-first/ChatFirstAgentActivityPanel.d.ts.map +1 -1
  9. package/dist/app/chat/chat-first/ChatFirstAgentActivityPanel.js +3 -2
  10. package/dist/app/chat/chat-first/ChatFirstAgentActivityPanel.js.map +1 -1
  11. package/dist/app/i18n/catalogs/ar-SA.d.ts.map +1 -1
  12. package/dist/app/i18n/catalogs/ar-SA.js +10 -2
  13. package/dist/app/i18n/catalogs/ar-SA.js.map +1 -1
  14. package/dist/app/i18n/catalogs/de-DE.d.ts.map +1 -1
  15. package/dist/app/i18n/catalogs/de-DE.js +10 -2
  16. package/dist/app/i18n/catalogs/de-DE.js.map +1 -1
  17. package/dist/app/i18n/catalogs/en-US.d.ts +10 -2
  18. package/dist/app/i18n/catalogs/en-US.d.ts.map +1 -1
  19. package/dist/app/i18n/catalogs/en-US.js +10 -2
  20. package/dist/app/i18n/catalogs/en-US.js.map +1 -1
  21. package/dist/app/i18n/catalogs/es-ES.d.ts.map +1 -1
  22. package/dist/app/i18n/catalogs/es-ES.js +10 -2
  23. package/dist/app/i18n/catalogs/es-ES.js.map +1 -1
  24. package/dist/app/i18n/catalogs/fr-FR.d.ts.map +1 -1
  25. package/dist/app/i18n/catalogs/fr-FR.js +10 -2
  26. package/dist/app/i18n/catalogs/fr-FR.js.map +1 -1
  27. package/dist/app/i18n/catalogs/hi-IN.d.ts.map +1 -1
  28. package/dist/app/i18n/catalogs/hi-IN.js +10 -2
  29. package/dist/app/i18n/catalogs/hi-IN.js.map +1 -1
  30. package/dist/app/i18n/catalogs/ja-JP.d.ts.map +1 -1
  31. package/dist/app/i18n/catalogs/ja-JP.js +10 -2
  32. package/dist/app/i18n/catalogs/ja-JP.js.map +1 -1
  33. package/dist/app/i18n/catalogs/ko-KR.d.ts.map +1 -1
  34. package/dist/app/i18n/catalogs/ko-KR.js +10 -2
  35. package/dist/app/i18n/catalogs/ko-KR.js.map +1 -1
  36. package/dist/app/i18n/catalogs/pt-BR.d.ts.map +1 -1
  37. package/dist/app/i18n/catalogs/pt-BR.js +10 -2
  38. package/dist/app/i18n/catalogs/pt-BR.js.map +1 -1
  39. package/dist/app/i18n/catalogs/zh-CN.d.ts.map +1 -1
  40. package/dist/app/i18n/catalogs/zh-CN.js +10 -2
  41. package/dist/app/i18n/catalogs/zh-CN.js.map +1 -1
  42. package/dist/app/i18n/catalogs/zh-TW.d.ts.map +1 -1
  43. package/dist/app/i18n/catalogs/zh-TW.js +10 -2
  44. package/dist/app/i18n/catalogs/zh-TW.js.map +1 -1
  45. package/dist/app/onboarding/OnboardingBanner.d.ts.map +1 -1
  46. package/dist/app/onboarding/OnboardingBanner.js +37 -3
  47. package/dist/app/onboarding/OnboardingBanner.js.map +1 -1
  48. package/dist/app/onboarding/OnboardingPanel.d.ts.map +1 -1
  49. package/dist/app/onboarding/OnboardingPanel.js +49 -11
  50. package/dist/app/onboarding/OnboardingPanel.js.map +1 -1
  51. package/dist/app/progress/RunsTray.d.ts.map +1 -1
  52. package/dist/app/progress/RunsTray.js +136 -17
  53. package/dist/app/progress/RunsTray.js.map +1 -1
  54. package/dist/app/settings/BuilderConnectPopover.d.ts +1 -0
  55. package/dist/app/settings/BuilderConnectPopover.d.ts.map +1 -1
  56. package/dist/app/settings/BuilderConnectPopover.js +21 -5
  57. package/dist/app/settings/BuilderConnectPopover.js.map +1 -1
  58. package/dist/app/settings/shell/pages/audit.d.ts.map +1 -1
  59. package/dist/app/settings/shell/pages/audit.js +3 -3
  60. package/dist/app/settings/shell/pages/audit.js.map +1 -1
  61. package/dist/app/settings/useBuilderStatus.d.ts +1 -0
  62. package/dist/app/settings/useBuilderStatus.d.ts.map +1 -1
  63. package/dist/app/settings/useBuilderStatus.js +1 -0
  64. package/dist/app/settings/useBuilderStatus.js.map +1 -1
  65. package/dist/app/shared/AgentMark.d.ts +6 -0
  66. package/dist/app/shared/AgentMark.d.ts.map +1 -0
  67. package/dist/app/shared/AgentMark.js +5 -0
  68. package/dist/app/shared/AgentMark.js.map +1 -0
  69. package/dist/app/shared/index.d.ts +1 -0
  70. package/dist/app/shared/index.d.ts.map +1 -1
  71. package/dist/app/shared/index.js +1 -0
  72. package/dist/app/shared/index.js.map +1 -1
  73. package/dist/app/sharing/ShareButton.d.ts +1 -0
  74. package/dist/app/sharing/ShareButton.d.ts.map +1 -1
  75. package/dist/app/sharing/ShareButton.js +2 -2
  76. package/dist/app/sharing/ShareButton.js.map +1 -1
  77. package/dist/app/styles/agent-native.css +1 -0
  78. package/dist/app-shell/sidebar.d.ts.map +1 -1
  79. package/dist/app-shell/sidebar.js +3 -3
  80. package/dist/app-shell/sidebar.js.map +1 -1
  81. package/dist/sharing/ShareControls.d.ts +1 -0
  82. package/dist/sharing/ShareControls.d.ts.map +1 -1
  83. package/dist/sharing/ShareControls.js +5 -2
  84. package/dist/sharing/ShareControls.js.map +1 -1
  85. package/package.json +4 -4
  86. package/src/app/auth/AuthPage.attribution.spec.tsx +268 -0
  87. package/src/app/auth/AuthPage.tsx +27 -54
  88. package/src/app/chat/chat/run-recovery.spec.tsx +76 -0
  89. package/src/app/chat/chat/run-recovery.tsx +101 -23
  90. package/src/app/chat/chat-first/ChatFirstAgentActivityPanel.tsx +11 -5
  91. package/src/app/i18n/catalogs/ar-SA.ts +17 -2
  92. package/src/app/i18n/catalogs/de-DE.ts +18 -2
  93. package/src/app/i18n/catalogs/en-US.ts +17 -2
  94. package/src/app/i18n/catalogs/es-ES.ts +17 -2
  95. package/src/app/i18n/catalogs/fr-FR.ts +18 -2
  96. package/src/app/i18n/catalogs/hi-IN.ts +17 -2
  97. package/src/app/i18n/catalogs/ja-JP.ts +17 -2
  98. package/src/app/i18n/catalogs/ko-KR.ts +17 -2
  99. package/src/app/i18n/catalogs/pt-BR.ts +17 -2
  100. package/src/app/i18n/catalogs/zh-CN.ts +16 -2
  101. package/src/app/i18n/catalogs/zh-TW.ts +16 -2
  102. package/src/app/onboarding/OnboardingBanner.tsx +70 -5
  103. package/src/app/onboarding/OnboardingPanel.save-scope.spec.tsx +143 -2
  104. package/src/app/onboarding/OnboardingPanel.tsx +72 -5
  105. package/src/app/progress/RunsTray.spec.tsx +577 -0
  106. package/src/app/progress/RunsTray.tsx +253 -51
  107. package/src/app/settings/BuilderConnectPopover.spec.tsx +39 -1
  108. package/src/app/settings/BuilderConnectPopover.tsx +27 -4
  109. package/src/app/settings/shell/pages/audit.tsx +7 -3
  110. package/src/app/settings/useBuilderStatus.spec.tsx +21 -1
  111. package/src/app/settings/useBuilderStatus.ts +2 -0
  112. package/src/app/shared/AgentMark.tsx +34 -0
  113. package/src/app/shared/index.ts +1 -0
  114. package/src/app/sharing/ShareButton.tsx +3 -0
  115. package/src/app/styles/agent-native.css +1 -0
  116. package/src/app-shell/sidebar.tsx +29 -21
  117. package/src/sharing/ShareControls.spec.tsx +36 -0
  118. package/src/sharing/ShareControls.tsx +17 -2
@@ -146,8 +146,16 @@ const messages: ToolkitAgentChatTranslation = {
146
146
  "onboarding.builderActivateTitle": "啟用免費額度",
147
147
  "onboarding.builderAccountExistsTitle": "您已有 Builder.io 帳戶",
148
148
  "onboarding.builderAccountExistsDescription": "登入以使用您的帳戶。",
149
+ "onboarding.builderActivationChecking": "正在確認是否可以建立新帳戶。",
150
+ "onboarding.builderActivationUnavailable":
151
+ "此應用程式未啟用新帳戶建立功能。你仍可連結現有帳戶。",
152
+ "onboarding.builderActivationUnavailableInMode":
153
+ "此模式無法啟用新帳戶。你仍可連結現有帳戶。",
154
+ "onboarding.builderActivationCheckFailed":
155
+ "無法確認此應用程式是否可以建立新帳戶。",
156
+
149
157
  "onboarding.builderActivationDescription":
150
- "按一下即可建立或連接 Builder.io 帳戶,取得免費額度。",
158
+ "建立新帳戶以啟用免費點數,或使用現有帳戶繼續。",
151
159
  "onboarding.builderOrgActivationDescription":
152
160
  "我們會一鍵建立您的 Builder.io 帳戶,讓您的組織可以使用。",
153
161
  "onboarding.builderCreateAndActivate": "建立並啟用",
@@ -155,7 +163,7 @@ const messages: ToolkitAgentChatTranslation = {
155
163
  "onboarding.builderTerms": "服務條款",
156
164
  "onboarding.builderPrivacy": "隱私權政策",
157
165
  "onboarding.builderConsentAnd": "和",
158
- "onboarding.builderExistingAccount": "使用 Builder.io",
166
+ "onboarding.builderExistingAccount": "我有 Builder.io 帳戶",
159
167
  "onboarding.builderActivating": "正在啟用 Builder.io 免費額度",
160
168
  "onboarding.builderConnecting": "正在設定 Builder.io 免費額度",
161
169
  "onboarding.builderProvisioningDescription":
@@ -1161,6 +1169,12 @@ const messages: ToolkitAgentChatTranslation = {
1161
1169
  "selection.attached": "已附加所選內容的 {{formattedCount}} 個字元",
1162
1170
  "selection.attached_other": "已附加所選內容的 {{formattedCount}} 個字元",
1163
1171
  "selection.clear": "清除所選內容的上下文",
1172
+ "setup.addKeyInSettings": "在設定中新增金鑰",
1173
+ "setup.addKeyInSettingsDescription": "供你的個人帳戶或組織使用。",
1174
+ "setup.setEnvironmentVariable": "設定環境變數",
1175
+ "setup.setEnvironmentVariableDescription":
1176
+ "此應用程式的所有使用者共用一個供應商金鑰。",
1177
+
1164
1178
  "setup.addOwnKeys": "加入您自己的金鑰",
1165
1179
  "setup.builderCredits":
1166
1180
  "Builder.io 提供免費額度,您也可以使用自己的 API 金鑰。",
@@ -1,6 +1,12 @@
1
+ import { useT } from "@agent-native/core/client/i18n";
1
2
  import { useOnboarding } from "@agent-native/core/client/onboarding/use-onboarding";
2
- import { IconChecklist, IconChevronRight } from "@tabler/icons-react";
3
- import React from "react";
3
+ import { Button } from "@agent-native/toolkit/ui/button";
4
+ import {
5
+ IconChecklist,
6
+ IconChevronRight,
7
+ IconLoader2,
8
+ } from "@tabler/icons-react";
9
+ import React, { useState } from "react";
4
10
 
5
11
  interface OnboardingBannerProps {
6
12
  onContinue?: () => void;
@@ -11,9 +17,55 @@ export function OnboardingBanner({
11
17
  onContinue,
12
18
  className,
13
19
  }: OnboardingBannerProps) {
14
- const { loading, totalCount, completeCount, allComplete, dismissed } =
15
- useOnboarding();
16
- if (loading || totalCount === 0 || allComplete || dismissed) return null;
20
+ const {
21
+ loading,
22
+ totalCount,
23
+ completeCount,
24
+ allComplete,
25
+ dismissed,
26
+ error,
27
+ summaryKnown,
28
+ refresh,
29
+ } = useOnboarding();
30
+ const t = useT();
31
+ const [retrying, setRetrying] = useState(false);
32
+
33
+ if (
34
+ loading ||
35
+ (summaryKnown && (dismissed || (totalCount > 0 && allComplete)))
36
+ ) {
37
+ return null;
38
+ }
39
+ if (error && (!summaryKnown || totalCount > 0)) {
40
+ const retry = async () => {
41
+ setRetrying(true);
42
+ try {
43
+ await refresh();
44
+ } finally {
45
+ setRetrying(false);
46
+ }
47
+ };
48
+
49
+ return (
50
+ <div role="alert" className={className} style={styles.error}>
51
+ <span>{t("agentChat.common.chunkLoadFailed")}</span>
52
+ <Button
53
+ type="button"
54
+ variant="outline"
55
+ size="xs"
56
+ data-testid="onboarding-summary-retry"
57
+ disabled={retrying}
58
+ onClick={() => void retry()}
59
+ >
60
+ {retrying ? (
61
+ <IconLoader2 className="animate-spin" aria-hidden />
62
+ ) : null}
63
+ {t("agentChat.common.retry")}
64
+ </Button>
65
+ </div>
66
+ );
67
+ }
68
+ if (!summaryKnown || totalCount === 0) return null;
17
69
 
18
70
  return (
19
71
  <button
@@ -38,6 +90,19 @@ export function OnboardingBanner({
38
90
  }
39
91
 
40
92
  const styles: Record<string, React.CSSProperties> = {
93
+ error: {
94
+ display: "flex",
95
+ flexWrap: "wrap",
96
+ alignItems: "center",
97
+ justifyContent: "space-between",
98
+ gap: 8,
99
+ width: "100%",
100
+ padding: "8px 12px",
101
+ borderBottom: "1px solid hsl(var(--border) / 0.7)",
102
+ background: "hsl(var(--muted) / 0.25)",
103
+ color: "hsl(var(--muted-foreground))",
104
+ fontSize: 12,
105
+ },
41
106
  root: {
42
107
  display: "flex",
43
108
  alignItems: "center",
@@ -8,15 +8,26 @@ import { createRoot, type Root } from "react-dom/client";
8
8
  import { afterEach, describe, expect, it, vi } from "vitest";
9
9
 
10
10
  let steps: OnboardingStepStatus[] = [];
11
+ let onboardingError: string | null = null;
12
+ let dismissed = false;
13
+ let summaryKnown = true;
14
+ let refresh = vi.fn(async () => {});
11
15
  vi.mock("@agent-native/core/client/onboarding/use-onboarding", () => ({
12
16
  createOnboardingCorrelationId: () => "test-onboarding-correlation-id",
13
17
  trackOnboardingEvent: vi.fn(),
14
18
  useOnboarding: () => ({
15
19
  steps,
16
20
  currentStepId: steps[0]?.id ?? null,
17
- dismissed: false,
21
+ completeCount: steps.filter((step) => step.complete).length,
22
+ totalCount: steps.length,
23
+ allComplete:
24
+ steps.length > 0 &&
25
+ steps.filter((step) => step.required).every((step) => step.complete),
26
+ dismissed,
27
+ summaryKnown,
18
28
  loading: false,
19
- refresh: async () => {},
29
+ error: onboardingError,
30
+ refresh,
20
31
  complete: vi.fn(),
21
32
  dismiss: vi.fn(),
22
33
  }),
@@ -28,6 +39,7 @@ vi.mock("@agent-native/core/client/use-dev-mode", () => ({
28
39
  useDevMode: () => ({ isDevMode: false }),
29
40
  }));
30
41
 
42
+ import { OnboardingBanner } from "./OnboardingBanner.js";
31
43
  import { OnboardingPanel } from "./OnboardingPanel.js";
32
44
 
33
45
  function json(body: unknown): Response {
@@ -69,9 +81,30 @@ afterEach(() => {
69
81
  container?.remove();
70
82
  root = null;
71
83
  container = null;
84
+ steps = [];
85
+ onboardingError = null;
86
+ dismissed = false;
87
+ summaryKnown = true;
88
+ refresh = vi.fn(async () => {});
72
89
  vi.unstubAllGlobals();
73
90
  });
74
91
 
92
+ async function renderOnboarding(child: React.ReactNode): Promise<void> {
93
+ container = document.createElement("div");
94
+ document.body.appendChild(container);
95
+ root = createRoot(container);
96
+ const queryClient = new QueryClient({
97
+ defaultOptions: { queries: { retry: false } },
98
+ });
99
+ await act(async () => {
100
+ root!.render(
101
+ <QueryClientProvider client={queryClient}>
102
+ <TooltipProvider>{child}</TooltipProvider>
103
+ </QueryClientProvider>,
104
+ );
105
+ });
106
+ }
107
+
75
108
  async function saveAs(
76
109
  role: "member" | "admin",
77
110
  saveTo?: "scoped-secrets",
@@ -156,4 +189,112 @@ describe("onboarding form save scope", () => {
156
189
  const [secretSave] = await saveAs("admin", "scoped-secrets");
157
190
  expect(secretSave.body.scope).toBe("workspace");
158
191
  });
192
+
193
+ it("shows retry only when the initial summary is unavailable", async () => {
194
+ steps = [formStep()];
195
+ onboardingError = "summary: 503";
196
+ summaryKnown = false;
197
+ refresh = vi.fn(async () => {});
198
+ await renderOnboarding(<OnboardingPanel />);
199
+
200
+ const retry = container?.querySelector<HTMLButtonElement>(
201
+ '[data-testid="onboarding-summary-retry"]',
202
+ );
203
+ expect(container?.querySelector('[role="alert"]')).not.toBeNull();
204
+ expect(container?.textContent).not.toContain("Example keys");
205
+ expect(retry).not.toBeNull();
206
+ await act(async () => retry?.click());
207
+ expect(refresh).toHaveBeenCalledOnce();
208
+ });
209
+
210
+ it("keeps known steps visible while showing a summary retry state", async () => {
211
+ steps = [formStep()];
212
+ onboardingError = "summary: 503";
213
+ await renderOnboarding(<OnboardingPanel />);
214
+
215
+ expect(container?.querySelector('[role="alert"]')).not.toBeNull();
216
+ expect(container?.textContent).toContain("Example keys");
217
+ expect(
218
+ container?.querySelector('[data-testid="onboarding-summary-retry"]'),
219
+ ).not.toBeNull();
220
+ });
221
+
222
+ it("shows a retry-only banner when the initial summary is unavailable", async () => {
223
+ steps = [formStep()];
224
+ onboardingError = "summary: 503";
225
+ summaryKnown = false;
226
+ refresh = vi.fn(async () => {});
227
+ await renderOnboarding(<OnboardingBanner />);
228
+
229
+ const retry = container?.querySelector<HTMLButtonElement>(
230
+ '[data-testid="onboarding-summary-retry"]',
231
+ );
232
+ expect(container?.querySelector('[role="alert"]')).not.toBeNull();
233
+ expect(container?.textContent).not.toContain("Example keys");
234
+ expect(container?.textContent).not.toContain("Continue");
235
+ expect(retry).not.toBeNull();
236
+ await act(async () => retry?.click());
237
+ expect(refresh).toHaveBeenCalledOnce();
238
+ });
239
+
240
+ it("shows a retry action on the banner for a known active summary", async () => {
241
+ steps = [formStep()];
242
+ onboardingError = "summary: 503";
243
+ summaryKnown = true;
244
+ refresh = vi.fn(async () => {});
245
+ await renderOnboarding(<OnboardingBanner />);
246
+
247
+ const retry = container?.querySelector<HTMLButtonElement>(
248
+ '[data-testid="onboarding-summary-retry"]',
249
+ );
250
+ expect(container?.querySelector('[role="alert"]')).not.toBeNull();
251
+ expect(retry).not.toBeNull();
252
+ await act(async () => retry?.click());
253
+ expect(refresh).toHaveBeenCalledOnce();
254
+ });
255
+
256
+ it("hides summary errors after onboarding is dismissed", async () => {
257
+ dismissed = true;
258
+ summaryKnown = true;
259
+ onboardingError = "summary: 503";
260
+
261
+ await renderOnboarding(
262
+ <>
263
+ <OnboardingBanner />
264
+ <OnboardingPanel />
265
+ </>,
266
+ );
267
+ expect(container?.querySelector('[role="alert"]')).toBeNull();
268
+ });
269
+
270
+ it("hides summary errors after all required steps are complete", async () => {
271
+ steps = [{ ...formStep(), complete: true }];
272
+ summaryKnown = true;
273
+ onboardingError = "summary: 503";
274
+
275
+ await renderOnboarding(
276
+ <>
277
+ <OnboardingBanner />
278
+ <OnboardingPanel />
279
+ </>,
280
+ );
281
+ expect(container?.querySelector('[role="alert"]')).toBeNull();
282
+ });
283
+
284
+ it("keeps the retry notice visible while the panel is collapsed", async () => {
285
+ steps = [formStep()];
286
+ summaryKnown = true;
287
+ onboardingError = "summary: 503";
288
+ await renderOnboarding(<OnboardingPanel />);
289
+
290
+ const collapse = container?.querySelector<HTMLButtonElement>(
291
+ '[aria-label="Collapse onboarding"]',
292
+ );
293
+ await act(async () => collapse?.click());
294
+
295
+ expect(container?.querySelector('[role="alert"]')).not.toBeNull();
296
+ expect(
297
+ container?.querySelector('[data-testid="onboarding-summary-retry"]'),
298
+ ).not.toBeNull();
299
+ });
159
300
  });
@@ -12,6 +12,7 @@ import type {
12
12
  OnboardingMethod,
13
13
  OnboardingStepStatus,
14
14
  } from "@agent-native/core/onboarding/types";
15
+ import { Button } from "@agent-native/toolkit/ui/button";
15
16
  import {
16
17
  Tooltip,
17
18
  TooltipContent,
@@ -56,10 +57,13 @@ export function OnboardingPanel({
56
57
  currentStepId: rawCurrentStepId,
57
58
  dismissed,
58
59
  loading,
60
+ error,
61
+ summaryKnown,
59
62
  refresh,
60
63
  complete,
61
64
  dismiss,
62
65
  } = onboarding;
66
+ const t = useT();
63
67
  const DEV_ONLY_STEP_IDS = new Set(["database", "auth"]);
64
68
  const steps = isDevMode
65
69
  ? rawSteps
@@ -75,6 +79,7 @@ export function OnboardingPanel({
75
79
  const checklistVisible =
76
80
  !loading && totalCount > 0 && (previewMode || (!dismissed && !allComplete));
77
81
  const [expanded, setExpanded] = useState(true);
82
+ const [retrying, setRetrying] = useState(false);
78
83
  const stepViewRef = useRef<{ key: string; id: string } | null>(null);
79
84
 
80
85
  useEffect(() => {
@@ -102,12 +107,58 @@ export function OnboardingPanel({
102
107
  });
103
108
  }, [checklistVisible, currentStepId, expanded, previewMode, steps]);
104
109
 
105
- if (loading || totalCount === 0) return null;
106
- if (!previewMode) {
107
- if (dismissed) return null;
108
- if (allComplete) return null;
109
- }
110
+ const handleRetry = async () => {
111
+ setRetrying(true);
112
+ try {
113
+ await refresh();
114
+ } finally {
115
+ setRetrying(false);
116
+ }
117
+ };
118
+ const errorNotice =
119
+ error &&
120
+ (previewMode ||
121
+ !summaryKnown ||
122
+ (totalCount > 0 && !dismissed && !allComplete)) ? (
123
+ <div role="alert" style={styles.errorNotice}>
124
+ <span>{t("agentChat.common.chunkLoadFailed")}</span>
125
+ <Button
126
+ type="button"
127
+ variant="outline"
128
+ size="xs"
129
+ data-testid="onboarding-summary-retry"
130
+ disabled={retrying}
131
+ onClick={() => void handleRetry()}
132
+ >
133
+ {retrying ? (
134
+ <IconLoader2 className="animate-spin" aria-hidden />
135
+ ) : null}
136
+ {t("agentChat.common.retry")}
137
+ </Button>
138
+ </div>
139
+ ) : null;
110
140
 
141
+ if (loading) return null;
142
+ if (!previewMode && !summaryKnown) {
143
+ if (!errorNotice) return null;
144
+ return (
145
+ <div className={className} style={styles.errorOnly}>
146
+ {errorNotice}
147
+ </div>
148
+ );
149
+ }
150
+ if (!previewMode && (dismissed || (totalCount > 0 && allComplete))) {
151
+ return null;
152
+ }
153
+ if (error && totalCount === 0) {
154
+ if (!errorNotice) return null;
155
+ return (
156
+ <div className={className} style={styles.errorOnly}>
157
+ {errorNotice}
158
+ </div>
159
+ );
160
+ }
161
+ if (totalCount === 0) return null;
111
162
  if (!expanded) {
112
163
  return (
113
164
  <div className={className} style={styles.compactBanner}>
@@ -139,6 +190,7 @@ export function OnboardingPanel({
139
190
  </TooltipTrigger>
140
191
  <TooltipContent>Expand setup</TooltipContent>
141
192
  </Tooltip>
193
+ {errorNotice}
142
194
  </div>
143
195
  );
144
196
  }
@@ -174,6 +226,8 @@ export function OnboardingPanel({
174
226
  </Tooltip>
175
227
  </div>
176
228
 
229
+ {errorNotice}
230
+
177
231
  <div style={styles.list}>
178
232
  {steps.map((step) => (
179
233
  <StepCard
@@ -853,6 +907,19 @@ function badgeStyle(
853
907
  }
854
908
 
855
909
  const styles: Record<string, React.CSSProperties> = {
910
+ errorOnly: {
911
+ borderBottom: "1px solid hsl(var(--border) / 0.7)",
912
+ background: "hsl(var(--muted) / 0.25)",
913
+ fontSize: 12,
914
+ },
915
+ errorNotice: {
916
+ display: "flex",
917
+ alignItems: "center",
918
+ justifyContent: "space-between",
919
+ gap: 8,
920
+ padding: "8px 12px",
921
+ color: "hsl(var(--muted-foreground))",
922
+ },
856
923
  root: {
857
924
  borderBottom: "1px solid hsl(var(--border) / 0.7)",
858
925
  background: "hsl(var(--muted) / 0.25)",