@agent-native/toolkit 0.201.1-nightly-20261005213104 → 0.201.1

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 (104) hide show
  1. package/agent-native.eject.json +1 -0
  2. package/dist/app/agentkit/react/components.d.ts.map +1 -1
  3. package/dist/app/agentkit/react/components.js +21 -13
  4. package/dist/app/agentkit/react/components.js.map +1 -1
  5. package/dist/app/agentkit/react/context.d.ts +15 -1
  6. package/dist/app/agentkit/react/context.d.ts.map +1 -1
  7. package/dist/app/agentkit/react/context.js +30 -4
  8. package/dist/app/agentkit/react/context.js.map +1 -1
  9. package/dist/app/agentkit/react/styles.css +11 -7
  10. package/dist/app/chat/AgentKitAssistantChat.d.ts.map +1 -1
  11. package/dist/app/chat/AgentKitAssistantChat.js +9 -4
  12. package/dist/app/chat/AgentKitAssistantChat.js.map +1 -1
  13. package/dist/app/chat/FileStorageSetupPopover.d.ts.map +1 -1
  14. package/dist/app/chat/FileStorageSetupPopover.js +3 -2
  15. package/dist/app/chat/FileStorageSetupPopover.js.map +1 -1
  16. package/dist/app/i18n/catalogs/ar-SA.d.ts.map +1 -1
  17. package/dist/app/i18n/catalogs/ar-SA.js +11 -5
  18. package/dist/app/i18n/catalogs/ar-SA.js.map +1 -1
  19. package/dist/app/i18n/catalogs/de-DE.d.ts.map +1 -1
  20. package/dist/app/i18n/catalogs/de-DE.js +11 -5
  21. package/dist/app/i18n/catalogs/de-DE.js.map +1 -1
  22. package/dist/app/i18n/catalogs/en-US.d.ts +11 -5
  23. package/dist/app/i18n/catalogs/en-US.d.ts.map +1 -1
  24. package/dist/app/i18n/catalogs/en-US.js +11 -5
  25. package/dist/app/i18n/catalogs/en-US.js.map +1 -1
  26. package/dist/app/i18n/catalogs/es-ES.d.ts.map +1 -1
  27. package/dist/app/i18n/catalogs/es-ES.js +11 -5
  28. package/dist/app/i18n/catalogs/es-ES.js.map +1 -1
  29. package/dist/app/i18n/catalogs/fr-FR.d.ts.map +1 -1
  30. package/dist/app/i18n/catalogs/fr-FR.js +11 -5
  31. package/dist/app/i18n/catalogs/fr-FR.js.map +1 -1
  32. package/dist/app/i18n/catalogs/hi-IN.d.ts.map +1 -1
  33. package/dist/app/i18n/catalogs/hi-IN.js +11 -5
  34. package/dist/app/i18n/catalogs/hi-IN.js.map +1 -1
  35. package/dist/app/i18n/catalogs/ja-JP.d.ts.map +1 -1
  36. package/dist/app/i18n/catalogs/ja-JP.js +11 -5
  37. package/dist/app/i18n/catalogs/ja-JP.js.map +1 -1
  38. package/dist/app/i18n/catalogs/ko-KR.d.ts.map +1 -1
  39. package/dist/app/i18n/catalogs/ko-KR.js +11 -5
  40. package/dist/app/i18n/catalogs/ko-KR.js.map +1 -1
  41. package/dist/app/i18n/catalogs/pt-BR.d.ts.map +1 -1
  42. package/dist/app/i18n/catalogs/pt-BR.js +11 -5
  43. package/dist/app/i18n/catalogs/pt-BR.js.map +1 -1
  44. package/dist/app/i18n/catalogs/zh-CN.d.ts.map +1 -1
  45. package/dist/app/i18n/catalogs/zh-CN.js +11 -5
  46. package/dist/app/i18n/catalogs/zh-CN.js.map +1 -1
  47. package/dist/app/i18n/catalogs/zh-TW.d.ts.map +1 -1
  48. package/dist/app/i18n/catalogs/zh-TW.js +11 -5
  49. package/dist/app/i18n/catalogs/zh-TW.js.map +1 -1
  50. package/dist/app/onboarding/BuilderIncludedServices.d.ts +23 -0
  51. package/dist/app/onboarding/BuilderIncludedServices.d.ts.map +1 -0
  52. package/dist/app/onboarding/BuilderIncludedServices.js +67 -0
  53. package/dist/app/onboarding/BuilderIncludedServices.js.map +1 -0
  54. package/dist/app/onboarding/FirstRunOnboarding.d.ts.map +1 -1
  55. package/dist/app/onboarding/FirstRunOnboarding.js +10 -29
  56. package/dist/app/onboarding/FirstRunOnboarding.js.map +1 -1
  57. package/dist/app/settings/BuilderConnectPopover.d.ts +1 -2
  58. package/dist/app/settings/BuilderConnectPopover.d.ts.map +1 -1
  59. package/dist/app/settings/BuilderConnectPopover.js +35 -21
  60. package/dist/app/settings/BuilderConnectPopover.js.map +1 -1
  61. package/dist/app/settings/deferred-builder-connect-popover.d.ts.map +1 -1
  62. package/dist/app/settings/deferred-builder-connect-popover.js +28 -1
  63. package/dist/app/settings/deferred-builder-connect-popover.js.map +1 -1
  64. package/dist/app/settings/useBuilderStatus.d.ts.map +1 -1
  65. package/dist/app/settings/useBuilderStatus.js +8 -1
  66. package/dist/app/settings/useBuilderStatus.js.map +1 -1
  67. package/dist/app/styles/tokens/agent-kit.css +23 -11
  68. package/dist/composer/MessageQueueDrawer.d.ts +5 -0
  69. package/dist/composer/MessageQueueDrawer.d.ts.map +1 -1
  70. package/dist/composer/MessageQueueDrawer.js +11 -5
  71. package/dist/composer/MessageQueueDrawer.js.map +1 -1
  72. package/package.json +5 -4
  73. package/src/app/agentkit/react/components.interaction.spec.tsx +13 -5
  74. package/src/app/agentkit/react/components.tsx +24 -14
  75. package/src/app/agentkit/react/context.tsx +53 -6
  76. package/src/app/agentkit/react/styles.css +11 -7
  77. package/src/app/chat/AgentKitAssistantChat.spec.tsx +35 -16
  78. package/src/app/chat/AgentKitAssistantChat.tsx +13 -4
  79. package/src/app/chat/FileStorageSetupPopover.spec.tsx +129 -0
  80. package/src/app/chat/FileStorageSetupPopover.tsx +10 -3
  81. package/src/app/i18n/catalogs/ar-SA.ts +14 -5
  82. package/src/app/i18n/catalogs/de-DE.ts +15 -5
  83. package/src/app/i18n/catalogs/en-US.ts +14 -5
  84. package/src/app/i18n/catalogs/es-ES.ts +14 -5
  85. package/src/app/i18n/catalogs/fr-FR.ts +15 -5
  86. package/src/app/i18n/catalogs/hi-IN.ts +14 -5
  87. package/src/app/i18n/catalogs/ja-JP.ts +14 -5
  88. package/src/app/i18n/catalogs/ko-KR.ts +14 -5
  89. package/src/app/i18n/catalogs/pt-BR.ts +15 -5
  90. package/src/app/i18n/catalogs/zh-CN.ts +13 -5
  91. package/src/app/i18n/catalogs/zh-TW.ts +13 -5
  92. package/src/app/onboarding/BuilderIncludedServices.tsx +263 -0
  93. package/src/app/onboarding/FirstRunOnboarding.spec.tsx +23 -8
  94. package/src/app/onboarding/FirstRunOnboarding.tsx +22 -112
  95. package/src/app/settings/BuilderConnectPopover.spec.tsx +175 -6
  96. package/src/app/settings/BuilderConnectPopover.tsx +87 -67
  97. package/src/app/settings/deferred-builder-connect-popover.tsx +46 -0
  98. package/src/app/settings/model/ModelSettingsPage.spec.tsx +8 -24
  99. package/src/app/settings/useBuilderStatus.spec.tsx +5 -0
  100. package/src/app/settings/useBuilderStatus.ts +8 -0
  101. package/src/app/styles/agent-native.spec.ts +5 -8
  102. package/src/app/styles/tokens/agent-kit.css +23 -11
  103. package/src/composer/MessageQueueDrawer.spec.tsx +20 -7
  104. package/src/composer/MessageQueueDrawer.tsx +47 -21
@@ -216,9 +216,16 @@ export interface AgentKitLabels {
216
216
  composerLabel: string;
217
217
  composerPlaceholder: string;
218
218
  queue: string;
219
+ /** @deprecated Use queueSendNow. */
219
220
  queueSteer: string;
221
+ /** @deprecated Use queueSendNowHint. */
220
222
  queueSteerHint: string;
223
+ /** @deprecated Use queueSendNext. */
221
224
  queueMoveToTop: string;
225
+ queueSendNow?: string;
226
+ queueSendNowHint?: string;
227
+ queueSendNext?: string;
228
+ queueSendNextHint?: string;
222
229
  queueRemove: string;
223
230
  queueMore: string;
224
231
  suggestions: string;
@@ -305,9 +312,13 @@ export const defaultAgentKitLabels: AgentKitLabels = {
305
312
  composerLabel: "Message agent",
306
313
  composerPlaceholder: "Ask the agent to explore, build, or explain…",
307
314
  queue: "Queued messages",
308
- queueSteer: "Steer",
309
- queueSteerHint: "Send this message to the active run",
310
- queueMoveToTop: "Move to top",
315
+ queueSteer: "Send now",
316
+ queueSteerHint: "Stops the current response, then sends this message.",
317
+ queueMoveToTop: "Send next",
318
+ queueSendNow: "Send now",
319
+ queueSendNowHint: "Stops the current response, then sends this message.",
320
+ queueSendNext: "Send next",
321
+ queueSendNextHint: "Send after the current response finishes",
311
322
  queueRemove: "Remove queued message",
312
323
  queueMore: "More actions",
313
324
  suggestions: "Suggested next actions",
@@ -399,12 +410,19 @@ export interface AgentKitProviderProps {
399
410
  children: ReactNode;
400
411
  }
401
412
 
413
+ interface ResolvedAgentKitLabels extends AgentKitLabels {
414
+ queueSendNow: string;
415
+ queueSendNowHint: string;
416
+ queueSendNext: string;
417
+ queueSendNextHint: string;
418
+ }
419
+
402
420
  export interface AgentKitContextValue {
403
421
  controller: AgentKitController;
404
422
  threadId: ThreadId;
405
423
  slots: AgentKitSlots;
406
424
  registry: AgentKitRegistry;
407
- labels: AgentKitLabels;
425
+ labels: ResolvedAgentKitLabels;
408
426
  onOpenObject?: (object: AgentObjectReference) => void;
409
427
  onThreadForked?: (thread: AgentThread) => void;
410
428
  branchNavigation?: AgentKitBranchNavigation;
@@ -447,8 +465,37 @@ export function AgentKitProvider({
447
465
  const requestComposerFocus = useCallback((targetThreadId: ThreadId) => {
448
466
  composerFocusTargets.current.get(targetThreadId)?.();
449
467
  }, []);
450
- const mergedLabels = useMemo(
451
- () => ({ ...defaultAgentKitLabels, ...labels }),
468
+ const mergedLabels = useMemo<ResolvedAgentKitLabels>(
469
+ () => ({
470
+ ...defaultAgentKitLabels,
471
+ ...labels,
472
+ queueSteer:
473
+ labels?.queueSteer ??
474
+ labels?.queueSendNow ??
475
+ defaultAgentKitLabels.queueSteer,
476
+ queueSteerHint:
477
+ labels?.queueSteerHint ??
478
+ labels?.queueSendNowHint ??
479
+ defaultAgentKitLabels.queueSteerHint,
480
+ queueMoveToTop:
481
+ labels?.queueMoveToTop ??
482
+ labels?.queueSendNext ??
483
+ defaultAgentKitLabels.queueMoveToTop,
484
+ queueSendNow:
485
+ labels?.queueSendNow ??
486
+ labels?.queueSteer ??
487
+ defaultAgentKitLabels.queueSendNow!,
488
+ queueSendNowHint:
489
+ labels?.queueSendNowHint ??
490
+ labels?.queueSteerHint ??
491
+ defaultAgentKitLabels.queueSendNowHint!,
492
+ queueSendNext:
493
+ labels?.queueSendNext ??
494
+ labels?.queueMoveToTop ??
495
+ defaultAgentKitLabels.queueSendNext!,
496
+ queueSendNextHint:
497
+ labels?.queueSendNextHint ?? defaultAgentKitLabels.queueSendNextHint!,
498
+ }),
452
499
  [labels],
453
500
  );
454
501
  const value = useMemo(
@@ -107,13 +107,6 @@
107
107
  border-color: var(--agentkit-composer-focus-border) !important;
108
108
  }
109
109
 
110
- :is(:root.dark, :root[data-theme="dark"], .dark)
111
- .agentkit-composer[data-agent-composer-slot="root"],
112
- :is(:root.dark, :root[data-theme="dark"], .dark)
113
- .agentkit-composer[data-agent-composer-slot="root"]:focus-within {
114
- border-color: transparent !important;
115
- }
116
-
117
110
  .agentkit-composer [data-agent-composer-slot="editor-wrap"] {
118
111
  padding: 0.75rem 0.875rem 0.25rem;
119
112
  }
@@ -272,6 +265,13 @@
272
265
  list-style: none;
273
266
  }
274
267
 
268
+ .agentkit-composer-stack [data-agent-message-queue-variant="recessed"] ul {
269
+ max-block-size: none;
270
+ gap: 0;
271
+ padding: 0;
272
+ overflow-y: hidden;
273
+ }
274
+
275
275
  .agentkit-composer-stack [data-agent-message-queue="true"] li {
276
276
  display: flex;
277
277
  min-block-size: 2.25rem;
@@ -284,6 +284,10 @@
284
284
  line-height: 1rem;
285
285
  }
286
286
 
287
+ .agentkit-composer-stack [data-agent-message-queue-variant="recessed"] li {
288
+ padding-block: 0.125rem;
289
+ }
290
+
287
291
  .agentkit-composer-stack [data-agent-message-queue="true"] li > svg {
288
292
  inline-size: 0.875rem;
289
293
  block-size: 0.875rem;
@@ -618,6 +618,7 @@ vi.mock("./chat/agent-approval-card.js", async () => {
618
618
  import {
619
619
  AGENT_CHAT_SUBMIT_RESULT_EVENT,
620
620
  appendAgentChatContextToMessage,
621
+ createAgentNativeAgentKitTransport,
621
622
  } from "@agent-native/core/client/agent-chat";
622
623
  import {
623
624
  deleteClientAppState,
@@ -2613,6 +2614,35 @@ describe("AgentKitAssistantChat host behavior", () => {
2613
2614
  });
2614
2615
  });
2615
2616
 
2617
+ it("localizes unsupported upload errors instead of exposing the HTTP status", async () => {
2618
+ const fetch = vi
2619
+ .spyOn(globalThis, "fetch")
2620
+ .mockResolvedValue(
2621
+ Response.json(
2622
+ { error: "Unsupported file type: application/pdf" },
2623
+ { status: 415 },
2624
+ ),
2625
+ );
2626
+ await mount(baseProps());
2627
+
2628
+ try {
2629
+ await expect(
2630
+ chatMocks.rootProps.clientOptions.upload(
2631
+ { uploadId: "upload-1", method: "POST", url: "/uploads" },
2632
+ {
2633
+ name: "reference.pdf",
2634
+ mediaType: "application/pdf",
2635
+ size: 4,
2636
+ body: new Blob(["data"], { type: "application/pdf" }),
2637
+ },
2638
+ ),
2639
+ ).rejects.toThrow("agentChat.composer.unsupportedFileType");
2640
+ expect(fetch).toHaveBeenCalledOnce();
2641
+ } finally {
2642
+ fetch.mockRestore();
2643
+ }
2644
+ });
2645
+
2616
2646
  it("sends without waiting for pending-selection cleanup", async () => {
2617
2647
  chatMocks.appState.set("pending-selection-context", {
2618
2648
  text: "Selected text",
@@ -3648,7 +3678,10 @@ describe("AgentKitAssistantChat host behavior", () => {
3648
3678
  collapseMessage: "agentChat.common.collapse",
3649
3679
  messageUnavailable: "agentChat.message.unavailable",
3650
3680
  navigationUnavailable: "agentChat.message.navigationUnavailable",
3651
- queueMoveToTop: "agentChat.queue.moveToTop",
3681
+ queueSendNow: "agentChat.queue.sendNow",
3682
+ queueSendNowHint: "agentChat.queue.sendNowHint",
3683
+ queueSendNext: "agentChat.queue.sendNext",
3684
+ queueSendNextHint: "agentChat.queue.sendNextHint",
3652
3685
  previewAttachment: "Preview {{name}}",
3653
3686
  imagePreview: "agentChat.composer.imagePreview",
3654
3687
  closePreview: "agentChat.composer.closePreview",
@@ -3920,13 +3953,7 @@ describe("AgentKitAssistantChat host behavior", () => {
3920
3953
  });
3921
3954
 
3922
3955
  it("routes the built-in transport 404 through AgentKitRoot to the not-found fallback", async () => {
3923
- const { createAgentNativeAgentKitTransport } =
3924
- await import("@agent-native/core/client/agent-chat");
3925
- let resolveNotFound!: (response: Response) => void;
3926
- const notFoundResponse = new Promise<Response>((resolve) => {
3927
- resolveNotFound = resolve;
3928
- });
3929
- const fetch = vi.fn(async () => notFoundResponse);
3956
+ const fetch = vi.fn(async () => new Response(null, { status: 404 }));
3930
3957
  const onThreadRestoreNotFound = vi.fn();
3931
3958
  const runtime = {
3932
3959
  id: "restore-test",
@@ -3949,20 +3976,12 @@ describe("AgentKitAssistantChat host behavior", () => {
3949
3976
  );
3950
3977
  await flush();
3951
3978
  expect(fetch).toHaveBeenCalledOnce();
3952
- expect(container.querySelector('[aria-busy="true"]')).not.toBeNull();
3953
-
3954
- await act(async () => {
3955
- resolveNotFound(new Response(null, { status: 404 }));
3956
- });
3957
- await flush();
3958
3979
 
3959
3980
  expect(onThreadRestoreNotFound).toHaveBeenCalledOnce();
3960
3981
  expect(container.textContent).toContain("agentChat.message.threadNotFound");
3961
3982
  });
3962
3983
 
3963
3984
  it("hands a recent snapshot across surfaces while thread persistence lags", async () => {
3964
- const { createAgentNativeAgentKitTransport } =
3965
- await import("@agent-native/core/client/agent-chat");
3966
3985
  const threadId = "surface-handoff-thread";
3967
3986
  const browserTabId = "surface-handoff-tab";
3968
3987
  const savedSnapshots = vi.fn();
@@ -609,6 +609,8 @@ export const AgentKitAssistantChat = forwardRef<
609
609
  );
610
610
  }
611
611
  const t = useT();
612
+ const translatorRef = useRef(t);
613
+ translatorRef.current = t;
612
614
  const { formatDate } = useFormatters();
613
615
  const threadId = props.threadId ?? props.tabId;
614
616
  if (!threadId) {
@@ -738,9 +740,10 @@ export const AgentKitAssistantChat = forwardRef<
738
740
  composerLabel: t("agentChat.composer.messageAgent"),
739
741
  composerPlaceholder: t("agentChat.composer.messageAgent"),
740
742
  queue: t("agentChat.queue.label"),
741
- queueSteer: t("agentChat.queue.steer"),
742
- queueSteerHint: t("agentChat.queue.steerHint"),
743
- queueMoveToTop: t("agentChat.queue.moveToTop"),
743
+ queueSendNow: t("agentChat.queue.sendNow"),
744
+ queueSendNowHint: t("agentChat.queue.sendNowHint"),
745
+ queueSendNext: t("agentChat.queue.sendNext"),
746
+ queueSendNextHint: t("agentChat.queue.sendNextHint"),
744
747
  queueRemove: t("agentChat.queue.remove"),
745
748
  queueMore: t("agentChat.queue.moreActions"),
746
749
  suggestions: t("agentChat.composer.suggestedPrompts"),
@@ -836,7 +839,13 @@ export const AgentKitAssistantChat = forwardRef<
836
839
  signal: context?.signal,
837
840
  });
838
841
  if (!response.ok) {
839
- throw new Error(`Upload failed with ${response.status}.`);
842
+ throw new Error(
843
+ translatorRef.current(
844
+ response.status === 415
845
+ ? "agentChat.composer.unsupportedFileType"
846
+ : "agentChat.composer.uploadFailed",
847
+ ),
848
+ );
840
849
  }
841
850
  const result: unknown = await response.json();
842
851
  const uploaded = asRecord(result);
@@ -0,0 +1,129 @@
1
+ // @vitest-environment happy-dom
2
+
3
+ import React, {
4
+ act,
5
+ type ButtonHTMLAttributes,
6
+ type HTMLAttributes,
7
+ } from "react";
8
+ import { createRoot, type Root } from "react-dom/client";
9
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
10
+
11
+ import { FileStorageSetupPopover } from "./FileStorageSetupPopover.js";
12
+
13
+ vi.mock("@agent-native/core/client/i18n", () => ({
14
+ useT: () => (key: string) =>
15
+ (
16
+ ({
17
+ "onboarding.fileStorage.title": "Connect storage to upload files",
18
+ "onboarding.fileStorage.description":
19
+ "Use Builder.io (free) or configure your own S3-compatible object storage.",
20
+ "onboarding.fileStorage.custom": "Use custom keys",
21
+ "composer.connectBuilder": "Connect Builder.io",
22
+ }) as Record<string, string>
23
+ )[key] ?? key,
24
+ }));
25
+
26
+ vi.mock("@agent-native/toolkit/ui/popover", () => ({
27
+ Popover: ({ children, open }: { children: React.ReactNode; open: boolean }) =>
28
+ (open && <div>{children}</div>) || null,
29
+ PopoverAnchor: () => null,
30
+ PopoverContent: ({ children, ...props }: HTMLAttributes<HTMLDivElement>) => (
31
+ <div {...props}>{children}</div>
32
+ ),
33
+ }));
34
+
35
+ vi.mock("@agent-native/toolkit/ui/button", () => ({
36
+ Button: ({
37
+ children,
38
+ className,
39
+ disabled,
40
+ onClick,
41
+ type,
42
+ }: ButtonHTMLAttributes<HTMLButtonElement>) => (
43
+ <button
44
+ className={className}
45
+ disabled={disabled}
46
+ onClick={onClick}
47
+ type={type}
48
+ >
49
+ {children}
50
+ </button>
51
+ ),
52
+ }));
53
+
54
+ vi.mock("@tabler/icons-react", () => ({ IconCloudUpload: () => null }));
55
+
56
+ vi.mock("../settings/deferred-builder-connect-popover.js", () => ({
57
+ DeferredBuilderConnectPopover: ({
58
+ children,
59
+ }: {
60
+ children: React.ReactNode;
61
+ }) => children,
62
+ }));
63
+
64
+ vi.mock("../setup-connections/BuilderConnectCard.js", () => ({
65
+ BuilderConnectCard: ({
66
+ render,
67
+ }: {
68
+ render: (context: {
69
+ viewModel: { connectFlow: null; pending: false; error: null };
70
+ }) => React.ReactNode;
71
+ }) =>
72
+ render({
73
+ viewModel: { connectFlow: null, pending: false, error: null },
74
+ }),
75
+ }));
76
+
77
+ describe("FileStorageSetupPopover", () => {
78
+ let container: HTMLDivElement;
79
+ let root: Root;
80
+
81
+ beforeEach(() => {
82
+ vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);
83
+ container = document.createElement("div");
84
+ document.body.appendChild(container);
85
+ root = createRoot(container);
86
+ });
87
+
88
+ afterEach(() => {
89
+ act(() => root.unmount());
90
+ container.remove();
91
+ vi.unstubAllGlobals();
92
+ });
93
+
94
+ it("shows storage guidance with both setup choices when storage is missing", () => {
95
+ act(() => {
96
+ root.render(
97
+ <FileStorageSetupPopover
98
+ open
99
+ onOpenChange={vi.fn()}
100
+ status="missing"
101
+ />,
102
+ );
103
+ });
104
+
105
+ expect(container.querySelector("h2")?.textContent).toBe(
106
+ "Connect storage to upload files",
107
+ );
108
+ expect(container.textContent).toContain(
109
+ "Use Builder.io (free) or configure your own S3-compatible object storage.",
110
+ );
111
+ expect(container.querySelector("button")?.textContent).toContain(
112
+ "Connect Builder.io",
113
+ );
114
+ expect(container.textContent).toContain("Use custom keys");
115
+ expect(
116
+ container.querySelector('[aria-label="Connect storage to upload files"]')
117
+ ?.className,
118
+ ).toContain("p-3");
119
+ expect(container.querySelector("div.grid.gap-2")?.className).toBe(
120
+ "grid gap-2",
121
+ );
122
+ expect(container.querySelector("h2")?.parentElement?.className).toBe(
123
+ "grid gap-1",
124
+ );
125
+ expect(container.querySelector("button")?.parentElement?.className).toBe(
126
+ "flex gap-2",
127
+ );
128
+ });
129
+ });
@@ -63,6 +63,7 @@ export function FileStorageSetupPopover(props: FileStorageSetupPopoverProps) {
63
63
  }
64
64
 
65
65
  const title = t("onboarding.fileStorage.title");
66
+ const description = t("onboarding.fileStorage.description");
66
67
  // ponytail: wide home composers open left; add an explicit placement prop if a wide sidebar needs another side.
67
68
  const useLeftSide =
68
69
  (anchorRef?.current?.getBoundingClientRect().width ?? 0) >= 500;
@@ -97,7 +98,7 @@ export function FileStorageSetupPopover(props: FileStorageSetupPopoverProps) {
97
98
  className={
98
99
  status === "unavailable"
99
100
  ? "w-[256px] gap-2 p-2"
100
- : "w-[288px] gap-1 p-2"
101
+ : "w-[288px] gap-2 p-3"
101
102
  }
102
103
  >
103
104
  {status === "unavailable" ? (
@@ -139,8 +140,14 @@ export function FileStorageSetupPopover(props: FileStorageSetupPopoverProps) {
139
140
  );
140
141
 
141
142
  return (
142
- <div className={viewModel.error ? "grid gap-1.5" : undefined}>
143
- <div className="mt-2 flex gap-1.5">
143
+ <div className="grid gap-2">
144
+ <div className="grid gap-1">
145
+ <h2 className="text-sm font-medium leading-5">{title}</h2>
146
+ <p className="text-xs leading-4 text-muted-foreground">
147
+ {description}
148
+ </p>
149
+ </div>
150
+ <div className="flex gap-2">
144
151
  {flow ? (
145
152
  <BuilderConnectPopover
146
153
  flow={flow}
@@ -132,11 +132,14 @@ const messages: ToolkitAgentChatTranslation = {
132
132
  "onboarding.builderCredits": "مضمّنة مع أرصدة Builder.io المجانية",
133
133
  "onboarding.builderIncludedFreeWithAccount": "مُضمّن مجانًا مع حساب Builder.io",
134
134
  "onboarding.builderMonthlyCredits": "60 رصيد Agent شهريًا",
135
+ "onboarding.builderIncludedFree": "مُضمّن مجانًا",
136
+ "onboarding.builderMoreServices": "+ {{count}} خدمات أخرى",
137
+ "onboarding.builderIncludedServices": "الخدمات المضمنة",
135
138
  "onboarding.builderActivateTitle": "تفعيل الأرصدة المجانية",
136
139
  "onboarding.builderAccountExistsTitle": "لديك حساب Builder.io بالفعل",
137
140
  "onboarding.builderAccountExistsDescription": "سجّل الدخول لاستخدام حسابك.",
138
141
  "onboarding.builderActivationDescription":
139
- "سننشئ حساب Builder.io الخاص بك تلقائيًا بنقرة واحدة.",
142
+ "أنشئ حساب Builder.io أو اربطه بنقرة واحدة للحصول على أرصدة مجانية.",
140
143
  "onboarding.builderOrgActivationDescription":
141
144
  "سننشئ حساب Builder.io الخاص بك بنقرة واحدة ليتمكن مؤسستك من استخدامه.",
142
145
  "onboarding.builderCreateAndActivate": "إنشاء وتفعيل",
@@ -158,6 +161,10 @@ const messages: ToolkitAgentChatTranslation = {
158
161
  "onboarding.openBackgroundAgentSettings": "فتح إعدادات الوكيل في الخلفية",
159
162
  "onboarding.capability.llm.keySummary": "اربط نموذج الذكاء الاصطناعي الخاص بك",
160
163
  "onboarding.capability.fileStorage.keySummary": "تحميل الملفات وتخزينها",
164
+ "onboarding.capability.llm.why":
165
+ "يستخدم الوكيل نموذجًا لغويًا لفهم الطلبات وصياغة الإجابات.",
166
+ "onboarding.capability.fileStorage.why":
167
+ "يحفظ الصور والملفات المرفوعة ليتمكن الوكيل من إعادة استخدامها في المحادثة.",
161
168
  "onboarding.fileStorage.title": "اختر تخزين الملفات",
162
169
  "onboarding.fileStorage.statusUnavailable": "تعذّر التحقق من التخزين",
163
170
  "onboarding.fileStorage.description":
@@ -174,6 +181,8 @@ const messages: ToolkitAgentChatTranslation = {
174
181
  "onboarding.capability.embeddings.keySummary": "التضمينات",
175
182
  "onboarding.capability.embeddings.why":
176
183
  "تُحسّن التضمينات البحث الدلالي. يظل البحث بالكلمات المفتاحية يعمل من دونها.",
184
+ "onboarding.capability.systemOne.why":
185
+ "Jev نموذج قرار اختياري يساعد في اختيار الأدوات والمهارات المناسبة قبل أول طلب للنموذج من الوكيل.",
177
186
  "onboarding.capability.assetsImageGeneration.label": "إنشاء الصور",
178
187
  "onboarding.capability.assetsImageGeneration.keySummary":
179
188
  "أرصدة Builder أو مفتاح مزود صور",
@@ -478,6 +487,7 @@ const messages: ToolkitAgentChatTranslation = {
478
487
  "composer.skill.uploadFile": "رفع ملف مهارة",
479
488
  "composer.upload": "رفع",
480
489
  "composer.uploadFailed": "تعذّر رفع الملف المحدد.",
490
+ "composer.unsupportedFileType": "نوع الملف هذا غير مدعوم.",
481
491
  "composer.useAttachedContext": "استخدم السياق المرفق.",
482
492
  "mentions.commands": "الأوامر",
483
493
  "mentions.learnMore": "معرفة المزيد",
@@ -1107,11 +1117,10 @@ const messages: ToolkitAgentChatTranslation = {
1107
1117
  "queue.followUpWithCount": "{{count}} في قائمة الانتظار — أرسل متابعة...",
1108
1118
  "queue.remove": "إزالة من قائمة الانتظار",
1109
1119
  "queue.sendNow": "إرسال الآن",
1110
- "queue.sendNowHint": "الإرسال الآن (يوقف الرد الحالي)",
1111
- "queue.steer": "توجيه",
1112
- "queue.steerHint": "إرسال هذه الرسالة التالية",
1120
+ "queue.sendNowHint": "يوقف الرد الحالي، ثم يرسل هذه الرسالة",
1121
+ "queue.sendNext": "إرسال التالي",
1122
+ "queue.sendNextHint": "إرسال بعد انتهاء الرد الحالي",
1113
1123
  "queue.moreActions": "إجراءات إضافية",
1114
- "queue.moveToTop": "نقل إلى الأعلى",
1115
1124
  "recovery.connectingBuilder": "جارٍ إعداد Builder.io",
1116
1125
  "recovery.copyDebug": "نسخ معلومات التصحيح",
1117
1126
  "recovery.copyFailed": "فشل النسخ",
@@ -139,13 +139,16 @@ const messages: ToolkitAgentChatTranslation = {
139
139
  "onboarding.builderIncludedFreeWithAccount":
140
140
  "Kostenlos mit einem Builder.io-Konto enthalten",
141
141
  "onboarding.builderMonthlyCredits": "60 Agent Credits pro Monat",
142
+ "onboarding.builderIncludedFree": "Kostenlos enthalten",
143
+ "onboarding.builderMoreServices": "+ {{count}} weitere Dienste",
144
+ "onboarding.builderIncludedServices": "Enthaltene Dienste",
142
145
  "onboarding.builderActivateTitle": "Gratiscredits aktivieren",
143
146
  "onboarding.builderAccountExistsTitle":
144
147
  "Du hast bereits ein Builder.io-Konto",
145
148
  "onboarding.builderAccountExistsDescription":
146
149
  "Melde dich an, um dein Konto zu nutzen.",
147
150
  "onboarding.builderActivationDescription":
148
- "Wir erstellen dein Builder.io-Konto automatisch für dich mit einem Klick.",
151
+ "Erstelle oder verbinde ein Builder.io-Konto mit einem Klick und erhalte kostenlose Credits.",
149
152
  "onboarding.builderOrgActivationDescription":
150
153
  "Wir erstellen dein Builder.io-Konto mit einem Klick, damit deine Organisation es nutzen kann.",
151
154
  "onboarding.builderCreateAndActivate": "Erstellen und aktivieren",
@@ -169,6 +172,10 @@ const messages: ToolkitAgentChatTranslation = {
169
172
  "Einstellungen für Hintergrundagenten öffnen",
170
173
  "onboarding.capability.llm.keySummary": "Verbinde dein eigenes KI-Modell",
171
174
  "onboarding.capability.fileStorage.keySummary": "Datei-Uploads und Speicher",
175
+ "onboarding.capability.llm.why":
176
+ "Der Agent nutzt ein Sprachmodell, um Anfragen zu verstehen und Antworten zu erstellen.",
177
+ "onboarding.capability.fileStorage.why":
178
+ "Speichert hochgeladene Bilder und Dateien, damit der Agent sie im Verlauf wiederverwenden kann.",
172
179
  "onboarding.fileStorage.title": "Speicher verbinden, um Dateien hochzuladen",
173
180
  "onboarding.fileStorage.statusUnavailable":
174
181
  "Speicherstatus konnte nicht geprüft werden",
@@ -186,6 +193,8 @@ const messages: ToolkitAgentChatTranslation = {
186
193
  "onboarding.capability.embeddings.keySummary": "Semantische Vektoren",
187
194
  "onboarding.capability.embeddings.why":
188
195
  "Semantische Vektoren verbessern die semantische Suche. Die Stichwortsuche funktioniert auch ohne sie.",
196
+ "onboarding.capability.systemOne.why":
197
+ "Jev ist ein optionales Entscheidungsmodell, das vor der ersten Modellanfrage des Agenten passende Tools und Skills auswählt.",
189
198
  "onboarding.capability.assetsImageGeneration.label": "Bilderzeugung",
190
199
  "onboarding.capability.assetsImageGeneration.keySummary":
191
200
  "Builder-Credits oder Schlüssel eines Bildanbieters",
@@ -783,11 +792,11 @@ const messages: ToolkitAgentChatTranslation = {
783
792
  "{{count}} in der Warteschlange – Folgenachricht senden...",
784
793
  "queue.remove": "Aus Warteschlange entfernen",
785
794
  "queue.sendNow": "Jetzt senden",
786
- "queue.sendNowHint": "Jetzt senden (stoppt die aktuelle Antwort)",
787
- "queue.steer": "Steuern",
788
- "queue.steerHint": "Diese Nachricht als Nächstes senden",
795
+ "queue.sendNowHint":
796
+ "Stoppt die aktuelle Antwort und sendet dann diese Nachricht",
797
+ "queue.sendNext": "Als Nächstes senden",
798
+ "queue.sendNextHint": "Nach Abschluss der aktuellen Antwort senden",
789
799
  "queue.moreActions": "Weitere Aktionen",
790
- "queue.moveToTop": "Nach oben verschieben",
791
800
  "recovery.connectingBuilder": "Builder.io wird eingerichtet",
792
801
  "recovery.copyDebug": "Debug-Informationen kopieren",
793
802
  "recovery.copyFailed": "Kopieren fehlgeschlagen",
@@ -1111,6 +1120,7 @@ const messages: ToolkitAgentChatTranslation = {
1111
1120
  "composer.upload": "Hochladen",
1112
1121
  "composer.uploadFailed":
1113
1122
  "Die ausgewählte Datei konnte nicht hochgeladen werden.",
1123
+ "composer.unsupportedFileType": "Dieser Dateityp wird nicht unterstützt.",
1114
1124
  "composer.useAttachedContext": "Verwende den angehängten Kontext.",
1115
1125
  "mentions.commands": "Befehle",
1116
1126
  "mentions.learnMore": "Mehr erfahren",
@@ -131,12 +131,15 @@ const messages = {
131
131
  "onboarding.builderIncludedFreeWithAccount":
132
132
  "Included free with a Builder.io account",
133
133
  "onboarding.builderMonthlyCredits": "60 monthly Agent Credits",
134
+ "onboarding.builderIncludedFree": "Included free",
135
+ "onboarding.builderMoreServices": "+ {{count}} more services",
136
+ "onboarding.builderIncludedServices": "Included services",
134
137
  "onboarding.builderActivateTitle": "Activate free credits",
135
138
  "onboarding.builderAccountExistsTitle":
136
139
  "You already have a Builder.io account",
137
140
  "onboarding.builderAccountExistsDescription": "Log in to use your account.",
138
141
  "onboarding.builderActivationDescription":
139
- "We'll automatically create your Builder.io account for you in one click.",
142
+ "Create or connect a Builder.io account in one click to get free credits.",
140
143
  "onboarding.builderOrgActivationDescription":
141
144
  "We'll create your Builder.io account in one click so your organization can use it.",
142
145
  "onboarding.builderCreateAndActivate": "Create and activate",
@@ -159,6 +162,10 @@ const messages = {
159
162
  "onboarding.openBackgroundAgentSettings": "Open Background Agent settings",
160
163
  "onboarding.capability.llm.keySummary": "Connect your own AI model",
161
164
  "onboarding.capability.fileStorage.keySummary": "File uploads and storage",
165
+ "onboarding.capability.llm.why":
166
+ "The agent uses a language model to understand requests and produce answers.",
167
+ "onboarding.capability.fileStorage.why":
168
+ "Stores uploaded images and files so the agent can reuse them in your thread.",
162
169
  "onboarding.fileStorage.title": "Connect storage to upload files",
163
170
  "onboarding.fileStorage.statusUnavailable": "Couldn't check storage",
164
171
  "onboarding.fileStorage.description":
@@ -175,6 +182,8 @@ const messages = {
175
182
  "onboarding.capability.embeddings.keySummary": "Embeddings",
176
183
  "onboarding.capability.embeddings.why":
177
184
  "Embeddings improve semantic search. Keyword search still works without them.",
185
+ "onboarding.capability.systemOne.why":
186
+ "Jev is an optional decision model that helps choose relevant tools and skills before the agent's first model request.",
178
187
  "onboarding.capability.assetsImageGeneration.label": "Image generation",
179
188
  "onboarding.capability.assetsImageGeneration.keySummary":
180
189
  "Builder credits or an image provider key",
@@ -486,6 +495,7 @@ const messages = {
486
495
  "composer.skill.uploadFile": "Upload skill file",
487
496
  "composer.upload": "Upload",
488
497
  "composer.uploadFailed": "Could not upload the selected file.",
498
+ "composer.unsupportedFileType": "This file type isn't supported.",
489
499
  "composer.useAttachedContext": "Use the attached context.",
490
500
  "mentions.commands": "Commands",
491
501
  "mentions.learnMore": "Learn more",
@@ -1099,11 +1109,10 @@ const messages = {
1099
1109
  "queue.followUpWithCount": "{{count}} queued — send a follow-up...",
1100
1110
  "queue.remove": "Remove from queue",
1101
1111
  "queue.sendNow": "Send now",
1102
- "queue.sendNowHint": "Send now (stops the current response)",
1103
- "queue.steer": "Steer",
1104
- "queue.steerHint": "Send this message next",
1112
+ "queue.sendNowHint": "Stops the current response, then sends this message.",
1113
+ "queue.sendNext": "Send next",
1114
+ "queue.sendNextHint": "Send after the current response finishes",
1105
1115
  "queue.moreActions": "More actions",
1106
- "queue.moveToTop": "Move to top",
1107
1116
  "recovery.connectingBuilder": "Setting up Builder.io",
1108
1117
  "recovery.copyDebug": "Copy debug",
1109
1118
  "recovery.copyFailed": "Copy failed",