@agent-native/toolkit 0.227.0 → 0.228.0-nightly-20261111004142

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 (144) hide show
  1. package/agent-native.eject.json +8 -0
  2. package/dist/app/agent-page/AgentTabFrame.d.ts +2 -1
  3. package/dist/app/agent-page/AgentTabFrame.d.ts.map +1 -1
  4. package/dist/app/agent-page/AgentTabFrame.js +3 -2
  5. package/dist/app/agent-page/AgentTabFrame.js.map +1 -1
  6. package/dist/app/chat/AgentPanel.d.ts +15 -15
  7. package/dist/app/chat/AgentPanel.d.ts.map +1 -1
  8. package/dist/app/chat/AgentPanel.js.map +1 -1
  9. package/dist/app/chat/AgentSidebar.d.ts +7 -1
  10. package/dist/app/chat/AgentSidebar.d.ts.map +1 -1
  11. package/dist/app/chat/AgentSidebar.js +47 -16
  12. package/dist/app/chat/AgentSidebar.js.map +1 -1
  13. package/dist/app/chat/chat/surface-types.d.ts +26 -26
  14. package/dist/app/chat/chat/surface-types.d.ts.map +1 -1
  15. package/dist/app/extensions/EmbeddedExtension.d.ts.map +1 -1
  16. package/dist/app/extensions/EmbeddedExtension.js +6 -4
  17. package/dist/app/extensions/EmbeddedExtension.js.map +1 -1
  18. package/dist/app/extensions/ExtensionViewer.d.ts.map +1 -1
  19. package/dist/app/extensions/ExtensionViewer.js +6 -3
  20. package/dist/app/extensions/ExtensionViewer.js.map +1 -1
  21. package/dist/app/extensions/InlineExtensionFrame.d.ts.map +1 -1
  22. package/dist/app/extensions/InlineExtensionFrame.js +32 -28
  23. package/dist/app/extensions/InlineExtensionFrame.js.map +1 -1
  24. package/dist/app/extensions/use-extension-chat-submission.d.ts +14 -0
  25. package/dist/app/extensions/use-extension-chat-submission.d.ts.map +1 -0
  26. package/dist/app/extensions/use-extension-chat-submission.js +36 -0
  27. package/dist/app/extensions/use-extension-chat-submission.js.map +1 -0
  28. package/dist/app/i18n/catalogs/ar-SA.d.ts.map +1 -1
  29. package/dist/app/i18n/catalogs/ar-SA.js +16 -0
  30. package/dist/app/i18n/catalogs/ar-SA.js.map +1 -1
  31. package/dist/app/i18n/catalogs/de-DE.d.ts.map +1 -1
  32. package/dist/app/i18n/catalogs/de-DE.js +12 -0
  33. package/dist/app/i18n/catalogs/de-DE.js.map +1 -1
  34. package/dist/app/i18n/catalogs/en-US.d.ts +12 -0
  35. package/dist/app/i18n/catalogs/en-US.d.ts.map +1 -1
  36. package/dist/app/i18n/catalogs/en-US.js +12 -0
  37. package/dist/app/i18n/catalogs/en-US.js.map +1 -1
  38. package/dist/app/i18n/catalogs/es-ES.d.ts.map +1 -1
  39. package/dist/app/i18n/catalogs/es-ES.js +13 -0
  40. package/dist/app/i18n/catalogs/es-ES.js.map +1 -1
  41. package/dist/app/i18n/catalogs/fr-FR.d.ts.map +1 -1
  42. package/dist/app/i18n/catalogs/fr-FR.js +13 -0
  43. package/dist/app/i18n/catalogs/fr-FR.js.map +1 -1
  44. package/dist/app/i18n/catalogs/hi-IN.d.ts.map +1 -1
  45. package/dist/app/i18n/catalogs/hi-IN.js +12 -0
  46. package/dist/app/i18n/catalogs/hi-IN.js.map +1 -1
  47. package/dist/app/i18n/catalogs/ja-JP.d.ts.map +1 -1
  48. package/dist/app/i18n/catalogs/ja-JP.js +12 -0
  49. package/dist/app/i18n/catalogs/ja-JP.js.map +1 -1
  50. package/dist/app/i18n/catalogs/ko-KR.d.ts.map +1 -1
  51. package/dist/app/i18n/catalogs/ko-KR.js +12 -0
  52. package/dist/app/i18n/catalogs/ko-KR.js.map +1 -1
  53. package/dist/app/i18n/catalogs/pt-BR.d.ts.map +1 -1
  54. package/dist/app/i18n/catalogs/pt-BR.js +13 -0
  55. package/dist/app/i18n/catalogs/pt-BR.js.map +1 -1
  56. package/dist/app/i18n/catalogs/zh-CN.d.ts.map +1 -1
  57. package/dist/app/i18n/catalogs/zh-CN.js +12 -0
  58. package/dist/app/i18n/catalogs/zh-CN.js.map +1 -1
  59. package/dist/app/i18n/catalogs/zh-TW.d.ts.map +1 -1
  60. package/dist/app/i18n/catalogs/zh-TW.js +12 -0
  61. package/dist/app/i18n/catalogs/zh-TW.js.map +1 -1
  62. package/dist/app/org/OrgSwitcher.d.ts.map +1 -1
  63. package/dist/app/org/OrgSwitcher.js +3 -2
  64. package/dist/app/org/OrgSwitcher.js.map +1 -1
  65. package/dist/app/resources/McpAccessSettings.d.ts +9 -2
  66. package/dist/app/resources/McpAccessSettings.d.ts.map +1 -1
  67. package/dist/app/resources/McpAccessSettings.js +264 -86
  68. package/dist/app/resources/McpAccessSettings.js.map +1 -1
  69. package/dist/app/settings/api-keys/ApiKeyDialogs.d.ts +6 -0
  70. package/dist/app/settings/api-keys/ApiKeyDialogs.d.ts.map +1 -1
  71. package/dist/app/settings/api-keys/ApiKeyDialogs.js +74 -2
  72. package/dist/app/settings/api-keys/ApiKeyDialogs.js.map +1 -1
  73. package/dist/app/settings/api-keys/ApiKeysSettingsPage.d.ts.map +1 -1
  74. package/dist/app/settings/api-keys/ApiKeysSettingsPage.js +23 -9
  75. package/dist/app/settings/api-keys/ApiKeysSettingsPage.js.map +1 -1
  76. package/dist/app/settings/api-keys/api-keys-client.d.ts +10 -1
  77. package/dist/app/settings/api-keys/api-keys-client.d.ts.map +1 -1
  78. package/dist/app/settings/api-keys/api-keys-client.js +19 -1
  79. package/dist/app/settings/api-keys/api-keys-client.js.map +1 -1
  80. package/dist/app/settings/shell/pages/mcp.d.ts +1 -1
  81. package/dist/app/settings/shell/pages/mcp.d.ts.map +1 -1
  82. package/dist/app/settings/shell/pages/mcp.js +26 -20
  83. package/dist/app/settings/shell/pages/mcp.js.map +1 -1
  84. package/dist/app/sharing/ShareButton.d.ts +2 -0
  85. package/dist/app/sharing/ShareButton.d.ts.map +1 -1
  86. package/dist/app/sharing/ShareButton.js +4 -3
  87. package/dist/app/sharing/ShareButton.js.map +1 -1
  88. package/dist/composer/TiptapComposer.js +3 -0
  89. package/dist/composer/TiptapComposer.js.map +1 -1
  90. package/dist/sharing/ShareControls.d.ts +2 -0
  91. package/dist/sharing/ShareControls.d.ts.map +1 -1
  92. package/dist/sharing/ShareControls.js +7 -2
  93. package/dist/sharing/ShareControls.js.map +1 -1
  94. package/dist/ui/index.d.ts +1 -0
  95. package/dist/ui/index.d.ts.map +1 -1
  96. package/dist/ui/index.js +1 -0
  97. package/dist/ui/index.js.map +1 -1
  98. package/dist/ui/numbered-steps.d.ts +14 -0
  99. package/dist/ui/numbered-steps.d.ts.map +1 -0
  100. package/dist/ui/numbered-steps.js +19 -0
  101. package/dist/ui/numbered-steps.js.map +1 -0
  102. package/package.json +4 -4
  103. package/src/app/agent-page/AgentTabFrame.tsx +21 -10
  104. package/src/app/chat/AgentPanel.header.spec.ts +4 -1
  105. package/src/app/chat/AgentPanel.tsx +19 -14
  106. package/src/app/chat/AgentSidebar.spec.tsx +167 -0
  107. package/src/app/chat/AgentSidebar.tsx +170 -101
  108. package/src/app/chat/chat/surface-types.ts +35 -31
  109. package/src/app/extensions/EmbeddedExtension.height.spec.tsx +45 -0
  110. package/src/app/extensions/EmbeddedExtension.tsx +6 -3
  111. package/src/app/extensions/ExtensionViewer.spec.tsx +28 -0
  112. package/src/app/extensions/ExtensionViewer.tsx +6 -2
  113. package/src/app/extensions/InlineExtensionFrame.spec.tsx +23 -0
  114. package/src/app/extensions/InlineExtensionFrame.tsx +23 -15
  115. package/src/app/extensions/use-extension-chat-submission.tsx +101 -0
  116. package/src/app/i18n/catalogs/ar-SA.ts +17 -0
  117. package/src/app/i18n/catalogs/de-DE.ts +15 -0
  118. package/src/app/i18n/catalogs/en-US.ts +13 -0
  119. package/src/app/i18n/catalogs/es-ES.ts +16 -0
  120. package/src/app/i18n/catalogs/fr-FR.ts +16 -0
  121. package/src/app/i18n/catalogs/hi-IN.ts +13 -0
  122. package/src/app/i18n/catalogs/ja-JP.ts +15 -0
  123. package/src/app/i18n/catalogs/ko-KR.ts +14 -0
  124. package/src/app/i18n/catalogs/pt-BR.ts +15 -0
  125. package/src/app/i18n/catalogs/zh-CN.ts +13 -0
  126. package/src/app/i18n/catalogs/zh-TW.ts +13 -0
  127. package/src/app/integrations/IntegrationsPanel.spec.tsx +1 -1
  128. package/src/app/org/OrgSwitcher.spec.tsx +43 -0
  129. package/src/app/org/OrgSwitcher.tsx +29 -24
  130. package/src/app/resources/McpAccessSettings.spec.tsx +354 -278
  131. package/src/app/resources/McpAccessSettings.tsx +1012 -323
  132. package/src/app/settings/api-keys/ApiKeyDialogs.tsx +148 -1
  133. package/src/app/settings/api-keys/ApiKeysSettingsPage.spec.tsx +190 -0
  134. package/src/app/settings/api-keys/ApiKeysSettingsPage.tsx +40 -1
  135. package/src/app/settings/api-keys/api-keys-client.spec.ts +49 -0
  136. package/src/app/settings/api-keys/api-keys-client.ts +32 -0
  137. package/src/app/settings/shell/pages/app-group-pages.spec.tsx +31 -21
  138. package/src/app/settings/shell/pages/mcp.tsx +50 -42
  139. package/src/app/sharing/ShareButton.tsx +10 -3
  140. package/src/composer/TiptapComposer.tsx +2 -0
  141. package/src/composer/TiptapComposer.voice-toolbar.spec.tsx +16 -0
  142. package/src/sharing/ShareControls.tsx +44 -24
  143. package/src/ui/index.ts +1 -0
  144. package/src/ui/numbered-steps.tsx +104 -0
@@ -1,4 +1,3 @@
1
- import { sendToAgentChat } from "@agent-native/core/client/agent-chat";
2
1
  import { agentNativePath } from "@agent-native/core/client/api-path";
3
2
  import { useAppearance } from "@agent-native/core/client/appearance";
4
3
  import { getBrowserTabId } from "@agent-native/core/client/hooks";
@@ -57,6 +56,7 @@ import {
57
56
  useOpenUrlLatch,
58
57
  } from "./open-extension-link.js";
59
58
  import { normalizeAgentNativeExtensionSandbox } from "./portable-extension.js";
59
+ import { useExtensionChatSubmission } from "./use-extension-chat-submission.js";
60
60
 
61
61
  interface Extension {
62
62
  id: string;
@@ -134,6 +134,7 @@ export function EmbeddedExtension({
134
134
  onHeightChange,
135
135
  }: EmbeddedExtensionProps) {
136
136
  const iframeRef = useRef<HTMLIFrameElement | null>(null);
137
+ const extensionChat = useExtensionChatSubmission();
137
138
  const onReadyRef = useRef(onReady);
138
139
  onReadyRef.current = onReady;
139
140
  const onHeightChangeRef = useRef(onHeightChange);
@@ -307,7 +308,7 @@ export function EmbeddedExtension({
307
308
  if (message.type === "agent-native-send-to-chat") {
308
309
  const text = serializeChatValue((message as any).message);
309
310
  if (!text?.trim()) return;
310
- sendToAgentChat({
311
+ extensionChat.send({
311
312
  message: text,
312
313
  context: serializeChatValue((message as any).context),
313
314
  submit: (message as any).submit === true,
@@ -391,7 +392,7 @@ export function EmbeddedExtension({
391
392
  );
392
393
  }
393
394
 
394
- sendToAgentChat({
395
+ extensionChat.send({
395
396
  message: `Fix runtime errors in extension "${name}" (id: ${extensionId}), embedded as a dashboard panel. The content snapshot below was just re-read from the database — treat it as authoritative and ignore any prior version you may have generated in this chat. If in doubt, call get-extension first.\n\nErrors:\n${errors.join("\n")}`,
396
397
  context: contextParts.join("\n"),
397
398
  submit: true,
@@ -495,6 +496,7 @@ export function EmbeddedExtension({
495
496
  sandbox={EXTENSION_IFRAME_SANDBOX}
496
497
  style={{ width: "100%", border: 0, height, display: "block" }}
497
498
  onLoad={() => {
499
+ extensionChat.cancel();
498
500
  iframeRef.current?.contentWindow?.postMessage(
499
501
  {
500
502
  type: "agent-native-slot-context",
@@ -513,6 +515,7 @@ export function EmbeddedExtension({
513
515
  fireReady();
514
516
  }}
515
517
  />
518
+ {extensionChat.confirmation}
516
519
  <EmbeddedToolMenu
517
520
  extensionId={extensionId}
518
521
  slotId={slotId}
@@ -150,6 +150,34 @@ describe("ExtensionViewer MCP embeds", () => {
150
150
  return container.querySelector("iframe") as HTMLIFrameElement;
151
151
  }
152
152
 
153
+ it("holds a frame-submitted chat turn for host confirmation", async () => {
154
+ await renderViewer();
155
+ const iframe = container.querySelector("iframe");
156
+ expect(iframe).toBeTruthy();
157
+ await act(async () => {
158
+ window.dispatchEvent(
159
+ new MessageEvent("message", {
160
+ source: iframe?.contentWindow,
161
+ data: {
162
+ type: "agent-native-send-to-chat",
163
+ message: "Forged on load",
164
+ submit: true,
165
+ },
166
+ }),
167
+ );
168
+ });
169
+ expect(chatMocks.sendToAgentChat).not.toHaveBeenCalled();
170
+ const dialog = document.querySelector('[role="alertdialog"]');
171
+ expect(dialog?.textContent).toContain("Forged on load");
172
+ const send = Array.from(dialog?.querySelectorAll("button") ?? []).find(
173
+ (button) => button.textContent === "Send to agent",
174
+ );
175
+ await act(async () => send?.click());
176
+ expect(chatMocks.sendToAgentChat).toHaveBeenCalledWith(
177
+ expect.objectContaining({ message: "Forged on load", submit: true }),
178
+ );
179
+ });
180
+
153
181
  it("uses the extension render route in the normal app", async () => {
154
182
  const iframe = await renderViewer();
155
183
 
@@ -80,6 +80,7 @@ import {
80
80
  useOpenUrlLatch,
81
81
  } from "./open-extension-link.js";
82
82
  import { normalizeAgentNativeExtensionSandbox } from "./portable-extension.js";
83
+ import { useExtensionChatSubmission } from "./use-extension-chat-submission.js";
83
84
 
84
85
  const THEME_CSS_VARS = [
85
86
  "--background",
@@ -739,6 +740,7 @@ export function ExtensionViewer({
739
740
  headerActions = <AgentToggleButton />,
740
741
  }: ExtensionViewerProps) {
741
742
  const t = useT();
743
+ const extensionChat = useExtensionChatSubmission();
742
744
  const location = useLocation();
743
745
  const navigate = useNavigate();
744
746
  const [isDark, setIsDark] = useState(false);
@@ -847,7 +849,7 @@ export function ExtensionViewer({
847
849
  if (message.type === "agent-native-send-to-chat") {
848
850
  const text = serializeChatValue(message.message);
849
851
  if (!text?.trim()) return;
850
- sendToAgentChat({
852
+ extensionChat.send({
851
853
  message: text,
852
854
  context: serializeChatValue(message.context),
853
855
  submit: message.submit === true,
@@ -936,7 +938,7 @@ export function ExtensionViewer({
936
938
  );
937
939
  }
938
940
 
939
- sendToAgentChat({
941
+ extensionChat.send({
940
942
  message: `Fix runtime errors in this extension. The content snapshot below was just re-read from the database — treat it as authoritative and ignore any prior version you may have generated in this chat. If in doubt, call get-extension first.\n\nErrors:\n${errors.join("\n")}`,
941
943
  context: contextParts.join("\n"),
942
944
  submit: true,
@@ -1379,6 +1381,7 @@ export function ExtensionViewer({
1379
1381
  pointerEvents: openPopoverCount > 0 ? "none" : "auto",
1380
1382
  }}
1381
1383
  onLoad={() => {
1384
+ extensionChat.cancel();
1382
1385
  // While the srcDoc frame waits for its CSP lists it has no
1383
1386
  // document yet, so this is the about:blank load. Keep the
1384
1387
  // spinner up until the real document loads.
@@ -1388,6 +1391,7 @@ export function ExtensionViewer({
1388
1391
  }}
1389
1392
  />
1390
1393
  </div>
1394
+ {extensionChat.confirmation}
1391
1395
  </div>
1392
1396
  </TooltipProvider>
1393
1397
  );
@@ -31,6 +31,16 @@ describe("InlineExtensionFrame", () => {
31
31
  let container: HTMLDivElement;
32
32
  let root: Root;
33
33
 
34
+ async function confirmPendingMessage() {
35
+ const dialog = document.querySelector('[role="alertdialog"]');
36
+ expect(dialog?.textContent).toContain("Send extension message to agent?");
37
+ const send = Array.from(dialog?.querySelectorAll("button") ?? []).find(
38
+ (button) => button.textContent === "Send to agent",
39
+ );
40
+ expect(send).toBeTruthy();
41
+ await act(async () => send?.click());
42
+ }
43
+
34
44
  beforeEach(() => {
35
45
  vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);
36
46
  container = document.createElement("div");
@@ -86,6 +96,12 @@ describe("InlineExtensionFrame", () => {
86
96
  );
87
97
  });
88
98
 
99
+ expect(sendToAgentChat).not.toHaveBeenCalled();
100
+ expect(iframe?.getAttribute("aria-disabled")).toBeNull();
101
+ expect(
102
+ document.querySelector('[role="alertdialog"]')?.textContent,
103
+ ).toContain('Context{"threshold":42}');
104
+ await confirmPendingMessage();
89
105
  expect(sendToAgentChat).toHaveBeenCalledWith({
90
106
  message: "Use this threshold",
91
107
  context: JSON.stringify({ threshold: 42 }),
@@ -108,6 +124,7 @@ describe("InlineExtensionFrame", () => {
108
124
  );
109
125
  });
110
126
  expect(sendToAgentChat).toHaveBeenCalledTimes(1);
127
+ expect(document.querySelector('[role="alertdialog"]')).toBeNull();
111
128
  });
112
129
 
113
130
  it("keeps extension chat messages draft-only without explicit submission", async () => {
@@ -181,6 +198,8 @@ describe("InlineExtensionFrame", () => {
181
198
  );
182
199
  });
183
200
 
201
+ expect(sendToAgentChat).not.toHaveBeenCalled();
202
+ await confirmPendingMessage();
184
203
  expect(sendToAgentChat).toHaveBeenCalledTimes(1);
185
204
  expect(sendToAgentChat).toHaveBeenCalledWith({
186
205
  message: "One-time action",
@@ -218,6 +237,8 @@ describe("InlineExtensionFrame", () => {
218
237
  );
219
238
  });
220
239
 
240
+ await confirmPendingMessage();
241
+
221
242
  await act(async () => {
222
243
  root.render(
223
244
  <InlineExtensionFrame
@@ -245,6 +266,8 @@ describe("InlineExtensionFrame", () => {
245
266
  );
246
267
  });
247
268
 
269
+ await confirmPendingMessage();
270
+
248
271
  expect(sendToAgentChat).toHaveBeenCalledTimes(2);
249
272
  expect(sendToAgentChat).toHaveBeenLastCalledWith({
250
273
  message: "Replacement action",
@@ -1,4 +1,3 @@
1
- import { sendToAgentChat } from "@agent-native/core/client/agent-chat";
2
1
  import { agentNativePath } from "@agent-native/core/client/api-path";
3
2
  import { getBrowserTabId } from "@agent-native/core/client/hooks";
4
3
  import { SESSION_REPLAY_IFRAME_ATTRIBUTE } from "@agent-native/core/client/host";
@@ -24,6 +23,7 @@ import {
24
23
  useOpenUrlLatch,
25
24
  } from "./open-extension-link.js";
26
25
  import { normalizeAgentNativeExtensionSandbox } from "./portable-extension.js";
26
+ import { useExtensionChatSubmission } from "./use-extension-chat-submission.js";
27
27
 
28
28
  const THEME_CSS_VARS = [
29
29
  "--background",
@@ -341,6 +341,7 @@ export function InlineExtensionFrame({
341
341
  }: InlineExtensionFrameProps) {
342
342
  const providedId = providedExtension?.id ?? extensionId ?? "";
343
343
  const iframeRef = useRef<HTMLIFrameElement | null>(null);
344
+ const extensionChat = useExtensionChatSubmission();
344
345
  const [height, setHeight] = useState<number>(initialHeight);
345
346
  const [isDark, setIsDark] = useState(() =>
346
347
  typeof document === "undefined"
@@ -539,20 +540,25 @@ export function InlineExtensionFrame({
539
540
  }
540
541
 
541
542
  if (message.type === "agent-native-send-to-chat") {
542
- const text = serializeChatValue((message as any).message);
543
+ const chatMessage = message as Record<string, unknown>;
544
+ const text = serializeChatValue(chatMessage.message);
543
545
  if (!text?.trim()) return;
544
- const submit = (message as any).submit === true;
545
- if (isTransient && submit) {
546
- if (hasSubmittedRef.current) return;
547
- hasSubmittedRef.current = true;
548
- setHasSubmitted(true);
549
- }
550
- sendToAgentChat({
551
- message: text,
552
- context: serializeChatValue((message as any).context),
553
- submit: (message as any).submit === true,
554
- openSidebar: (message as any).openSidebar !== false,
555
- });
546
+ const submit = chatMessage.submit === true;
547
+ if (isTransient && submit && hasSubmittedRef.current) return;
548
+ extensionChat.send(
549
+ {
550
+ message: text,
551
+ context: serializeChatValue(chatMessage.context),
552
+ submit,
553
+ openSidebar: chatMessage.openSidebar !== false,
554
+ },
555
+ () => {
556
+ if (isTransient) {
557
+ hasSubmittedRef.current = true;
558
+ setHasSubmitted(true);
559
+ }
560
+ },
561
+ );
556
562
  return;
557
563
  }
558
564
 
@@ -577,7 +583,7 @@ export function InlineExtensionFrame({
577
583
  const errors: string[] = Array.isArray((message as any).errors)
578
584
  ? (message as any).errors
579
585
  : [];
580
- sendToAgentChat({
586
+ extensionChat.send({
581
587
  message: `Fix runtime errors in the inline extension "${extension?.name ?? resolvedId}".\n\nErrors:\n${errors.join("\n")}`,
582
588
  context: [
583
589
  `The user is viewing an inline generated extension named "${extension?.name ?? resolvedId}".`,
@@ -725,10 +731,12 @@ export function InlineExtensionFrame({
725
731
  pointerEvents: isTransient && hasSubmitted ? "none" : undefined,
726
732
  }}
727
733
  onLoad={() => {
734
+ extensionChat.cancel();
728
735
  sendThemeToIframe();
729
736
  sendContextToIframe();
730
737
  }}
731
738
  />
739
+ {extensionChat.confirmation}
732
740
  </div>
733
741
  );
734
742
  }
@@ -0,0 +1,101 @@
1
+ import { sendToAgentChat } from "@agent-native/core/client/agent-chat";
2
+ import { useT } from "@agent-native/core/client/i18n";
3
+ import { useState } from "react";
4
+
5
+ import {
6
+ AlertDialog,
7
+ AlertDialogAction,
8
+ AlertDialogCancel,
9
+ AlertDialogContent,
10
+ AlertDialogDescription,
11
+ AlertDialogFooter,
12
+ AlertDialogHeader,
13
+ AlertDialogTitle,
14
+ } from "../../ui/alert-dialog.js";
15
+
16
+ interface ExtensionChatMessage {
17
+ message: string;
18
+ context?: string | undefined;
19
+ openSidebar: boolean;
20
+ }
21
+
22
+ interface PendingExtensionChatMessage {
23
+ message: string;
24
+ context?: string;
25
+ openSidebar: boolean;
26
+ }
27
+
28
+ export function useExtensionChatSubmission() {
29
+ const t = useT();
30
+ const [pending, setPending] = useState<{
31
+ input: PendingExtensionChatMessage;
32
+ onConfirmed?: () => void;
33
+ } | null>(null);
34
+
35
+ const send = (
36
+ input: ExtensionChatMessage & { submit: boolean },
37
+ onConfirmed?: () => void,
38
+ ) => {
39
+ const message: PendingExtensionChatMessage = {
40
+ message: input.message,
41
+ ...(input.context !== undefined ? { context: input.context } : {}),
42
+ openSidebar: input.openSidebar,
43
+ };
44
+ if (!input.submit) {
45
+ sendToAgentChat({ ...message, submit: false });
46
+ return;
47
+ }
48
+ setPending(
49
+ (current) =>
50
+ current ?? {
51
+ input: message,
52
+ ...(onConfirmed ? { onConfirmed } : {}),
53
+ },
54
+ );
55
+ };
56
+
57
+ const confirmation = (
58
+ <AlertDialog
59
+ open={pending !== null}
60
+ onOpenChange={(open) => {
61
+ if (!open) setPending(null);
62
+ }}
63
+ >
64
+ <AlertDialogContent>
65
+ <AlertDialogHeader>
66
+ <AlertDialogTitle>
67
+ {t("agentChat.extensions.confirmAgentMessage")}
68
+ </AlertDialogTitle>
69
+ <AlertDialogDescription className="max-h-48 overflow-auto whitespace-pre-wrap break-words">
70
+ {pending?.input.message}
71
+ {pending?.input.context !== undefined && (
72
+ <span className="mt-3 block border-t pt-3">
73
+ <span className="block font-medium">
74
+ {t("agentChat.extensions.context")}
75
+ </span>
76
+ <span className="block">{pending.input.context}</span>
77
+ </span>
78
+ )}
79
+ </AlertDialogDescription>
80
+ </AlertDialogHeader>
81
+ <AlertDialogFooter>
82
+ <AlertDialogCancel>
83
+ {t("agentChat.extensions.cancel")}
84
+ </AlertDialogCancel>
85
+ <AlertDialogAction
86
+ onClick={() => {
87
+ if (!pending) return;
88
+ sendToAgentChat({ ...pending.input, submit: true });
89
+ pending.onConfirmed?.();
90
+ setPending(null);
91
+ }}
92
+ >
93
+ {t("agentChat.extensions.sendToAgent")}
94
+ </AlertDialogAction>
95
+ </AlertDialogFooter>
96
+ </AlertDialogContent>
97
+ </AlertDialog>
98
+ );
99
+
100
+ return { send, confirmation, cancel: () => setPending(null) };
101
+ }
@@ -1,6 +1,23 @@
1
1
  import type { ToolkitAgentChatTranslation } from "../types.js";
2
2
 
3
3
  const messages: ToolkitAgentChatTranslation = {
4
+ "settingsApiKeys.approvedOrigins": "المصادر المعتمدة",
5
+ "settingsApiKeys.originsHint":
6
+ "مصدر HTTPS محدد واحد في كل سطر. يمنع الحقل الفارغ الإرسال. يُسمح بـ HTTP المحلي.",
7
+ "settingsApiKeys.invalidOrigins": "أدخل مصادر HTTPS محددة، مصدرًا في كل سطر.",
8
+ "settingsApiKeys.editOrigins": "تعديل المصادر",
9
+ "settingsApiKeys.originsSaved": "تم حفظ المصادر",
10
+ "settingsApiKeys.originsCount_zero": "{{count}} مصادر معتمدة",
11
+ "settingsApiKeys.originsCount_one": "{{count}} مصدر معتمد",
12
+ "settingsApiKeys.originsCount_two": "{{count}} مصدران معتمدان",
13
+ "settingsApiKeys.originsCount_few": "{{count}} مصادر معتمدة",
14
+ "settingsApiKeys.originsCount_many": "{{count}} مصدرًا معتمدًا",
15
+ "settingsApiKeys.originsCount_other": "{{count}} مصادر معتمدة",
16
+ "settingsApiKeys.noApprovedOrigins": "لا توجد مصادر معتمدة",
17
+ "extensions.cancel": "إلغاء",
18
+ "extensions.context": "السياق",
19
+ "extensions.confirmAgentMessage": "هل تريد إرسال رسالة الإضافة إلى الوكيل؟",
20
+ "extensions.sendToAgent": "إرسال إلى الوكيل",
4
21
  "auth.logOutFailed": "تعذّر تسجيل الخروج",
5
22
  "block.renderUnavailable": "هذه الكتلة غير متاحة مؤقتًا.",
6
23
  "block.loading": "جارٍ تحميل هذه الكتلة.",
@@ -1,6 +1,21 @@
1
1
  import type { ToolkitAgentChatTranslation } from "../types.js";
2
2
 
3
3
  const messages: ToolkitAgentChatTranslation = {
4
+ "settingsApiKeys.approvedOrigins": "Genehmigte Ursprünge",
5
+ "settingsApiKeys.originsHint":
6
+ "Ein exakter HTTPS-Ursprung pro Zeile. Leer sperrt die Weitergabe. Lokales HTTP ist erlaubt.",
7
+ "settingsApiKeys.invalidOrigins":
8
+ "Exakte HTTPS-Ursprünge eingeben, einen pro Zeile.",
9
+ "settingsApiKeys.editOrigins": "Ursprünge bearbeiten",
10
+ "settingsApiKeys.originsSaved": "Ursprünge gespeichert",
11
+ "settingsApiKeys.originsCount_one": "{{count}} genehmigter Ursprung",
12
+ "settingsApiKeys.originsCount_other": "{{count}} genehmigte Ursprünge",
13
+ "settingsApiKeys.noApprovedOrigins": "Keine genehmigten Ursprünge",
14
+ "extensions.cancel": "Abbrechen",
15
+ "extensions.context": "Kontext",
16
+ "extensions.confirmAgentMessage":
17
+ "Nachricht der Erweiterung an den Agenten senden?",
18
+ "extensions.sendToAgent": "An Agenten senden",
4
19
  "auth.logOutFailed": "Abmelden fehlgeschlagen",
5
20
  "block.renderUnavailable": "Dieser Block ist vorübergehend nicht verfügbar.",
6
21
  "block.loading": "Block wird geladen.",
@@ -1,4 +1,17 @@
1
1
  const messages = {
2
+ "settingsApiKeys.approvedOrigins": "Approved origins",
3
+ "settingsApiKeys.originsHint":
4
+ "One exact HTTPS origin per line. Empty blocks forwarding. Local loopback HTTP is allowed.",
5
+ "settingsApiKeys.invalidOrigins": "Enter exact HTTPS origins, one per line.",
6
+ "settingsApiKeys.editOrigins": "Edit origins",
7
+ "settingsApiKeys.originsSaved": "Origins saved",
8
+ "settingsApiKeys.originsCount_one": "{{count}} approved origin",
9
+ "settingsApiKeys.originsCount_other": "{{count}} approved origins",
10
+ "settingsApiKeys.noApprovedOrigins": "No approved origins",
11
+ "extensions.cancel": "Cancel",
12
+ "extensions.context": "Context",
13
+ "extensions.confirmAgentMessage": "Send extension message to agent?",
14
+ "extensions.sendToAgent": "Send to agent",
2
15
  "auth.logOutFailed": "Log out failed",
3
16
  "block.renderUnavailable": "This block is temporarily unavailable.",
4
17
  "block.loading": "Loading block.",
@@ -1,6 +1,22 @@
1
1
  import type { ToolkitAgentChatTranslation } from "../types.js";
2
2
 
3
3
  const messages: ToolkitAgentChatTranslation = {
4
+ "settingsApiKeys.approvedOrigins": "Orígenes aprobados",
5
+ "settingsApiKeys.originsHint":
6
+ "Un origen HTTPS exacto por línea. Vacío bloquea el envío. Se permite HTTP local.",
7
+ "settingsApiKeys.invalidOrigins":
8
+ "Introduce orígenes HTTPS exactos, uno por línea.",
9
+ "settingsApiKeys.editOrigins": "Editar orígenes",
10
+ "settingsApiKeys.originsSaved": "Orígenes guardados",
11
+ "settingsApiKeys.originsCount_one": "{{count}} origen aprobado",
12
+ "settingsApiKeys.originsCount_many": "{{count}} orígenes aprobados",
13
+ "settingsApiKeys.originsCount_other": "{{count}} orígenes aprobados",
14
+ "settingsApiKeys.noApprovedOrigins": "Sin orígenes aprobados",
15
+ "extensions.cancel": "Cancelar",
16
+ "extensions.context": "Contexto",
17
+ "extensions.confirmAgentMessage":
18
+ "¿Enviar el mensaje de la extensión al agente?",
19
+ "extensions.sendToAgent": "Enviar al agente",
4
20
  "auth.logOutFailed": "No se pudo cerrar la sesión",
5
21
  "block.renderUnavailable": "Este bloque no está disponible temporalmente.",
6
22
  "block.loading": "Cargando bloque.",
@@ -1,6 +1,22 @@
1
1
  import type { ToolkitAgentChatTranslation } from "../types.js";
2
2
 
3
3
  const messages: ToolkitAgentChatTranslation = {
4
+ "settingsApiKeys.approvedOrigins": "Origines approuvées",
5
+ "settingsApiKeys.originsHint":
6
+ "Une origine HTTPS exacte par ligne. Vide bloque le transfert. HTTP local est autorisé.",
7
+ "settingsApiKeys.invalidOrigins":
8
+ "Saisissez des origines HTTPS exactes, une par ligne.",
9
+ "settingsApiKeys.editOrigins": "Modifier les origines",
10
+ "settingsApiKeys.originsSaved": "Origines enregistrées",
11
+ "settingsApiKeys.originsCount_one": "{{count}} origine approuvée",
12
+ "settingsApiKeys.originsCount_many": "{{count}} origines approuvées",
13
+ "settingsApiKeys.originsCount_other": "{{count}} origines approuvées",
14
+ "settingsApiKeys.noApprovedOrigins": "Aucune origine approuvée",
15
+ "extensions.cancel": "Annuler",
16
+ "extensions.context": "Contexte",
17
+ "extensions.confirmAgentMessage":
18
+ "Envoyer le message de l’extension à l’agent ?",
19
+ "extensions.sendToAgent": "Envoyer à l’agent",
4
20
  "auth.logOutFailed": "Échec de la déconnexion",
5
21
  "block.renderUnavailable": "Ce bloc est temporairement indisponible.",
6
22
  "block.loading": "Chargement du bloc.",
@@ -1,6 +1,19 @@
1
1
  import type { ToolkitAgentChatTranslation } from "../types.js";
2
2
 
3
3
  const messages: ToolkitAgentChatTranslation = {
4
+ "settingsApiKeys.approvedOrigins": "स्वीकृत मूल",
5
+ "settingsApiKeys.originsHint":
6
+ "प्रति पंक्ति एक सटीक HTTPS मूल। खाली रहने पर भेजना रुकता है। स्थानीय HTTP की अनुमति है।",
7
+ "settingsApiKeys.invalidOrigins": "प्रति पंक्ति एक सटीक HTTPS मूल दर्ज करें।",
8
+ "settingsApiKeys.editOrigins": "मूल संपादित करें",
9
+ "settingsApiKeys.originsSaved": "मूल सहेजे गए",
10
+ "settingsApiKeys.originsCount_one": "{{count}} स्वीकृत मूल",
11
+ "settingsApiKeys.originsCount_other": "{{count}} स्वीकृत मूल",
12
+ "settingsApiKeys.noApprovedOrigins": "कोई स्वीकृत मूल नहीं",
13
+ "extensions.cancel": "रद्द करें",
14
+ "extensions.context": "संदर्भ",
15
+ "extensions.confirmAgentMessage": "एक्सटेंशन का संदेश एजेंट को भेजें?",
16
+ "extensions.sendToAgent": "एजेंट को भेजें",
4
17
  "auth.logOutFailed": "साइन आउट नहीं हो सका",
5
18
  "block.renderUnavailable": "यह ब्लॉक अस्थायी रूप से उपलब्ध नहीं है।",
6
19
  "block.loading": "ब्लॉक लोड हो रहा है।",
@@ -1,6 +1,21 @@
1
1
  import type { ToolkitAgentChatTranslation } from "../types.js";
2
2
 
3
3
  const messages: ToolkitAgentChatTranslation = {
4
+ "settingsApiKeys.approvedOrigins": "承認済みオリジン",
5
+ "settingsApiKeys.originsHint":
6
+ "HTTPS オリジンを1行に1つ入力します。空欄では転送できません。ローカル HTTP は許可されます。",
7
+ "settingsApiKeys.invalidOrigins":
8
+ "HTTPS オリジンを1行に1つ正確に入力してください。",
9
+ "settingsApiKeys.editOrigins": "オリジンを編集",
10
+ "settingsApiKeys.originsSaved": "オリジンを保存しました",
11
+ "settingsApiKeys.originsCount_one": "承認済みオリジン {{count}} 件",
12
+ "settingsApiKeys.originsCount_other": "承認済みオリジン {{count}} 件",
13
+ "settingsApiKeys.noApprovedOrigins": "承認済みオリジンなし",
14
+ "extensions.cancel": "キャンセル",
15
+ "extensions.context": "コンテキスト",
16
+ "extensions.confirmAgentMessage":
17
+ "拡張機能のメッセージをエージェントに送信しますか?",
18
+ "extensions.sendToAgent": "エージェントに送信",
4
19
  "auth.logOutFailed": "ログアウトに失敗しました",
5
20
  "block.renderUnavailable": "このブロックは一時的に利用できません。",
6
21
  "block.loading": "ブロックを読み込み中です。",
@@ -1,6 +1,20 @@
1
1
  import type { ToolkitAgentChatTranslation } from "../types.js";
2
2
 
3
3
  const messages: ToolkitAgentChatTranslation = {
4
+ "settingsApiKeys.approvedOrigins": "승인된 출처",
5
+ "settingsApiKeys.originsHint":
6
+ "한 줄에 정확한 HTTPS 출처 하나씩 입력하세요. 비워 두면 전달이 차단됩니다. 로컬 HTTP는 허용됩니다.",
7
+ "settingsApiKeys.invalidOrigins":
8
+ "정확한 HTTPS 출처를 한 줄에 하나씩 입력하세요.",
9
+ "settingsApiKeys.editOrigins": "출처 편집",
10
+ "settingsApiKeys.originsSaved": "출처 저장됨",
11
+ "settingsApiKeys.originsCount_one": "승인된 출처 {{count}}개",
12
+ "settingsApiKeys.originsCount_other": "승인된 출처 {{count}}개",
13
+ "settingsApiKeys.noApprovedOrigins": "승인된 출처 없음",
14
+ "extensions.cancel": "취소",
15
+ "extensions.context": "컨텍스트",
16
+ "extensions.confirmAgentMessage": "확장 기능 메시지를 에이전트에게 보낼까요?",
17
+ "extensions.sendToAgent": "에이전트에게 보내기",
4
18
  "auth.logOutFailed": "로그아웃하지 못했습니다",
5
19
  "block.renderUnavailable": "이 블록은 일시적으로 사용할 수 없습니다.",
6
20
  "block.loading": "블록을 불러오는 중입니다.",
@@ -1,6 +1,21 @@
1
1
  import type { ToolkitAgentChatTranslation } from "../types.js";
2
2
 
3
3
  const messages: ToolkitAgentChatTranslation = {
4
+ "settingsApiKeys.approvedOrigins": "Origens aprovadas",
5
+ "settingsApiKeys.originsHint":
6
+ "Uma origem HTTPS exata por linha. Vazio bloqueia o encaminhamento. HTTP local é permitido.",
7
+ "settingsApiKeys.invalidOrigins":
8
+ "Informe origens HTTPS exatas, uma por linha.",
9
+ "settingsApiKeys.editOrigins": "Editar origens",
10
+ "settingsApiKeys.originsSaved": "Origens salvas",
11
+ "settingsApiKeys.originsCount_one": "{{count}} origem aprovada",
12
+ "settingsApiKeys.originsCount_many": "{{count}} origens aprovadas",
13
+ "settingsApiKeys.originsCount_other": "{{count}} origens aprovadas",
14
+ "settingsApiKeys.noApprovedOrigins": "Nenhuma origem aprovada",
15
+ "extensions.cancel": "Cancelar",
16
+ "extensions.context": "Contexto",
17
+ "extensions.confirmAgentMessage": "Enviar a mensagem da extensão ao agente?",
18
+ "extensions.sendToAgent": "Enviar ao agente",
4
19
  "auth.logOutFailed": "Não foi possível sair",
5
20
  "block.renderUnavailable": "Este bloco está temporariamente indisponível.",
6
21
  "block.loading": "Carregando bloco.",
@@ -1,6 +1,19 @@
1
1
  import type { ToolkitAgentChatTranslation } from "../types.js";
2
2
 
3
3
  const messages: ToolkitAgentChatTranslation = {
4
+ "settingsApiKeys.approvedOrigins": "已批准的来源",
5
+ "settingsApiKeys.originsHint":
6
+ "每行填写一个准确的 HTTPS 来源。留空将阻止转发。允许本地 HTTP。",
7
+ "settingsApiKeys.invalidOrigins": "请每行输入一个准确的 HTTPS 来源。",
8
+ "settingsApiKeys.editOrigins": "编辑来源",
9
+ "settingsApiKeys.originsSaved": "来源已保存",
10
+ "settingsApiKeys.originsCount_one": "{{count}} 个已批准的来源",
11
+ "settingsApiKeys.originsCount_other": "{{count}} 个已批准的来源",
12
+ "settingsApiKeys.noApprovedOrigins": "没有已批准的来源",
13
+ "extensions.cancel": "取消",
14
+ "extensions.context": "上下文",
15
+ "extensions.confirmAgentMessage": "将扩展消息发送给智能体?",
16
+ "extensions.sendToAgent": "发送给智能体",
4
17
  "auth.logOutFailed": "退出登录失败",
5
18
  "block.renderUnavailable": "此区块暂时不可用。",
6
19
  "block.loading": "正在加载区块。",
@@ -1,6 +1,19 @@
1
1
  import type { ToolkitAgentChatTranslation } from "../types.js";
2
2
 
3
3
  const messages: ToolkitAgentChatTranslation = {
4
+ "settingsApiKeys.approvedOrigins": "已核准的來源",
5
+ "settingsApiKeys.originsHint":
6
+ "每行填寫一個確切的 HTTPS 來源。留空會封鎖轉送。允許本機 HTTP。",
7
+ "settingsApiKeys.invalidOrigins": "請每行輸入一個確切的 HTTPS 來源。",
8
+ "settingsApiKeys.editOrigins": "編輯來源",
9
+ "settingsApiKeys.originsSaved": "來源已儲存",
10
+ "settingsApiKeys.originsCount_one": "{{count}} 個已核准的來源",
11
+ "settingsApiKeys.originsCount_other": "{{count}} 個已核准的來源",
12
+ "settingsApiKeys.noApprovedOrigins": "沒有已核准的來源",
13
+ "extensions.cancel": "取消",
14
+ "extensions.context": "上下文",
15
+ "extensions.confirmAgentMessage": "要將擴充功能訊息傳送給代理嗎?",
16
+ "extensions.sendToAgent": "傳送給代理",
4
17
  "auth.logOutFailed": "登出失敗",
5
18
  "block.renderUnavailable": "此區塊暫時無法使用。",
6
19
  "block.loading": "正在載入區塊。",
@@ -365,7 +365,7 @@ describe("IntegrationsPanel MCP connection errors", () => {
365
365
  });
366
366
 
367
367
  it.each([
368
- ["Claude Cowork", "codex"],
368
+ ["Claude Cowork", "claude"],
369
369
  ["Claude Code", "claude-code"],
370
370
  ["Anthropic", "claude"],
371
371
  ["OpenAI", "chatgpt"],