@agent-native/toolkit 0.206.0 → 0.206.1-nightly-20261009213000

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 (82) hide show
  1. package/dist/app/agentkit/react/components.d.ts.map +1 -1
  2. package/dist/app/agentkit/react/components.js +3 -3
  3. package/dist/app/agentkit/react/components.js.map +1 -1
  4. package/dist/app/agentkit/react/context.d.ts +1 -0
  5. package/dist/app/agentkit/react/context.d.ts.map +1 -1
  6. package/dist/app/agentkit/react/context.js +1 -0
  7. package/dist/app/agentkit/react/context.js.map +1 -1
  8. package/dist/app/agentkit/react/styles.css +43 -0
  9. package/dist/app/chat/AgentKitAssistantChat.d.ts.map +1 -1
  10. package/dist/app/chat/AgentKitAssistantChat.js +219 -75
  11. package/dist/app/chat/AgentKitAssistantChat.js.map +1 -1
  12. package/dist/app/chat/agentkit-chat/guided-questions.d.ts +18 -0
  13. package/dist/app/chat/agentkit-chat/guided-questions.d.ts.map +1 -1
  14. package/dist/app/chat/agentkit-chat/guided-questions.js +12 -4
  15. package/dist/app/chat/agentkit-chat/guided-questions.js.map +1 -1
  16. package/dist/app/chat/chat/run-recovery.d.ts +6 -1
  17. package/dist/app/chat/chat/run-recovery.d.ts.map +1 -1
  18. package/dist/app/chat/chat/run-recovery.js +6 -3
  19. package/dist/app/chat/chat/run-recovery.js.map +1 -1
  20. package/dist/app/i18n/catalogs/ar-SA.d.ts.map +1 -1
  21. package/dist/app/i18n/catalogs/ar-SA.js +8 -2
  22. package/dist/app/i18n/catalogs/ar-SA.js.map +1 -1
  23. package/dist/app/i18n/catalogs/de-DE.d.ts.map +1 -1
  24. package/dist/app/i18n/catalogs/de-DE.js +8 -2
  25. package/dist/app/i18n/catalogs/de-DE.js.map +1 -1
  26. package/dist/app/i18n/catalogs/en-US.d.ts +8 -2
  27. package/dist/app/i18n/catalogs/en-US.d.ts.map +1 -1
  28. package/dist/app/i18n/catalogs/en-US.js +8 -2
  29. package/dist/app/i18n/catalogs/en-US.js.map +1 -1
  30. package/dist/app/i18n/catalogs/es-ES.d.ts.map +1 -1
  31. package/dist/app/i18n/catalogs/es-ES.js +8 -2
  32. package/dist/app/i18n/catalogs/es-ES.js.map +1 -1
  33. package/dist/app/i18n/catalogs/fr-FR.d.ts.map +1 -1
  34. package/dist/app/i18n/catalogs/fr-FR.js +8 -2
  35. package/dist/app/i18n/catalogs/fr-FR.js.map +1 -1
  36. package/dist/app/i18n/catalogs/hi-IN.d.ts.map +1 -1
  37. package/dist/app/i18n/catalogs/hi-IN.js +8 -2
  38. package/dist/app/i18n/catalogs/hi-IN.js.map +1 -1
  39. package/dist/app/i18n/catalogs/ja-JP.d.ts.map +1 -1
  40. package/dist/app/i18n/catalogs/ja-JP.js +8 -2
  41. package/dist/app/i18n/catalogs/ja-JP.js.map +1 -1
  42. package/dist/app/i18n/catalogs/ko-KR.d.ts.map +1 -1
  43. package/dist/app/i18n/catalogs/ko-KR.js +8 -2
  44. package/dist/app/i18n/catalogs/ko-KR.js.map +1 -1
  45. package/dist/app/i18n/catalogs/pt-BR.d.ts.map +1 -1
  46. package/dist/app/i18n/catalogs/pt-BR.js +8 -2
  47. package/dist/app/i18n/catalogs/pt-BR.js.map +1 -1
  48. package/dist/app/i18n/catalogs/zh-CN.d.ts.map +1 -1
  49. package/dist/app/i18n/catalogs/zh-CN.js +8 -2
  50. package/dist/app/i18n/catalogs/zh-CN.js.map +1 -1
  51. package/dist/app/i18n/catalogs/zh-TW.d.ts.map +1 -1
  52. package/dist/app/i18n/catalogs/zh-TW.js +8 -2
  53. package/dist/app/i18n/catalogs/zh-TW.js.map +1 -1
  54. package/dist/app/sharing/ShareButton.d.ts +9 -0
  55. package/dist/app/sharing/ShareButton.d.ts.map +1 -1
  56. package/dist/app/sharing/ShareButton.js +23 -11
  57. package/dist/app/sharing/ShareButton.js.map +1 -1
  58. package/package.json +4 -4
  59. package/src/app/agentkit/react/components.tsx +6 -3
  60. package/src/app/agentkit/react/context.tsx +2 -0
  61. package/src/app/agentkit/react/styles.css +43 -0
  62. package/src/app/chat/AgentKitAssistantChat.spec.tsx +425 -15
  63. package/src/app/chat/AgentKitAssistantChat.tsx +306 -95
  64. package/src/app/chat/agentkit-chat/guided-questions.flow.spec.tsx +89 -5
  65. package/src/app/chat/agentkit-chat/guided-questions.tsx +17 -6
  66. package/src/app/chat/chat/run-recovery.spec.tsx +48 -0
  67. package/src/app/chat/chat/run-recovery.tsx +23 -1
  68. package/src/app/i18n/catalogs/ar-SA.ts +14 -2
  69. package/src/app/i18n/catalogs/de-DE.ts +12 -2
  70. package/src/app/i18n/catalogs/en-US.ts +13 -2
  71. package/src/app/i18n/catalogs/es-ES.ts +12 -2
  72. package/src/app/i18n/catalogs/fr-FR.ts +12 -2
  73. package/src/app/i18n/catalogs/hi-IN.ts +12 -2
  74. package/src/app/i18n/catalogs/ja-JP.ts +12 -2
  75. package/src/app/i18n/catalogs/ko-KR.ts +12 -2
  76. package/src/app/i18n/catalogs/pt-BR.ts +12 -2
  77. package/src/app/i18n/catalogs/zh-CN.ts +8 -2
  78. package/src/app/i18n/catalogs/zh-TW.ts +8 -2
  79. package/src/app/settings/model/ProviderDialog.spec.tsx +1 -0
  80. package/src/app/sharing/ShareButton.spec.tsx +148 -0
  81. package/src/app/sharing/ShareButton.tsx +44 -15
  82. package/src/app/sharing/useShareButtonController.spec.tsx +25 -1
@@ -479,9 +479,14 @@ const messages: ToolkitAgentChatTranslation = {
479
479
  "composer.skill.uploadFile": "上傳技能檔案",
480
480
  "composer.upload": "上傳",
481
481
  "composer.uploadFailed": "無法上傳所選檔案。",
482
- "composer.fileTooLarge": "此檔案超出上傳大小限制。",
483
- "composer.sessionExpired": "工作階段已逾期。請重新整理頁面後再試一次。",
482
+ "composer.fileTooLarge": "此檔案超過 {{size}} MB 的上傳大小限制。",
483
+ "composer.sessionExpired": "工作階段已逾期。請重新登入,然後再傳送訊息。",
484
484
  "composer.unsupportedFileType": "不支援此檔案類型。",
485
+ "composer.uploadUnavailable": "目前無法上傳檔案。請稍後再試。",
486
+ "composer.uploadOffline": "上傳無法連線至伺服器。請檢查網路連線後再試一次。",
487
+ "composer.submissionNotReady": "聊天尚未準備好傳送。請稍候片刻再傳送。",
488
+ "composer.submissionScopeChanged": "此聊天在訊息傳送前已變更。請重新傳送。",
489
+ "composer.attachmentNotSaved": "未隨此聊天儲存",
485
490
  "composer.useAttachedContext": "使用附加的上下文。",
486
491
  "mentions.commands": "命令",
487
492
  "mentions.learnMore": "深入瞭解",
@@ -1081,6 +1086,7 @@ const messages: ToolkitAgentChatTranslation = {
1081
1086
  "recovery.continueUnavailable": "此執行已無法繼續。傳送訊息以繼續。",
1082
1087
  "recovery.retryAttachmentUnavailable":
1083
1088
  "此要求包含無法重試的檔案。請在訊息輸入框中重新附加檔案,然後再試一次。",
1089
+ "recovery.retryWithoutAttachment": "不含附件重試",
1084
1090
  "recovery.deferredSubmissionFailed":
1085
1091
  "無法傳送這則訊息。請檢查連線或聊天設定,然後再試一次。",
1086
1092
  "recovery.credentialRejected":
@@ -340,6 +340,7 @@ describe("ProviderDialog", () => {
340
340
  outcome: "accepted",
341
341
  }),
342
342
  );
343
+ expect(button("Add provider").disabled).toBe(false);
343
344
  });
344
345
 
345
346
  await act(async () => button("Add provider").click());
@@ -1395,6 +1395,154 @@ describe("ShareButton", () => {
1395
1395
  expect(queriedActions).not.toContain("list-resource-access-requests");
1396
1396
  });
1397
1397
 
1398
+ it("keeps to the basic share actions when the session cannot run the rest", async () => {
1399
+ sharesData.current = { ...sharesData.current, agentReadable: true };
1400
+ accessRequestsData.current = [patRequest];
1401
+ await act(async () => {
1402
+ root.render(
1403
+ <TooltipProvider>
1404
+ <QueryClientProvider client={queryClient}>
1405
+ <ShareButton
1406
+ resourceType="deck"
1407
+ resourceId="deck-1"
1408
+ basicSharingOnly
1409
+ />
1410
+ </QueryClientProvider>
1411
+ </TooltipProvider>,
1412
+ );
1413
+ });
1414
+
1415
+ const text = container.textContent ?? "";
1416
+ expect(text).toContain("People with access");
1417
+ expect(text).not.toContain("Access requests");
1418
+ expect(text).not.toContain("Share with agents");
1419
+ expect(queriedActions).not.toContain("list-resource-access-requests");
1420
+ expect(queriedActions).toContain("list-resource-shares");
1421
+ });
1422
+
1423
+ it("does not search the organization for people when keeping to the basic share actions", async () => {
1424
+ const fetchMock = vi.fn(async () => Response.json({ members: [] }));
1425
+ vi.stubGlobal("fetch", fetchMock);
1426
+ await act(async () => {
1427
+ root.render(
1428
+ <TooltipProvider>
1429
+ <QueryClientProvider client={queryClient}>
1430
+ <ShareButton
1431
+ resourceType="deck"
1432
+ resourceId="deck-1"
1433
+ basicSharingOnly
1434
+ />
1435
+ </QueryClientProvider>
1436
+ </TooltipProvider>,
1437
+ );
1438
+ });
1439
+
1440
+ const input = container.querySelector(
1441
+ 'input[placeholder="Add people by email"]',
1442
+ ) as HTMLInputElement;
1443
+ act(() => input.focus());
1444
+ setInputValue(input, "guest@example.com");
1445
+ await act(async () => {
1446
+ await new Promise((resolve) => setTimeout(resolve, 180));
1447
+ });
1448
+
1449
+ expect(
1450
+ fetchMock.mock.calls.some((call) =>
1451
+ String(call[0]).includes("/_agent-native/org/members"),
1452
+ ),
1453
+ ).toBe(false);
1454
+ expect(container.textContent).not.toContain("Could not load people.");
1455
+ });
1456
+
1457
+ it("does not offer the admin role or an email note when keeping to the basic share actions", async () => {
1458
+ await act(async () => {
1459
+ root.render(
1460
+ <QueryClientProvider client={queryClient}>
1461
+ <ShareButton
1462
+ resourceType="deck"
1463
+ resourceId="deck-1"
1464
+ basicSharingOnly
1465
+ />
1466
+ </QueryClientProvider>,
1467
+ );
1468
+ });
1469
+
1470
+ const input = container.querySelector(
1471
+ 'input[placeholder="Add people by email"]',
1472
+ ) as HTMLInputElement;
1473
+ setInputValue(input, "guest@example.com");
1474
+ expect(container.textContent).toContain("Notify people");
1475
+ expect(container.textContent).not.toContain("Add a message");
1476
+
1477
+ const roleTrigger = container.querySelector(
1478
+ 'button[aria-label="Role"]',
1479
+ ) as HTMLButtonElement | null;
1480
+ await act(async () => roleTrigger?.click());
1481
+ const options = Array.from(
1482
+ document.querySelectorAll<HTMLElement>('[role="option"]'),
1483
+ ).map((option) => option.textContent ?? "");
1484
+ expect(options.some((option) => option.includes("Editor"))).toBe(true);
1485
+ expect(options.some((option) => option.includes("Admin"))).toBe(false);
1486
+ });
1487
+
1488
+ it("offers the admin role and an email note outside the basic share actions", async () => {
1489
+ await act(async () => {
1490
+ root.render(
1491
+ <QueryClientProvider client={queryClient}>
1492
+ <ShareButton resourceType="deck" resourceId="deck-1" />
1493
+ </QueryClientProvider>,
1494
+ );
1495
+ });
1496
+
1497
+ const input = container.querySelector(
1498
+ 'input[placeholder="Add people by email"]',
1499
+ ) as HTMLInputElement;
1500
+ setInputValue(input, "guest@example.com");
1501
+ expect(container.textContent).toContain("Add a message");
1502
+
1503
+ const roleTrigger = container.querySelector(
1504
+ 'button[aria-label="Role"]',
1505
+ ) as HTMLButtonElement | null;
1506
+ await act(async () => roleTrigger?.click());
1507
+ expect(
1508
+ Array.from(
1509
+ document.querySelectorAll<HTMLElement>('[role="option"]'),
1510
+ ).some((option) => option.textContent?.includes("Admin")),
1511
+ ).toBe(true);
1512
+ });
1513
+
1514
+ it("lets a host size the joined copy control through quickCopy.className", async () => {
1515
+ await act(async () => {
1516
+ root.render(
1517
+ <TooltipProvider>
1518
+ <QueryClientProvider client={queryClient}>
1519
+ <ShareButton
1520
+ resourceType="document"
1521
+ resourceId="doc-1"
1522
+ quickCopy={{
1523
+ label: "Copy page link",
1524
+ copiedLabel: "Copied page link",
1525
+ onCopy: async () => true,
1526
+ className: "widget-joined-share",
1527
+ }}
1528
+ />
1529
+ </QueryClientProvider>
1530
+ </TooltipProvider>,
1531
+ );
1532
+ });
1533
+
1534
+ const joined = container.querySelector(".widget-joined-share");
1535
+ expect(joined).not.toBeNull();
1536
+ expect(
1537
+ joined?.contains(
1538
+ container.querySelector('button[aria-label="Copy page link"]'),
1539
+ ),
1540
+ ).toBe(true);
1541
+ expect(
1542
+ joined?.contains(container.querySelector('button[aria-label="Share"]')),
1543
+ ).toBe(true);
1544
+ });
1545
+
1398
1546
  // Keep the non-source-locale provider test last: react-i18next's global
1399
1547
  // fallback instance otherwise leaks the selected language into tests that
1400
1548
  // intentionally exercise providerless compatibility.
@@ -80,6 +80,14 @@ export interface ShareButtonProps {
80
80
  shareUrl?: string;
81
81
  /** Use a bottom sheet for the share surface below the small-screen breakpoint. */
82
82
  mobileSheet?: boolean;
83
+ /**
84
+ * The session can run only the basic share actions (list, share, unshare,
85
+ * visibility), as a scoped MCP App widget session can. Omits the access
86
+ * request review, the agent-context link and the people suggestions, which
87
+ * need other routes, and the admin role and email note, which such a
88
+ * session may not send; an email is still added by typing it.
89
+ */
90
+ basicSharingOnly?: boolean;
83
91
  /** Open the share surface without rendering a trigger button. */
84
92
  hideTrigger?: boolean;
85
93
  /** Override the optional temporary agent-context link label. */
@@ -93,6 +101,7 @@ export interface ShareButtonProps {
93
101
  label: string;
94
102
  copiedLabel: string;
95
103
  onCopy: () => Promise<boolean | void> | boolean | void;
104
+ className?: string;
96
105
  };
97
106
  /** Optional label for the primary copyable link section. */
98
107
  shareUrlLabel?: string;
@@ -220,6 +229,18 @@ function visibilityMeta(
220
229
  };
221
230
  }
222
231
 
232
+ // A scoped host session cannot grant the admin role, so it is not offered.
233
+ const BASIC_SHARING_ROLES: readonly Role[] = ["viewer", "commenter", "editor"];
234
+
235
+ function allowedRolesFor(
236
+ props: Pick<ShareButtonProps, "allowedRoles" | "basicSharingOnly">,
237
+ ): readonly Role[] | undefined {
238
+ return (
239
+ props.allowedRoles ??
240
+ (props.basicSharingOnly ? BASIC_SHARING_ROLES : undefined)
241
+ );
242
+ }
243
+
223
244
  function roleOptions(
224
245
  t: ShareTranslate,
225
246
  ): Array<{ value: Role; label: string; description: string }> {
@@ -312,7 +333,7 @@ export function ShareButton(props: ShareButtonProps) {
312
333
  onShareSuccess: props.onShareSuccess,
313
334
  shareTabs: props.shareTabs,
314
335
  shareUrl: props.shareUrl,
315
- allowedRoles: props.allowedRoles,
336
+ allowedRoles: allowedRolesFor(props),
316
337
  hideInSearchControl: props.hideInSearchControl,
317
338
  });
318
339
  useEffect(() => {
@@ -355,6 +376,7 @@ export function ShareButton(props: ShareButtonProps) {
355
376
  copyLabel={props.quickCopy.label}
356
377
  copiedLabel={props.quickCopy.copiedLabel}
357
378
  onCopy={props.quickCopy.onCopy}
379
+ className={props.quickCopy.className}
358
380
  />
359
381
  ) : (
360
382
  <SheetTrigger asChild>{trigger}</SheetTrigger>
@@ -391,6 +413,7 @@ export function ShareButton(props: ShareButtonProps) {
391
413
  copyLabel={props.quickCopy.label}
392
414
  copiedLabel={props.quickCopy.copiedLabel}
393
415
  onCopy={props.quickCopy.onCopy}
416
+ className={props.quickCopy.className}
394
417
  />
395
418
  </PopoverAnchor>
396
419
  ) : (
@@ -469,12 +492,13 @@ function SharePanel(
469
492
  const generalAccessLabel =
470
493
  props.generalAccessLabel ??
471
494
  t("agentChat.share.generalAccess", { defaultValue: "General access" });
472
- const accessRequests = canManage ? (
473
- <AccessRequestsSection
474
- resourceType={props.resourceType}
475
- resourceId={props.resourceId}
476
- />
477
- ) : null;
495
+ const accessRequests =
496
+ canManage && !props.basicSharingOnly ? (
497
+ <AccessRequestsSection
498
+ resourceType={props.resourceType}
499
+ resourceId={props.resourceId}
500
+ />
501
+ ) : null;
478
502
  const shareLinks = (
479
503
  <>
480
504
  {props.shareUrl ? (
@@ -610,8 +634,10 @@ function SharePanel(
610
634
  <div className="w-full sm:min-w-0 sm:flex-1">
611
635
  <MemberAutocomplete
612
636
  value={inviteEmail}
613
- open={suggestionsOpen}
614
- onOpenChange={setSuggestionsOpen}
637
+ open={suggestionsOpen && !props.basicSharingOnly}
638
+ onOpenChange={(open) => {
639
+ if (!props.basicSharingOnly) setSuggestionsOpen(open);
640
+ }}
615
641
  onValueChange={(next) => {
616
642
  onInviteEmailChange(next);
617
643
  if (shareError) setShareError(null);
@@ -656,7 +682,7 @@ function SharePanel(
656
682
  value={role}
657
683
  onChange={setRole}
658
684
  roleCopy={props.roleCopy}
659
- allowedRoles={props.allowedRoles}
685
+ allowedRoles={allowedRolesFor(props)}
660
686
  />
661
687
  <button
662
688
  type="button"
@@ -688,7 +714,7 @@ function SharePanel(
688
714
  defaultValue: "Notify people",
689
715
  })}
690
716
  </label>
691
- {notifyPeople ? (
717
+ {notifyPeople && !props.basicSharingOnly ? (
692
718
  <button
693
719
  type="button"
694
720
  aria-expanded={messageOpen}
@@ -706,7 +732,10 @@ function SharePanel(
706
732
  ) : null}
707
733
  </div>
708
734
  ) : null}
709
- {hasInviteEmail && notifyPeople && messageOpen ? (
735
+ {hasInviteEmail &&
736
+ notifyPeople &&
737
+ messageOpen &&
738
+ !props.basicSharingOnly ? (
710
739
  <div className="rounded-md border border-border/70 bg-muted/20 p-2.5">
711
740
  <textarea
712
741
  aria-label={t("agentChat.share.message", {
@@ -777,7 +806,7 @@ function SharePanel(
777
806
  disabled={inFlight.has(keyOf(s))}
778
807
  plain
779
808
  roleCopy={props.roleCopy}
780
- allowedRoles={props.allowedRoles}
809
+ allowedRoles={allowedRolesFor(props)}
781
810
  />
782
811
  ) : (
783
812
  <span className="text-xs text-muted-foreground">
@@ -818,7 +847,7 @@ function SharePanel(
818
847
  </div>
819
848
  ) : null}
820
849
 
821
- {!props.agentTabContent ? (
850
+ {!props.agentTabContent && !props.basicSharingOnly ? (
822
851
  <AgentShareSection
823
852
  enabled={data?.agentReadable === true}
824
853
  resourceType={props.resourceType}
@@ -849,7 +878,7 @@ function SharePanel(
849
878
  const agentPanel = (
850
879
  <div className="space-y-4">
851
880
  {props.agentTabContent}
852
- {!loadFailed && !isLoading ? (
881
+ {!loadFailed && !isLoading && !props.basicSharingOnly ? (
853
882
  <AgentShareSection
854
883
  enabled={data?.agentReadable === true}
855
884
  resourceType={props.resourceType}
@@ -12,6 +12,7 @@ import { createRoot, type Root } from "react-dom/client";
12
12
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
13
13
 
14
14
  const mocks = vi.hoisted(() => ({
15
+ useActionQuery: vi.fn(),
15
16
  query: {
16
17
  data: undefined as ShareButtonSharesResponse | undefined,
17
18
  refetch: vi.fn(async () => undefined),
@@ -22,7 +23,7 @@ const mocks = vi.hoisted(() => ({
22
23
  }));
23
24
 
24
25
  vi.mock("@agent-native/core/client/use-action", () => ({
25
- useActionQuery: vi.fn(() => mocks.query),
26
+ useActionQuery: mocks.useActionQuery,
26
27
  useActionMutation: vi.fn((name: string) => {
27
28
  if (name === "set-resource-visibility") return mocks.setVisibility;
28
29
  if (name === "share-resource") return mocks.share;
@@ -84,6 +85,7 @@ describe("useShareButtonController", () => {
84
85
  ],
85
86
  };
86
87
  mocks.query.refetch.mockClear();
88
+ mocks.useActionQuery.mockReset().mockReturnValue(mocks.query);
87
89
  mocks.setVisibility.mutate.mockReset();
88
90
  mocks.share.mutate.mockReset();
89
91
  mocks.unshare.mutate.mockReset();
@@ -106,6 +108,28 @@ describe("useShareButtonController", () => {
106
108
  controller = undefined;
107
109
  });
108
110
 
111
+ it("loads share state only while the popover is open", async () => {
112
+ const result = await render();
113
+ const latestShareQueryOptions = () =>
114
+ mocks.useActionQuery.mock.calls
115
+ .filter(([name]) => name === "list-resource-shares")
116
+ .at(-1)?.[2];
117
+
118
+ expect(latestShareQueryOptions()).toEqual({
119
+ enabled: false,
120
+ staleTime: 0,
121
+ });
122
+ expect(mocks.query.refetch).not.toHaveBeenCalled();
123
+
124
+ act(() => result.handleOpenChange(true));
125
+
126
+ expect(latestShareQueryOptions()).toEqual({
127
+ enabled: true,
128
+ staleTime: 0,
129
+ });
130
+ expect(mocks.query.refetch).not.toHaveBeenCalled();
131
+ });
132
+
109
133
  it("guards rapid duplicate invites for the same principal", async () => {
110
134
  const result = await render();
111
135
  act(() => {