@agent-native/core 0.155.0 → 0.157.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 (95) hide show
  1. package/corpus/templates/assets/app/components/asset/AssetPreviewDialog.tsx +3 -1
  2. package/corpus/templates/assets/app/i18n-data.ts +21 -1
  3. package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +17 -13
  4. package/corpus/templates/clips/app/components/player/share-dialog.tsx +102 -59
  5. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +15 -1
  6. package/corpus/templates/clips/app/routes/share.$shareId.tsx +16 -2
  7. package/corpus/templates/slides/app/components/editor/AddSlidePopover.tsx +98 -29
  8. package/corpus/templates/slides/app/components/editor/EditorActionCluster.tsx +45 -91
  9. package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +94 -2
  10. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +17 -29
  11. package/corpus/templates/slides/app/components/editor/SlideContextToolbar.tsx +1 -1
  12. package/corpus/templates/slides/app/context/DeckContext.tsx +42 -2
  13. package/corpus/templates/slides/app/global.css +7 -40
  14. package/corpus/templates/slides/app/i18n/en-US.ts +4 -0
  15. package/corpus/templates/slides/app/pages/DeckEditor.tsx +130 -45
  16. package/dist/agent/index.d.ts +1 -1
  17. package/dist/agent/production-agent.d.ts +30 -0
  18. package/dist/agent/production-agent.js +100 -8
  19. package/dist/agent/types.d.ts +9 -0
  20. package/dist/client/AgentPanel.js +12 -9
  21. package/dist/client/AssistantChat.d.ts +15 -1
  22. package/dist/client/AssistantChat.js +110 -43
  23. package/dist/client/MultiTabAssistantChat.js +44 -27
  24. package/dist/client/chat/markdown-renderer.js +4 -2
  25. package/dist/client/chat/message-components.d.ts +2 -2
  26. package/dist/client/chat/message-components.js +69 -35
  27. package/dist/client/chat/run-recovery.d.ts +4 -1
  28. package/dist/client/chat/run-recovery.js +62 -30
  29. package/dist/client/chat/tool-call-display.d.ts +12 -3
  30. package/dist/client/chat/tool-call-display.js +79 -40
  31. package/dist/client/chat/widgets/DataChartRenderer.js +3 -1
  32. package/dist/client/chat/widgets/DataChartWidget.js +8 -2
  33. package/dist/client/chat/widgets/DataInsightsWidget.js +3 -1
  34. package/dist/client/chat/widgets/DataTableWidget.js +23 -9
  35. package/dist/client/chat/widgets/builtin-tool-renderers.js +3 -1
  36. package/dist/client/components/ui/message-scroller.d.ts +1 -1
  37. package/dist/client/components/ui/message-scroller.js +7 -3
  38. package/dist/client/composer/runtime-adapters.js +3 -2
  39. package/dist/client/context-xray/ContextMeter.js +5 -1
  40. package/dist/client/context-xray/ContextXRayPanel.js +5 -5
  41. package/dist/client/error-format.d.ts +4 -0
  42. package/dist/client/error-format.js +93 -5
  43. package/dist/client/i18n.js +83 -17
  44. package/dist/client/observability/ThumbsFeedback.js +10 -8
  45. package/dist/client/sharing/ShareButton.js +160 -54
  46. package/dist/coding-tools/run-code.js +2 -1
  47. package/dist/coding-tools/sandbox/background.d.ts +1 -0
  48. package/dist/coding-tools/sandbox/background.js +8 -1
  49. package/dist/coding-tools/sandbox/executions-store.d.ts +2 -0
  50. package/dist/coding-tools/sandbox/executions-store.js +41 -3
  51. package/dist/collab/routes.d.ts +1 -1
  52. package/dist/index.d.ts +1 -1
  53. package/dist/localization/core-messages/ar-SA.d.ts +3 -0
  54. package/dist/localization/core-messages/ar-SA.js +541 -0
  55. package/dist/localization/core-messages/de-DE.d.ts +3 -0
  56. package/dist/localization/core-messages/de-DE.js +513 -0
  57. package/dist/localization/core-messages/en-US.d.ts +513 -0
  58. package/dist/localization/core-messages/en-US.js +513 -0
  59. package/dist/localization/core-messages/es-ES.d.ts +3 -0
  60. package/dist/localization/core-messages/es-ES.js +520 -0
  61. package/dist/localization/core-messages/fr-FR.d.ts +3 -0
  62. package/dist/localization/core-messages/fr-FR.js +520 -0
  63. package/dist/localization/core-messages/hi-IN.d.ts +3 -0
  64. package/dist/localization/core-messages/hi-IN.js +513 -0
  65. package/dist/localization/core-messages/ja-JP.d.ts +3 -0
  66. package/dist/localization/core-messages/ja-JP.js +506 -0
  67. package/dist/localization/core-messages/ko-KR.d.ts +3 -0
  68. package/dist/localization/core-messages/ko-KR.js +506 -0
  69. package/dist/localization/core-messages/pt-BR.d.ts +3 -0
  70. package/dist/localization/core-messages/pt-BR.js +520 -0
  71. package/dist/localization/core-messages/zh-CN.d.ts +3 -0
  72. package/dist/localization/core-messages/zh-CN.js +506 -0
  73. package/dist/localization/core-messages/zh-TW.d.ts +3 -0
  74. package/dist/localization/core-messages/zh-TW.js +506 -0
  75. package/dist/localization/core-messages.d.ts +524 -0
  76. package/dist/localization/core-messages.js +124 -0
  77. package/dist/localization/default-messages.d.ts +2 -0
  78. package/dist/localization/default-messages.js +2 -0
  79. package/dist/notifications/routes.d.ts +1 -1
  80. package/dist/observability/routes.d.ts +5 -5
  81. package/dist/resources/handlers.d.ts +1 -1
  82. package/dist/secrets/routes.d.ts +9 -9
  83. package/dist/server/agent-chat/plugin-options.d.ts +7 -2
  84. package/dist/server/agent-chat-plugin.d.ts +10 -0
  85. package/dist/server/agent-chat-plugin.js +144 -41
  86. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  87. package/dist/server/agent-run-context.d.ts +7 -1
  88. package/dist/server/agent-run-context.js +9 -2
  89. package/dist/server/agent-teams-run-queue.d.ts +3 -0
  90. package/dist/server/agent-teams.js +38 -9
  91. package/dist/server/index.d.ts +1 -1
  92. package/dist/server/request-context.d.ts +7 -0
  93. package/dist/server/request-context.js +15 -0
  94. package/docs/content/agent-surfaces.mdx +30 -0
  95. package/package.json +2 -2
@@ -3,14 +3,16 @@ import * as PopoverPrimitive from "@radix-ui/react-popover";
3
3
  import { IconThumbUp, IconThumbDown } from "@tabler/icons-react";
4
4
  import { useState, useCallback } from "react";
5
5
  import { agentNativePath } from "../api-path.js";
6
+ import { useT } from "../i18n.js";
6
7
  import { cn } from "../utils.js";
7
8
  const THUMBS_DOWN_CATEGORIES = [
8
- "Inaccurate",
9
- "Not helpful",
10
- "Wrong tool",
11
- "Too slow",
9
+ { value: "Inaccurate", key: "agentChat.feedback.inaccurate" },
10
+ { value: "Not helpful", key: "agentChat.feedback.notHelpful" },
11
+ { value: "Wrong tool", key: "agentChat.feedback.wrongTool" },
12
+ { value: "Too slow", key: "agentChat.feedback.tooSlow" },
12
13
  ];
13
14
  export function ThumbsFeedback({ threadId, runId, messageSeq, className, }) {
15
+ const t = useT();
14
16
  const [selection, setSelection] = useState(null);
15
17
  const [categoryOpen, setCategoryOpen] = useState(false);
16
18
  const [submittedCategory, setSubmittedCategory] = useState(null);
@@ -54,11 +56,11 @@ export function ThumbsFeedback({ threadId, runId, messageSeq, className, }) {
54
56
  setCategoryOpen(false);
55
57
  sendFeedback("category", category);
56
58
  }, [sendFeedback]);
57
- return (_jsxs("div", { className: cn("inline-flex items-center gap-0.5", className), children: [_jsx("button", { type: "button", "aria-label": "Thumbs up", onClick: handleThumbsUp, className: cn("flex h-6 w-6 items-center justify-center rounded", selection === "up"
59
+ return (_jsxs("div", { className: cn("inline-flex items-center gap-0.5", className), children: [_jsx("button", { type: "button", "aria-label": t("agentChat.feedback.thumbsUp"), onClick: handleThumbsUp, className: cn("flex h-6 w-6 items-center justify-center rounded", selection === "up"
58
60
  ? "text-foreground"
59
- : "text-muted-foreground/70 hover:text-muted-foreground hover:bg-accent/50"), children: _jsx(IconThumbUp, { size: 16, stroke: selection === "up" ? 2.5 : 1.5, fill: selection === "up" ? "currentColor" : "none" }) }), _jsxs(PopoverPrimitive.Root, { open: categoryOpen, onOpenChange: setCategoryOpen, children: [_jsx(PopoverPrimitive.Trigger, { asChild: true, children: _jsx("button", { type: "button", "aria-label": "Thumbs down", onClick: handleThumbsDown, className: cn("flex h-6 w-6 items-center justify-center rounded", selection === "down"
61
+ : "text-muted-foreground/70 hover:text-muted-foreground hover:bg-accent/50"), children: _jsx(IconThumbUp, { size: 16, stroke: selection === "up" ? 2.5 : 1.5, fill: selection === "up" ? "currentColor" : "none" }) }), _jsxs(PopoverPrimitive.Root, { open: categoryOpen, onOpenChange: setCategoryOpen, children: [_jsx(PopoverPrimitive.Trigger, { asChild: true, children: _jsx("button", { type: "button", "aria-label": t("agentChat.feedback.thumbsDown"), onClick: handleThumbsDown, className: cn("flex h-6 w-6 items-center justify-center rounded", selection === "down"
60
62
  ? "text-foreground"
61
- : "text-muted-foreground/70 hover:text-muted-foreground hover:bg-accent/50"), children: _jsx(IconThumbDown, { size: 16, stroke: selection === "down" ? 2.5 : 1.5, fill: selection === "down" ? "currentColor" : "none" }) }) }), _jsx(PopoverPrimitive.Portal, { children: _jsx(PopoverPrimitive.Content, { side: "bottom", align: "start", sideOffset: 4, collisionPadding: 8, className: "z-[300] overflow-hidden rounded-lg border border-border bg-popover p-1 shadow-lg outline-none", children: _jsx("div", { className: "flex flex-col gap-0.5", children: THUMBS_DOWN_CATEGORIES.map((category) => (_jsx("button", { type: "button", onClick: () => handleCategory(category), className: cn("rounded-md px-3 py-1.5 text-left text-xs", submittedCategory === category
63
+ : "text-muted-foreground/70 hover:text-muted-foreground hover:bg-accent/50"), children: _jsx(IconThumbDown, { size: 16, stroke: selection === "down" ? 2.5 : 1.5, fill: selection === "down" ? "currentColor" : "none" }) }) }), _jsx(PopoverPrimitive.Portal, { children: _jsx(PopoverPrimitive.Content, { side: "bottom", align: "start", sideOffset: 4, collisionPadding: 8, className: "z-[300] overflow-hidden rounded-lg border border-border bg-popover p-1 shadow-lg outline-none", children: _jsx("div", { className: "flex flex-col gap-0.5", children: THUMBS_DOWN_CATEGORIES.map((category) => (_jsx("button", { type: "button", onClick: () => handleCategory(category.value), className: cn("rounded-md px-3 py-1.5 text-start text-xs", submittedCategory === category.value
62
64
  ? "bg-accent text-foreground font-medium"
63
- : "text-muted-foreground hover:bg-accent/50 hover:text-foreground"), children: category }, category))) }) }) })] })] }));
65
+ : "text-muted-foreground hover:bg-accent/50 hover:text-foreground"), children: t(category.key) }, category.value))) }) }) })] })] }));
64
66
  }
@@ -4,6 +4,7 @@ import { IconLock, IconWorld, IconTrash, IconCheck, IconChevronDown, IconLoader2
4
4
  import { useEffect, useId, useRef, useState, } from "react";
5
5
  import { writeClipboardText } from "../clipboard.js";
6
6
  import { Popover, PopoverAnchor, PopoverContent, PopoverTrigger, } from "../components/ui/popover.js";
7
+ import { useT } from "../i18n.js";
7
8
  import { cn } from "../utils.js";
8
9
  import { useShareButtonController, } from "./useShareButtonController.js";
9
10
  // Match shadcn's <Button size="sm" variant="outline"> sizing so the trigger
@@ -17,46 +18,77 @@ const SHARE_NESTED_OVERLAY_ATTR = "data-agent-native-share-overlay";
17
18
  const SHARE_NESTED_OVERLAY_Z = "z-[100020]";
18
19
  const VIS_META = {
19
20
  private: {
20
- label: "Private",
21
- description: "Only people with access can view",
21
+ labelKey: "agentChat.share.private",
22
+ descriptionKey: "agentChat.share.privateDescription",
23
+ defaultLabel: "Private",
24
+ defaultDescription: "Only people with access can view",
22
25
  Icon: IconLock,
23
26
  },
24
27
  org: {
25
- label: "Organization",
26
- description: "Anyone in your organization can view",
28
+ labelKey: "agentChat.share.organization",
29
+ descriptionKey: "agentChat.share.organizationDescription",
30
+ defaultLabel: "Organization",
31
+ defaultDescription: "Anyone in your organization can view",
27
32
  Icon: IconUsersGroup,
28
33
  },
29
34
  public: {
30
- label: "Public",
31
- description: "Anyone with the link can view",
35
+ labelKey: "agentChat.share.public",
36
+ descriptionKey: "agentChat.share.publicDescription",
37
+ defaultLabel: "Public",
38
+ defaultDescription: "Anyone with the link can view",
32
39
  Icon: IconWorld,
33
40
  },
34
41
  };
35
- function visibilityMeta(visibility, copy) {
42
+ function visibilityMeta(visibility, t, copy) {
36
43
  const base = VIS_META[visibility];
37
44
  const override = copy?.[visibility];
38
45
  return {
39
- ...base,
40
- label: override?.label ?? base.label,
41
- description: override?.description ?? base.description,
46
+ Icon: base.Icon,
47
+ label: override?.label ??
48
+ t(base.labelKey, {
49
+ defaultValue: base.defaultLabel,
50
+ }),
51
+ description: override?.description ??
52
+ t(base.descriptionKey, {
53
+ defaultValue: base.defaultDescription,
54
+ }),
42
55
  };
43
56
  }
44
- const ROLE_OPTIONS = [
45
- { value: "viewer", label: "Viewer", description: "Can view" },
46
- {
47
- value: "commenter",
48
- label: "Commenter",
49
- description: "Can view and add comments",
50
- },
51
- { value: "editor", label: "Editor", description: "Can edit" },
52
- {
53
- value: "admin",
54
- label: "Admin",
55
- description: "Can edit and manage access",
56
- },
57
- ];
58
- function roleMeta(role, copy) {
59
- const base = ROLE_OPTIONS.find((option) => option.value === role) ?? ROLE_OPTIONS[0];
57
+ function roleOptions(t) {
58
+ return [
59
+ {
60
+ value: "viewer",
61
+ label: t("agentChat.share.viewer", { defaultValue: "Viewer" }),
62
+ description: t("agentChat.share.viewerDescription", {
63
+ defaultValue: "Can view",
64
+ }),
65
+ },
66
+ {
67
+ value: "commenter",
68
+ label: t("agentChat.share.commenter", { defaultValue: "Commenter" }),
69
+ description: t("agentChat.share.commenterDescription", {
70
+ defaultValue: "Can view and add comments",
71
+ }),
72
+ },
73
+ {
74
+ value: "editor",
75
+ label: t("agentChat.share.editor", { defaultValue: "Editor" }),
76
+ description: t("agentChat.share.editorDescription", {
77
+ defaultValue: "Can edit",
78
+ }),
79
+ },
80
+ {
81
+ value: "admin",
82
+ label: t("agentChat.share.admin", { defaultValue: "Admin" }),
83
+ description: t("agentChat.share.adminDescription", {
84
+ defaultValue: "Can edit and manage access",
85
+ }),
86
+ },
87
+ ];
88
+ }
89
+ function roleMeta(role, t, copy) {
90
+ const options = roleOptions(t);
91
+ const base = options.find((option) => option.value === role) ?? options[0];
60
92
  const override = copy?.[role];
61
93
  return {
62
94
  ...base,
@@ -81,6 +113,7 @@ function handleSharePopoverInteractOutside(event) {
81
113
  * dark mode in any shadcn template.
82
114
  */
83
115
  export function ShareButton(props) {
116
+ const t = useT();
84
117
  const controller = useShareButtonController({
85
118
  resourceType: props.resourceType,
86
119
  resourceId: props.resourceId,
@@ -93,22 +126,32 @@ export function ShareButton(props) {
93
126
  });
94
127
  const triggerVisibility = controller.triggerVisibility;
95
128
  const triggerMeta = triggerVisibility
96
- ? visibilityMeta(triggerVisibility, props.visibilityCopy)
129
+ ? visibilityMeta(triggerVisibility, t, props.visibilityCopy)
97
130
  : null;
98
131
  const TriggerIcon = triggerMeta?.Icon ?? IconShare3;
99
132
  const iconOnly = props.trigger === "icon";
100
133
  const showTriggerIcon = iconOnly || props.trigger === "label-icon";
101
- const triggerLabel = iconOnly && triggerMeta ? `Share (${triggerMeta.label})` : "Share";
102
- return (_jsxs(Popover, { open: controller.open, onOpenChange: controller.handleOpenChange, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("button", { type: "button", className: cn(iconOnly ? BUTTON_GHOST_ICON : BUTTON_OUTLINE_SM, props.triggerClassName), "aria-label": triggerLabel, title: triggerLabel, children: [showTriggerIcon && _jsx(TriggerIcon, { size: 16, strokeWidth: 1.75 }), !iconOnly && _jsx("span", { children: "Share" })] }) }), _jsx(PopoverContent, { align: "end", sideOffset: 6, "data-agent-native-share-overlay": "", className: cn("z-[2000] w-[min(460px,92vw)] rounded-lg p-4 shadow-lg", SHARE_POPOVER_SURFACE, props.popoverClassName), onOpenAutoFocus: (e) => e.preventDefault(), onInteractOutside: handleSharePopoverInteractOutside, children: _jsx(SharePanel, { ...props, controller: controller }) })] }));
134
+ const triggerLabel = iconOnly && triggerMeta
135
+ ? t("agentChat.share.triggerWithVisibility", {
136
+ defaultValue: "Share ({{visibility}})",
137
+ visibility: triggerMeta.label,
138
+ })
139
+ : t("agentChat.share.share", { defaultValue: "Share" });
140
+ return (_jsxs(Popover, { open: controller.open, onOpenChange: controller.handleOpenChange, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("button", { type: "button", className: cn(iconOnly ? BUTTON_GHOST_ICON : BUTTON_OUTLINE_SM, props.triggerClassName), "aria-label": triggerLabel, title: triggerLabel, children: [showTriggerIcon && _jsx(TriggerIcon, { size: 16, strokeWidth: 1.75 }), !iconOnly && (_jsx("span", { children: t("agentChat.share.share", { defaultValue: "Share" }) }))] }) }), _jsx(PopoverContent, { align: "end", sideOffset: 6, "data-agent-native-share-overlay": "", className: cn("z-[2000] w-[min(460px,92vw)] rounded-lg p-4 shadow-lg", SHARE_POPOVER_SURFACE, props.popoverClassName), onOpenAutoFocus: (e) => e.preventDefault(), onInteractOutside: handleSharePopoverInteractOutside, children: _jsx(SharePanel, { ...props, controller: controller }) })] }));
103
141
  }
104
142
  function SharePanel(props) {
143
+ const t = useT();
105
144
  const { controller } = props;
106
145
  const { inviteEmail, setInviteEmail: onInviteEmailChange, activeShareTab, handleShareTabChange, data, policy, visibility, canManage, role, setRole, notifyPeople, setNotifyPeople, shareMessage, setShareMessage, messageOpen, setMessageOpen, shareError, setShareError, suggestionsOpen, setSuggestionsOpen, inFlight, memberSearch, memberSuggestions, knownMembers, shares, handleVisibility, handleHideInSearch, handleAdd, handleChangeRole, handleRemove, } = controller;
107
146
  const hasInviteEmail = inviteEmail.trim().length > 0;
108
147
  const isLoading = data === undefined;
109
- const meta = visibilityMeta(visibility, props.visibilityCopy);
110
- const peopleAccessLabel = props.peopleAccessLabel ?? "People with access";
111
- const generalAccessLabel = props.generalAccessLabel ?? "General access";
148
+ const meta = visibilityMeta(visibility, t, props.visibilityCopy);
149
+ const peopleAccessLabel = props.peopleAccessLabel ??
150
+ t("agentChat.share.peopleWithAccess", {
151
+ defaultValue: "People with access",
152
+ });
153
+ const generalAccessLabel = props.generalAccessLabel ??
154
+ t("agentChat.share.generalAccess", { defaultValue: "General access" });
112
155
  const shareLinks = (_jsxs(_Fragment, { children: [props.shareUrl ? (_jsx(CopyLinkField, { value: props.shareUrl, label: props.shareUrlLabel, description: props.shareUrlDescription })) : props.shareUrlPlaceholder ? (_jsxs("div", { className: "mb-4 rounded-md border border-dashed border-border bg-muted/20 px-3 py-2.5 text-xs text-muted-foreground", children: [props.shareUrlLabel ? (_jsx("div", { className: "mb-0.5 font-medium text-foreground", children: props.shareUrlLabel })) : null, props.shareUrlPlaceholder] })) : null, props.secondaryShareUrl ? (_jsx(CopyLinkField, { value: props.secondaryShareUrl, label: props.secondaryShareUrlLabel, description: props.secondaryShareUrlDescription })) : null] }));
113
156
  const showShareLinks = (props.showShareLinks ?? true) &&
114
157
  (Boolean(props.shareUrl) ||
@@ -117,7 +160,8 @@ function SharePanel(props) {
117
160
  const shareUrlPlacement = props.shareUrlPlacement ?? "top";
118
161
  const extraTabs = props.shareTabs?.tabs.filter((tab) => tab.value !== "context") ?? [];
119
162
  const hasTabs = extraTabs.length > 0;
120
- const shareTabLabel = props.shareTabs?.shareLabel ?? "Share link";
163
+ const shareTabLabel = props.shareTabs?.shareLabel ??
164
+ t("agentChat.share.shareLink", { defaultValue: "Share link" });
121
165
  const sharePanel = isLoading ? (_jsxs("div", { children: [showShareLinks ? (_jsx("div", { className: "mb-4 h-9 rounded-md bg-muted animate-pulse" })) : null, _jsx("div", { className: "mb-2 text-sm font-semibold", children: generalAccessLabel }), _jsx("div", { className: "mb-4 h-9 rounded-md bg-muted animate-pulse" }), _jsx("div", { className: "mb-2 text-sm font-semibold", children: peopleAccessLabel }), _jsx("div", { className: "mb-4 h-7 rounded-md bg-muted animate-pulse" })] })) : (_jsxs("div", { children: [showShareLinks && shareUrlPlacement === "top" ? shareLinks : null, _jsxs("div", { className: "mb-4", children: [_jsx("div", { className: "mb-2 text-sm font-semibold", children: generalAccessLabel }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("span", { "aria-hidden": true, className: "inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-muted text-muted-foreground", children: _jsx(meta.Icon, { size: 16, strokeWidth: 1.75 }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx(VisibilitySelect, { value: visibility, onChange: handleVisibility, disabled: !canManage, visibilityCopy: props.visibilityCopy, allowPublic: policy.allowPublic }), _jsxs("div", { className: "mt-0.5 flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-muted-foreground", children: [_jsx("span", { className: "sr-only", children: meta.description }), visibility === "org" && props.hideInSearchControl ? (_jsx(AdvancedAccessPopover, { control: props.hideInSearchControl, canManage: canManage, onToggle: handleHideInSearch })) : null] })] })] })] }), _jsxs("div", { className: "mb-4 space-y-4", children: [_jsx("div", { className: "text-sm font-semibold", children: peopleAccessLabel }), canManage ? (_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-stretch gap-2", children: [_jsx(MemberAutocomplete, { value: inviteEmail, open: suggestionsOpen, onOpenChange: setSuggestionsOpen, onValueChange: (next) => {
122
166
  onInviteEmailChange(next);
123
167
  if (shareError)
@@ -128,8 +172,28 @@ function SharePanel(props) {
128
172
  if (shareError)
129
173
  setShareError(null);
130
174
  }, onSubmit: handleAdd, placeholder: policy.requireOrgMemberForUserShares
131
- ? "Add people from your organization"
132
- : "Add people by email", suggestions: memberSuggestions, search: memberSearch }), _jsx(RoleSelect, { value: role, onChange: setRole, roleCopy: props.roleCopy, allowedRoles: props.allowedRoles }), _jsx("button", { type: "button", onClick: handleAdd, disabled: !hasInviteEmail, className: BUTTON_PRIMARY_SM, children: "Add" })] }), shareError ? (_jsx("div", { role: "alert", className: "rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive", children: shareError })) : null, hasInviteEmail ? (_jsxs("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-2 text-xs text-muted-foreground", children: [_jsxs("label", { className: "inline-flex items-center gap-2", children: [_jsx("input", { type: "checkbox", checked: notifyPeople, onChange: (e) => setNotifyPeople(e.target.checked), className: "h-4 w-4 rounded border-input accent-primary" }), "Notify people"] }), notifyPeople ? (_jsx("button", { type: "button", "aria-expanded": messageOpen, onClick: () => setMessageOpen(!messageOpen), className: "rounded-sm px-1 py-0.5 font-medium text-foreground underline decoration-border underline-offset-2 transition-colors hover:bg-accent hover:text-accent-foreground", children: messageOpen ? "Hide message" : "Add a message" })) : null] })) : null, hasInviteEmail && notifyPeople && messageOpen ? (_jsx("div", { className: "rounded-md border border-border/70 bg-muted/20 p-2.5", children: _jsx("textarea", { "aria-label": "Message", placeholder: "Add a short note (optional)", value: shareMessage, onChange: (event) => setShareMessage(event.target.value), maxLength: 500, rows: 3, className: "w-full resize-y rounded-md border border-input bg-card px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:ring-offset-background" }) })) : null] })) : null, _jsxs("ul", { className: "flex list-none flex-col gap-1 p-0 m-0", children: [data?.ownerEmail ? (_jsxs("li", { className: "flex items-center gap-3 px-1 py-1.5 text-sm", children: [_jsx(Avatar, { label: displayName(data.ownerEmail, knownMembers) }), _jsx("span", { className: "flex-1 min-w-0 truncate", children: displayName(data.ownerEmail, knownMembers) }), _jsx("span", { className: "text-xs text-muted-foreground", children: "Owner" })] })) : null, shares.map((s) => (_jsxs("li", { className: cn("flex items-center gap-3 px-1 py-1.5 text-sm", inFlight.has(keyOf(s)) && "opacity-60"), children: [_jsx(Avatar, { label: principalLabel(s, knownMembers), org: s.principalType === "org" }), _jsx("span", { className: "flex-1 min-w-0 truncate", children: principalLabel(s, knownMembers) }), canManage ? (_jsx(RoleSelect, { value: s.role, onChange: (r) => handleChangeRole(s, r), disabled: inFlight.has(keyOf(s)), plain: true, roleCopy: props.roleCopy, allowedRoles: props.allowedRoles })) : (_jsx("span", { className: "text-xs text-muted-foreground", children: roleMeta(s.role, props.roleCopy).label })), canManage ? (_jsx("button", { type: "button", "aria-label": "Remove", onClick: () => handleRemove(s), disabled: inFlight.has(keyOf(s)), className: BUTTON_GHOST_ICON, children: _jsx(IconTrash, { size: 14 }) })) : null] }, keyOf(s)))), !shares.length && !data?.ownerEmail ? (_jsx("li", { className: "px-1 py-1.5 text-sm text-muted-foreground", children: "No one has access yet." })) : null] })] }), shareError && !canManage ? (_jsx("div", { role: "alert", className: "mb-4 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive", children: shareError })) : null, props.accessNote ? (_jsx("div", { className: "mb-4 rounded-md border border-border bg-muted/35 p-3 text-xs text-muted-foreground", children: props.accessNote })) : null, showShareLinks && shareUrlPlacement === "bottom" ? shareLinks : null, props.shareFooterContent] }));
175
+ ? t("agentChat.share.addPeopleOrganization", {
176
+ defaultValue: "Add people from your organization",
177
+ })
178
+ : t("agentChat.share.addPeopleEmail", {
179
+ defaultValue: "Add people by email",
180
+ }), suggestions: memberSuggestions, search: memberSearch }), _jsx(RoleSelect, { value: role, onChange: setRole, roleCopy: props.roleCopy, allowedRoles: props.allowedRoles }), _jsx("button", { type: "button", onClick: handleAdd, disabled: !hasInviteEmail, className: BUTTON_PRIMARY_SM, children: t("agentChat.share.add", { defaultValue: "Add" }) })] }), shareError ? (_jsx("div", { role: "alert", className: "rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive", children: shareError })) : null, hasInviteEmail ? (_jsxs("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-2 text-xs text-muted-foreground", children: [_jsxs("label", { className: "inline-flex items-center gap-2", children: [_jsx("input", { type: "checkbox", checked: notifyPeople, onChange: (e) => setNotifyPeople(e.target.checked), className: "h-4 w-4 rounded border-input accent-primary" }), t("agentChat.share.notifyPeople", {
181
+ defaultValue: "Notify people",
182
+ })] }), notifyPeople ? (_jsx("button", { type: "button", "aria-expanded": messageOpen, onClick: () => setMessageOpen(!messageOpen), className: "rounded-sm px-1 py-0.5 font-medium text-foreground underline decoration-border underline-offset-2 transition-colors hover:bg-accent hover:text-accent-foreground", children: messageOpen
183
+ ? t("agentChat.share.hideMessage", {
184
+ defaultValue: "Hide message",
185
+ })
186
+ : t("agentChat.share.addMessage", {
187
+ defaultValue: "Add a message",
188
+ }) })) : null] })) : null, hasInviteEmail && notifyPeople && messageOpen ? (_jsx("div", { className: "rounded-md border border-border/70 bg-muted/20 p-2.5", children: _jsx("textarea", { "aria-label": t("agentChat.share.message", {
189
+ defaultValue: "Message",
190
+ }), placeholder: t("agentChat.share.messagePlaceholder", {
191
+ defaultValue: "Add a short note (optional)",
192
+ }), value: shareMessage, onChange: (event) => setShareMessage(event.target.value), maxLength: 500, rows: 3, className: "w-full resize-y rounded-md border border-input bg-card px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:ring-offset-background" }) })) : null] })) : null, _jsxs("ul", { className: "flex list-none flex-col gap-1 p-0 m-0", children: [data?.ownerEmail ? (_jsxs("li", { className: "flex items-center gap-3 px-1 py-1.5 text-sm", children: [_jsx(Avatar, { label: displayName(data.ownerEmail, knownMembers, t) }), _jsx("span", { className: "flex-1 min-w-0 truncate", children: displayName(data.ownerEmail, knownMembers, t) }), _jsx("span", { className: "text-xs text-muted-foreground", children: t("agentChat.share.owner", { defaultValue: "Owner" }) })] })) : null, shares.map((s) => (_jsxs("li", { className: cn("flex items-center gap-3 px-1 py-1.5 text-sm", inFlight.has(keyOf(s)) && "opacity-60"), children: [_jsx(Avatar, { label: principalLabel(s, knownMembers, t), org: s.principalType === "org" }), _jsx("span", { className: "flex-1 min-w-0 truncate", children: principalLabel(s, knownMembers, t) }), canManage ? (_jsx(RoleSelect, { value: s.role, onChange: (r) => handleChangeRole(s, r), disabled: inFlight.has(keyOf(s)), plain: true, roleCopy: props.roleCopy, allowedRoles: props.allowedRoles })) : (_jsx("span", { className: "text-xs text-muted-foreground", children: roleMeta(s.role, t, props.roleCopy).label })), canManage ? (_jsx("button", { type: "button", "aria-label": t("agentChat.share.remove", {
193
+ defaultValue: "Remove",
194
+ }), onClick: () => handleRemove(s), disabled: inFlight.has(keyOf(s)), className: BUTTON_GHOST_ICON, children: _jsx(IconTrash, { size: 14 }) })) : null] }, keyOf(s)))), !shares.length && !data?.ownerEmail ? (_jsx("li", { className: "px-1 py-1.5 text-sm text-muted-foreground", children: t("agentChat.share.noAccess", {
195
+ defaultValue: "No one has access yet.",
196
+ }) })) : null] })] }), shareError && !canManage ? (_jsx("div", { role: "alert", className: "mb-4 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive", children: shareError })) : null, props.accessNote ? (_jsx("div", { className: "mb-4 rounded-md border border-border bg-muted/35 p-3 text-xs text-muted-foreground", children: props.accessNote })) : null, showShareLinks && shareUrlPlacement === "bottom" ? shareLinks : null, props.shareFooterContent] }));
133
197
  if (!hasTabs)
134
198
  return sharePanel;
135
199
  const tabs = [
@@ -144,17 +208,30 @@ function SharePanel(props) {
144
208
  const activeTab = tabs.some((tab) => tab.value === activeShareTab)
145
209
  ? activeShareTab
146
210
  : "share";
147
- return (_jsxs("div", { className: "flex flex-col gap-4", children: [_jsx("div", { role: "tablist", "aria-label": "Share options", className: "flex gap-1 rounded-xl bg-muted/70 p-1", children: tabs.map((tab) => {
211
+ return (_jsxs("div", { className: "flex flex-col gap-4", children: [_jsx("div", { role: "tablist", "aria-label": t("agentChat.share.shareOptions", {
212
+ defaultValue: "Share options",
213
+ }), className: "flex gap-1 rounded-xl bg-muted/70 p-1", children: tabs.map((tab) => {
148
214
  const active = tab.value === activeTab;
149
215
  return (_jsx("button", { type: "button", role: "tab", "aria-selected": active, disabled: tab.disabled, onClick: () => handleShareTabChange(tab.value), className: cn("h-11 min-w-0 flex-1 rounded-lg px-3 text-sm font-medium text-muted-foreground transition-colors hover:bg-background/70 hover:text-foreground disabled:pointer-events-none disabled:opacity-50", active &&
150
216
  "bg-background text-foreground shadow-sm ring-2 ring-primary"), children: _jsx("span", { className: "block truncate", children: tab.label }) }, tab.value));
151
217
  }) }), _jsx("div", { role: "tabpanel", children: tabs.find((tab) => tab.value === activeTab)?.content })] }));
152
218
  }
153
219
  function AdvancedAccessPopover({ control, canManage, onToggle, }) {
154
- return (_jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("button", { type: "button", disabled: !canManage, className: "inline-flex items-center gap-1 rounded-sm px-1 py-0.5 text-xs font-medium text-muted-foreground transition-colors hover:bg-accent hover:text-foreground disabled:cursor-not-allowed disabled:opacity-50", children: ["Advanced", _jsx(IconChevronDown, { size: 12, strokeWidth: 1.8 })] }) }), _jsx(PopoverContent, { align: "start", sideOffset: 6, "data-agent-native-share-overlay": "", onOpenAutoFocus: (event) => event.preventDefault(), className: cn(SHARE_NESTED_OVERLAY_Z, "w-72 p-3 shadow-lg", SHARE_POPOVER_SURFACE), children: _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { children: [_jsx("div", { className: "text-sm font-medium text-foreground", children: "Advanced access" }), _jsx("div", { className: "mt-1 text-xs leading-5 text-muted-foreground", children: "Control how organization access appears in search." })] }), _jsxs("button", { type: "button", role: "switch", "aria-checked": control.checked, disabled: !canManage || control.pending, onClick: onToggle, className: cn("flex w-full items-start gap-3 rounded-md border border-border/70 bg-card px-3 py-2.5 text-start transition-colors hover:bg-accent/45 disabled:cursor-not-allowed disabled:opacity-60", control.checked && "border-border bg-accent/35 text-foreground"), children: [_jsx("span", { "aria-hidden": true, className: cn("relative mt-0.5 inline-flex h-5 w-9 shrink-0 items-center rounded-full border border-border bg-muted-foreground/25 transition-colors", control.checked && "border-primary/70 bg-primary"), children: _jsx("span", { className: cn("ml-0.5 size-4 rounded-full bg-popover shadow-sm transition-transform", control.checked && "translate-x-4") }) }), _jsxs("span", { className: "min-w-0 flex-1", children: [_jsxs("span", { className: "flex items-center gap-1.5 text-sm font-medium text-foreground", children: [_jsx(IconSearchOff, { size: 14, strokeWidth: 1.8 }), control.label ?? "Hide in search"] }), _jsx("span", { className: "mt-0.5 block text-xs leading-5 text-muted-foreground", children: control.description ??
155
- "People with the link can still open this." })] })] })] }) })] }));
220
+ const t = useT();
221
+ return (_jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("button", { type: "button", disabled: !canManage, className: "inline-flex items-center gap-1 rounded-sm px-1 py-0.5 text-xs font-medium text-muted-foreground transition-colors hover:bg-accent hover:text-foreground disabled:cursor-not-allowed disabled:opacity-50", children: [t("agentChat.share.advanced", { defaultValue: "Advanced" }), _jsx(IconChevronDown, { size: 12, strokeWidth: 1.8 })] }) }), _jsx(PopoverContent, { align: "start", sideOffset: 6, "data-agent-native-share-overlay": "", onOpenAutoFocus: (event) => event.preventDefault(), className: cn(SHARE_NESTED_OVERLAY_Z, "w-72 p-3 shadow-lg", SHARE_POPOVER_SURFACE), children: _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { children: [_jsx("div", { className: "text-sm font-medium text-foreground", children: t("agentChat.share.advancedAccess", {
222
+ defaultValue: "Advanced access",
223
+ }) }), _jsx("div", { className: "mt-1 text-xs leading-5 text-muted-foreground", children: t("agentChat.share.advancedDescription", {
224
+ defaultValue: "Control how organization access appears in search.",
225
+ }) })] }), _jsxs("button", { type: "button", role: "switch", "aria-checked": control.checked, disabled: !canManage || control.pending, onClick: onToggle, className: cn("flex w-full items-start gap-3 rounded-md border border-border/70 bg-card px-3 py-2.5 text-start transition-colors hover:bg-accent/45 disabled:cursor-not-allowed disabled:opacity-60", control.checked && "border-border bg-accent/35 text-foreground"), children: [_jsx("span", { "aria-hidden": true, className: cn("relative mt-0.5 inline-flex h-5 w-9 shrink-0 items-center rounded-full border border-border bg-muted-foreground/25 transition-colors", control.checked && "border-primary/70 bg-primary"), children: _jsx("span", { className: cn("ml-0.5 size-4 rounded-full bg-popover shadow-sm transition-transform", control.checked && "translate-x-4") }) }), _jsxs("span", { className: "min-w-0 flex-1", children: [_jsxs("span", { className: "flex items-center gap-1.5 text-sm font-medium text-foreground", children: [_jsx(IconSearchOff, { size: 14, strokeWidth: 1.8 }), control.label ??
226
+ t("agentChat.share.hideInSearch", {
227
+ defaultValue: "Hide in search",
228
+ })] }), _jsx("span", { className: "mt-0.5 block text-xs leading-5 text-muted-foreground", children: control.description ??
229
+ t("agentChat.share.linkCanStillOpen", {
230
+ defaultValue: "People with the link can still open this.",
231
+ }) })] })] })] }) })] }));
156
232
  }
157
233
  function MemberAutocomplete({ value, open, onOpenChange, onValueChange, onSelectMember, onSubmit, placeholder, suggestions, search, }) {
234
+ const t = useT();
158
235
  const rawListboxId = useId();
159
236
  const listboxId = rawListboxId.replace(/:/g, "");
160
237
  const inputRef = useRef(null);
@@ -247,12 +324,23 @@ function MemberAutocomplete({ value, open, onOpenChange, onValueChange, onSelect
247
324
  return (_jsxs("div", { id: optionId(listboxId, index), role: "option", "aria-selected": active, onMouseDown: (event) => event.preventDefault(), onMouseEnter: () => setActiveIndex(index), onClick: () => chooseMember(member), className: cn("flex cursor-pointer select-none flex-col rounded-sm px-3 py-2 text-sm outline-none", active
248
325
  ? "bg-accent text-accent-foreground"
249
326
  : "text-foreground hover:bg-accent hover:text-accent-foreground"), children: [_jsx("span", { className: "truncate font-medium", children: member.name?.trim() || member.email }), member.name?.trim() ? (_jsx("span", { className: "truncate text-xs text-muted-foreground", children: member.email })) : null] }, member.email));
250
- }), search.isLoading && suggestions.length === 0 ? (_jsx("div", { className: "px-3 py-3 text-sm text-muted-foreground", children: "Searching..." })) : null, search.error ? (_jsx("div", { className: "px-3 py-3 text-sm text-muted-foreground", children: "Could not load people." })) : null, !search.isLoading && !search.error && suggestions.length === 0 ? (_jsx("div", { className: "px-3 py-3 text-sm text-muted-foreground", children: value.trim() ? "No matches." : "No people found." })) : null, search.isLoadingMore ? (_jsxs("div", { className: "flex items-center gap-2 px-3 py-2 text-sm text-muted-foreground", children: [_jsx(IconLoader2, { "aria-hidden": true, size: 14, strokeWidth: 1.8, className: "animate-spin" }), "Loading..."] })) : null, search.hasMore && !search.isLoadingMore ? (_jsx("button", { type: "button", onMouseDown: (event) => event.preventDefault(), onClick: search.loadMore, className: "mt-1 flex w-full items-center justify-center rounded-sm px-3 py-2 text-sm font-medium text-muted-foreground hover:bg-accent hover:text-accent-foreground", children: "Load more" })) : null] }) })] }));
327
+ }), search.isLoading && suggestions.length === 0 ? (_jsx("div", { className: "px-3 py-3 text-sm text-muted-foreground", children: t("agentChat.share.searching", {
328
+ defaultValue: "Searching...",
329
+ }) })) : null, search.error ? (_jsx("div", { className: "px-3 py-3 text-sm text-muted-foreground", children: t("agentChat.share.loadPeopleFailed", {
330
+ defaultValue: "Could not load people.",
331
+ }) })) : null, !search.isLoading && !search.error && suggestions.length === 0 ? (_jsx("div", { className: "px-3 py-3 text-sm text-muted-foreground", children: value.trim()
332
+ ? t("agentChat.share.noMatches", {
333
+ defaultValue: "No matches.",
334
+ })
335
+ : t("agentChat.share.noPeopleFound", {
336
+ defaultValue: "No people found.",
337
+ }) })) : null, search.isLoadingMore ? (_jsxs("div", { className: "flex items-center gap-2 px-3 py-2 text-sm text-muted-foreground", children: [_jsx(IconLoader2, { "aria-hidden": true, size: 14, strokeWidth: 1.8, className: "animate-spin" }), t("agentChat.share.loading", { defaultValue: "Loading..." })] })) : null, search.hasMore && !search.isLoadingMore ? (_jsx("button", { type: "button", onMouseDown: (event) => event.preventDefault(), onClick: search.loadMore, className: "mt-1 flex w-full items-center justify-center rounded-sm px-3 py-2 text-sm font-medium text-muted-foreground hover:bg-accent hover:text-accent-foreground", children: t("agentChat.share.loadMore", { defaultValue: "Load more" }) })) : null] }) })] }));
251
338
  }
252
339
  function optionId(baseId, index) {
253
340
  return `${baseId}-option-${index}`;
254
341
  }
255
- function CopyLinkField({ value, label = "Share link", description, }) {
342
+ function CopyLinkField({ value, label, description, }) {
343
+ const t = useT();
256
344
  const [copied, setCopied] = useState(false);
257
345
  const resetRef = useRef(undefined);
258
346
  useEffect(() => {
@@ -272,7 +360,12 @@ function CopyLinkField({ value, label = "Share link", description, }) {
272
360
  setCopied(false);
273
361
  }
274
362
  };
275
- return (_jsxs("div", { className: "mb-4 flex items-center justify-between gap-4", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "text-sm font-semibold", children: label }), description ? (_jsx("div", { className: "mt-1 text-xs text-muted-foreground", children: description })) : null] }), _jsxs("button", { type: "button", onClick: handleCopy, "aria-label": copied ? "Link copied" : "Copy", className: "inline-flex h-9 shrink-0 items-center gap-2 whitespace-nowrap rounded-md border border-input bg-card px-3 text-sm font-medium text-foreground hover:bg-accent", children: [copied ? _jsx(IconCheck, { size: 15 }) : _jsx(IconLink, { size: 15 }), copied ? "Copied" : "Copy"] })] }));
363
+ return (_jsxs("div", { className: "mb-4 flex items-center justify-between gap-4", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "text-sm font-semibold", children: label ??
364
+ t("agentChat.share.shareLink", { defaultValue: "Share link" }) }), description ? (_jsx("div", { className: "mt-1 text-xs text-muted-foreground", children: description })) : null] }), _jsxs("button", { type: "button", onClick: handleCopy, "aria-label": copied
365
+ ? t("agentChat.share.copied", { defaultValue: "Copied" })
366
+ : t("agentChat.share.copy", { defaultValue: "Copy" }), className: "inline-flex h-9 shrink-0 items-center gap-2 whitespace-nowrap rounded-md border border-input bg-card px-3 text-sm font-medium text-foreground hover:bg-accent", children: [copied ? _jsx(IconCheck, { size: 15 }) : _jsx(IconLink, { size: 15 }), copied
367
+ ? t("agentChat.share.copied", { defaultValue: "Copied" })
368
+ : t("agentChat.share.copy", { defaultValue: "Copy" })] })] }));
276
369
  }
277
370
  // ---------------------------------------------------------------------------
278
371
  // Radix Select wrappers styled like shadcn Select (no native <select> anywhere)
@@ -283,17 +376,22 @@ function SelectItems({ items }) {
283
376
  return (_jsx(_Fragment, { children: items.map((it) => (_jsxs(Select.Item, { value: it.value, className: selectItemClass, children: [_jsx("span", { className: "absolute start-2 top-2 flex h-4 w-4 items-center justify-center", children: _jsx(Select.ItemIndicator, { children: _jsx(IconCheck, { size: 14 }) }) }), _jsxs("span", { className: "flex flex-col", children: [_jsx(Select.ItemText, { children: it.label }), it.description ? (_jsx("span", { className: "text-xs text-muted-foreground", children: it.description })) : null] })] }, it.value))) }));
284
377
  }
285
378
  function RoleSelect(props) {
286
- const current = roleMeta(props.value, props.roleCopy);
287
- const allowedRoles = props.allowedRoles ?? ROLE_OPTIONS.map((item) => item.value);
288
- const options = ROLE_OPTIONS.filter((option) => option.value === props.value || allowedRoles.includes(option.value)).map((option) => roleMeta(option.value, props.roleCopy));
379
+ const t = useT();
380
+ const allOptions = roleOptions(t);
381
+ const current = roleMeta(props.value, t, props.roleCopy);
382
+ const allowedRoles = props.allowedRoles ?? allOptions.map((item) => item.value);
383
+ const options = allOptions
384
+ .filter((option) => option.value === props.value || allowedRoles.includes(option.value))
385
+ .map((option) => roleMeta(option.value, t, props.roleCopy));
289
386
  return (_jsxs(Select.Root, { value: props.value, onValueChange: (v) => props.onChange(v), disabled: props.disabled, children: [_jsxs(Select.Trigger, { className: props.plain
290
387
  ? cn(BUTTON_BASE, "h-7 px-2 bg-transparent text-muted-foreground hover:bg-accent hover:text-accent-foreground")
291
- : cn(BUTTON_BASE, "h-9 px-3 border border-input bg-card hover:bg-accent hover:text-accent-foreground"), "aria-label": "Role", children: [_jsx(Select.Value, { children: current.label }), _jsx(Select.Icon, { children: _jsx(IconChevronDown, { size: 14 }) })] }), _jsx(Select.Portal, { children: _jsx(Select.Content, { "data-agent-native-share-overlay": "", className: selectContentClass, position: "popper", sideOffset: 4, children: _jsx(Select.Viewport, { children: _jsx(SelectItems, { items: options }) }) }) })] }));
388
+ : cn(BUTTON_BASE, "h-9 px-3 border border-input bg-card hover:bg-accent hover:text-accent-foreground"), "aria-label": t("agentChat.share.role", { defaultValue: "Role" }), children: [_jsx(Select.Value, { children: current.label }), _jsx(Select.Icon, { children: _jsx(IconChevronDown, { size: 14 }) })] }), _jsx(Select.Portal, { children: _jsx(Select.Content, { "data-agent-native-share-overlay": "", className: selectContentClass, position: "popper", sideOffset: 4, children: _jsx(Select.Viewport, { children: _jsx(SelectItems, { items: options }) }) }) })] }));
292
389
  }
293
390
  function VisibilitySelect(props) {
391
+ const t = useT();
294
392
  const allowPrivate = props.allowPrivate !== false;
295
393
  const allowPublic = props.allowPublic !== false;
296
- const current = visibilityMeta(props.value, props.visibilityCopy);
394
+ const current = visibilityMeta(props.value, t, props.visibilityCopy);
297
395
  const options = Object.keys(VIS_META).filter((k) => {
298
396
  if (k === props.value)
299
397
  return true;
@@ -303,10 +401,12 @@ function VisibilitySelect(props) {
303
401
  return false;
304
402
  return true;
305
403
  });
306
- return (_jsxs(Select.Root, { value: props.value, onValueChange: (v) => props.onChange(v), disabled: props.disabled, children: [_jsxs(Select.Trigger, { className: cn(BUTTON_BASE, "h-7 px-1 -ms-1 bg-transparent text-foreground hover:bg-accent hover:text-accent-foreground"), "aria-label": "General access", children: [_jsx(Select.Value, { children: current.label }), _jsx(Select.Icon, { children: _jsx(IconChevronDown, { size: 14 }) })] }), _jsx(Select.Portal, { children: _jsx(Select.Content, { "data-agent-native-share-overlay": "", className: selectContentClass, position: "popper", sideOffset: 4, children: _jsx(Select.Viewport, { children: _jsx(SelectItems, { items: options.map((k) => ({
404
+ return (_jsxs(Select.Root, { value: props.value, onValueChange: (v) => props.onChange(v), disabled: props.disabled, children: [_jsxs(Select.Trigger, { className: cn(BUTTON_BASE, "h-7 px-1 -ms-1 bg-transparent text-foreground hover:bg-accent hover:text-accent-foreground"), "aria-label": t("agentChat.share.generalAccess", {
405
+ defaultValue: "General access",
406
+ }), children: [_jsx(Select.Value, { children: current.label }), _jsx(Select.Icon, { children: _jsx(IconChevronDown, { size: 14 }) })] }), _jsx(Select.Portal, { children: _jsx(Select.Content, { "data-agent-native-share-overlay": "", className: selectContentClass, position: "popper", sideOffset: 4, children: _jsx(Select.Viewport, { children: _jsx(SelectItems, { items: options.map((k) => ({
307
407
  value: k,
308
- label: visibilityMeta(k, props.visibilityCopy).label,
309
- description: visibilityMeta(k, props.visibilityCopy)
408
+ label: visibilityMeta(k, t, props.visibilityCopy).label,
409
+ description: visibilityMeta(k, t, props.visibilityCopy)
310
410
  .description,
311
411
  })) }) }) }) })] }));
312
412
  }
@@ -320,18 +420,24 @@ function initials(s) {
320
420
  const name = s.split("@")[0] ?? s;
321
421
  return (name[0] ?? "?").toUpperCase();
322
422
  }
323
- function principalLabel(share, members) {
423
+ function principalLabel(share, members, t) {
324
424
  const serverLabel = share.displayName?.trim();
325
425
  if (serverLabel)
326
426
  return serverLabel;
327
427
  if (share.principalType === "org")
328
- return "Organization";
329
- return displayName(share.principalId, members);
428
+ return t("agentChat.share.organization", {
429
+ defaultValue: "Organization",
430
+ });
431
+ return displayName(share.principalId, members, t);
330
432
  }
331
- function displayName(emailOrId, members) {
433
+ function displayName(emailOrId, members, t) {
332
434
  const normalized = emailOrId.trim().toLowerCase();
333
435
  const match = members.find((m) => m.email.toLowerCase() === normalized);
334
436
  if (match?.name && match.name.trim())
335
437
  return match.name;
336
- return normalized.includes("@") ? emailOrId : "Unknown person";
438
+ return normalized.includes("@")
439
+ ? emailOrId
440
+ : t("agentChat.share.unknownPerson", {
441
+ defaultValue: "Unknown person",
442
+ });
337
443
  }
@@ -30,7 +30,7 @@
30
30
  */
31
31
  import crypto from "node:crypto";
32
32
  import http from "node:http";
33
- import { getRequestUserEmail } from "../server/request-context.js";
33
+ import { getRequestRunContext, getRequestUserEmail, } from "../server/request-context.js";
34
34
  import { failExpiredSandboxExecution, getSandboxExecutionForOwner, } from "./sandbox/executions-store.js";
35
35
  import { BACKGROUND_DEFAULT_TIMEOUT_MS, BACKGROUND_MAX_TIMEOUT_MS, SANDBOX_EXECUTION_REDRIVE_AFTER_MS, driveSandboxExecution, enqueueSandboxExecution, getSandboxAdapter, isQueuedSandboxAdapter, registerSandboxExecutionRunner, resolveExecutionSandboxAdapter, } from "./sandbox/index.js";
36
36
  const DEFAULT_TIMEOUT_MS = 120_000;
@@ -289,6 +289,7 @@ async function enqueueBackgroundRunCode(input) {
289
289
  owner,
290
290
  orgId: input.context?.orgId ?? null,
291
291
  threadId: input.context?.threadId ?? null,
292
+ allowedActionNames: getRequestRunContext()?.allowedActionNames,
292
293
  });
293
294
  const hasGetTool = Boolean(input.getActions()["get-code-execution"]);
294
295
  return JSON.stringify({
@@ -96,6 +96,7 @@ export interface EnqueueSandboxExecutionInput {
96
96
  owner: string;
97
97
  orgId?: string | null;
98
98
  threadId?: string | null;
99
+ allowedActionNames?: readonly string[];
99
100
  }
100
101
  export interface EnqueueSandboxExecutionResult {
101
102
  execution: SandboxExecutionRow;
@@ -106,6 +106,7 @@ export async function enqueueSandboxExecution(input) {
106
106
  code: input.code,
107
107
  timeoutMs: input.timeoutMs,
108
108
  maxOutputChars: input.maxOutputChars,
109
+ allowedActionNames: input.allowedActionNames,
109
110
  });
110
111
  let driveNote;
111
112
  try {
@@ -201,7 +202,13 @@ export async function processQueuedSandboxExecution(executionId) {
201
202
  threadId: claimed.threadId ?? undefined,
202
203
  actionName: "run-code",
203
204
  };
204
- const output = await runWithRequestContext({ userEmail: claimed.owner, orgId: claimed.orgId ?? undefined }, () => runner.execute({
205
+ const output = await runWithRequestContext({
206
+ userEmail: claimed.owner,
207
+ orgId: claimed.orgId ?? undefined,
208
+ run: claimed.allowedActionNames === undefined
209
+ ? undefined
210
+ : { allowedActionNames: claimed.allowedActionNames },
211
+ }, () => runner.execute({
205
212
  code: claimed.code,
206
213
  timeoutMs: claimed.timeoutMs,
207
214
  context,
@@ -51,6 +51,7 @@ export interface SandboxExecutionRow {
51
51
  timedOut: boolean;
52
52
  error: string | null;
53
53
  bridgeToolsUsed: string[];
54
+ allowedActionNames: string[] | undefined;
54
55
  createdAt: number;
55
56
  startedAt: number | null;
56
57
  finishedAt: number | null;
@@ -65,6 +66,7 @@ export interface CreateSandboxExecutionInput {
65
66
  maxOutputChars: number;
66
67
  maxAttempts?: number;
67
68
  runtime?: string;
69
+ allowedActionNames?: readonly string[];
68
70
  }
69
71
  export interface FinalizeSandboxExecutionInput {
70
72
  status: Extract<SandboxExecutionStatus, "succeeded" | "failed" | "timed_out">;
@@ -79,6 +79,7 @@ async function _doEnsureTable() {
79
79
  timed_out ${intType()} NOT NULL DEFAULT 0,
80
80
  error TEXT,
81
81
  bridge_tools_used TEXT,
82
+ allowed_action_names TEXT,
82
83
  created_at ${intType()} NOT NULL,
83
84
  started_at ${intType()},
84
85
  finished_at ${intType()},
@@ -94,7 +95,10 @@ async function _doEnsureTable() {
94
95
  await ensureTableExists(TABLE, createSql);
95
96
  // Additive-column guard: keeps older deployments (created before a column
96
97
  // was added) self-healing without destructive migrations.
97
- const pgColumns = [["bridge_tools_used", "TEXT"]];
98
+ const pgColumns = [
99
+ ["bridge_tools_used", "TEXT"],
100
+ ["allowed_action_names", "TEXT"],
101
+ ];
98
102
  for (const [col, def] of pgColumns) {
99
103
  await ensureColumnExists(TABLE, col, `ALTER TABLE ${TABLE} ADD COLUMN IF NOT EXISTS ${col} ${def}`);
100
104
  }
@@ -103,6 +107,15 @@ async function _doEnsureTable() {
103
107
  }
104
108
  else {
105
109
  await retryOnDdlRace(() => client.execute(createSql));
110
+ try {
111
+ await retryOnDdlRace(() => client.execute(`ALTER TABLE ${TABLE} ADD COLUMN allowed_action_names TEXT`));
112
+ }
113
+ catch (error) {
114
+ const message = String(error?.message ?? error);
115
+ if (!/duplicate column name|column .* already exists/i.test(message)) {
116
+ throw error;
117
+ }
118
+ }
106
119
  await retryOnDdlRace(() => client.execute(ownerIdxSql));
107
120
  await retryOnDdlRace(() => client.execute(dueIdxSql));
108
121
  }
@@ -136,6 +149,27 @@ function rowFromDb(raw) {
136
149
  bridgeToolsUsed = [];
137
150
  }
138
151
  }
152
+ let allowedActionNames;
153
+ if (raw.allowed_action_names !== null &&
154
+ raw.allowed_action_names !== undefined) {
155
+ if (typeof raw.allowed_action_names !== "string") {
156
+ allowedActionNames = [];
157
+ }
158
+ else {
159
+ try {
160
+ const parsed = JSON.parse(raw.allowed_action_names);
161
+ allowedActionNames =
162
+ Array.isArray(parsed) &&
163
+ parsed.every((item) => typeof item === "string")
164
+ ? [...new Set(parsed)]
165
+ : [];
166
+ }
167
+ catch {
168
+ // A malformed persisted surface must never restore the full registry.
169
+ allowedActionNames = [];
170
+ }
171
+ }
172
+ }
139
173
  return {
140
174
  id: String(raw.id),
141
175
  owner: String(raw.owner),
@@ -165,6 +199,7 @@ function rowFromDb(raw) {
165
199
  timedOut: toBool(raw.timed_out),
166
200
  error: raw.error === null || raw.error === undefined ? null : String(raw.error),
167
201
  bridgeToolsUsed,
202
+ allowedActionNames,
168
203
  createdAt: toNumberOrNull(raw.created_at) ?? 0,
169
204
  startedAt: toNumberOrNull(raw.started_at),
170
205
  finishedAt: toNumberOrNull(raw.finished_at),
@@ -180,8 +215,8 @@ export async function createSandboxExecution(input) {
180
215
  const maxAttempts = Math.max(1, Math.min(input.maxAttempts ?? SANDBOX_EXECUTION_DEFAULT_MAX_ATTEMPTS, 5));
181
216
  await client.execute({
182
217
  sql: `INSERT INTO ${TABLE}
183
- (id, owner, org_id, thread_id, runtime, code, status, timeout_ms, max_output_chars, attempt_count, max_attempts, created_at, updated_at)
184
- VALUES (?, ?, ?, ?, ?, ?, 'queued', ?, ?, 0, ?, ?, ?)`,
218
+ (id, owner, org_id, thread_id, runtime, code, status, timeout_ms, max_output_chars, attempt_count, max_attempts, allowed_action_names, created_at, updated_at)
219
+ VALUES (?, ?, ?, ?, ?, ?, 'queued', ?, ?, 0, ?, ?, ?, ?)`,
185
220
  args: [
186
221
  id,
187
222
  input.owner,
@@ -192,6 +227,9 @@ export async function createSandboxExecution(input) {
192
227
  input.timeoutMs,
193
228
  input.maxOutputChars,
194
229
  maxAttempts,
230
+ input.allowedActionNames === undefined
231
+ ? null
232
+ : JSON.stringify([...new Set(input.allowedActionNames)]),
195
233
  now,
196
234
  now,
197
235
  ],
@@ -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;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export * from "./config.js";
2
- export { createProductionAgentHandler, type ActionEntry, type ScriptEntry, type ProductionAgentOptions, type ActionTool, type ScriptTool, type AgentMessage, type AgentChatRequest, type AgentChatEvent, type AgentChatAttachment, DEFAULT_MODEL, TripWire, type Processor, type ProcessorState, type ProcessorAbort, } from "./agent/index.js";
2
+ export { createProductionAgentHandler, type ActionEntry, type ScriptEntry, type ProductionAgentOptions, type AgentActionSurface, type AgentActionSurfaceDetails, type ActionTool, type ScriptTool, type AgentMessage, type AgentChatRequest, type AgentChatEvent, type AgentChatAttachment, DEFAULT_MODEL, TripWire, type Processor, type ProcessorState, type ProcessorAbort, } from "./agent/index.js";
3
3
  export { defineAction, ActionContractError, isActionContractError, type ActionContractErrorOptions, AgentActionStopError, isAgentActionStopError, type ActionDefinition, type ActionHttpConfig, type AgentActionStopOptions, type PublicAgentActionConfig, type ActionDeepLink, type ActionLinkBuilder, MCP_APP_EXTENSION_ID, MCP_APP_MIME_TYPE, MCP_APP_RESOURCE_URI_META_KEY, type ActionMcpAppConfig, type ActionMcpAppCsp, type ActionMcpAppCspBuilder, type ActionMcpAppHtmlBuilder, type ActionMcpAppPermissions, type ActionMcpAppResourceConfig, type ActionMcpAppResourceMeta, } from "./action.js";
4
4
  export * from "./user-profile/index.js";
5
5
  export { embedApp, MCP_APP_REQUEST_ORIGIN_CSP_SOURCE, type EmbedAppOptions, } from "./mcp/embed-app.js";
@@ -0,0 +1,3 @@
1
+ import type { AgentChatTranslation } from "../core-messages.js";
2
+ declare const messages: AgentChatTranslation;
3
+ export default messages;