@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.
- package/agent-native.eject.json +8 -0
- package/dist/app/agent-page/AgentTabFrame.d.ts +2 -1
- package/dist/app/agent-page/AgentTabFrame.d.ts.map +1 -1
- package/dist/app/agent-page/AgentTabFrame.js +3 -2
- package/dist/app/agent-page/AgentTabFrame.js.map +1 -1
- package/dist/app/chat/AgentPanel.d.ts +15 -15
- package/dist/app/chat/AgentPanel.d.ts.map +1 -1
- package/dist/app/chat/AgentPanel.js.map +1 -1
- package/dist/app/chat/AgentSidebar.d.ts +7 -1
- package/dist/app/chat/AgentSidebar.d.ts.map +1 -1
- package/dist/app/chat/AgentSidebar.js +47 -16
- package/dist/app/chat/AgentSidebar.js.map +1 -1
- package/dist/app/chat/chat/surface-types.d.ts +26 -26
- package/dist/app/chat/chat/surface-types.d.ts.map +1 -1
- package/dist/app/extensions/EmbeddedExtension.d.ts.map +1 -1
- package/dist/app/extensions/EmbeddedExtension.js +6 -4
- package/dist/app/extensions/EmbeddedExtension.js.map +1 -1
- package/dist/app/extensions/ExtensionViewer.d.ts.map +1 -1
- package/dist/app/extensions/ExtensionViewer.js +6 -3
- package/dist/app/extensions/ExtensionViewer.js.map +1 -1
- package/dist/app/extensions/InlineExtensionFrame.d.ts.map +1 -1
- package/dist/app/extensions/InlineExtensionFrame.js +32 -28
- package/dist/app/extensions/InlineExtensionFrame.js.map +1 -1
- package/dist/app/extensions/use-extension-chat-submission.d.ts +14 -0
- package/dist/app/extensions/use-extension-chat-submission.d.ts.map +1 -0
- package/dist/app/extensions/use-extension-chat-submission.js +36 -0
- package/dist/app/extensions/use-extension-chat-submission.js.map +1 -0
- package/dist/app/i18n/catalogs/ar-SA.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/ar-SA.js +16 -0
- package/dist/app/i18n/catalogs/ar-SA.js.map +1 -1
- package/dist/app/i18n/catalogs/de-DE.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/de-DE.js +12 -0
- package/dist/app/i18n/catalogs/de-DE.js.map +1 -1
- package/dist/app/i18n/catalogs/en-US.d.ts +12 -0
- package/dist/app/i18n/catalogs/en-US.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/en-US.js +12 -0
- package/dist/app/i18n/catalogs/en-US.js.map +1 -1
- package/dist/app/i18n/catalogs/es-ES.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/es-ES.js +13 -0
- package/dist/app/i18n/catalogs/es-ES.js.map +1 -1
- package/dist/app/i18n/catalogs/fr-FR.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/fr-FR.js +13 -0
- package/dist/app/i18n/catalogs/fr-FR.js.map +1 -1
- package/dist/app/i18n/catalogs/hi-IN.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/hi-IN.js +12 -0
- package/dist/app/i18n/catalogs/hi-IN.js.map +1 -1
- package/dist/app/i18n/catalogs/ja-JP.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/ja-JP.js +12 -0
- package/dist/app/i18n/catalogs/ja-JP.js.map +1 -1
- package/dist/app/i18n/catalogs/ko-KR.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/ko-KR.js +12 -0
- package/dist/app/i18n/catalogs/ko-KR.js.map +1 -1
- package/dist/app/i18n/catalogs/pt-BR.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/pt-BR.js +13 -0
- package/dist/app/i18n/catalogs/pt-BR.js.map +1 -1
- package/dist/app/i18n/catalogs/zh-CN.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/zh-CN.js +12 -0
- package/dist/app/i18n/catalogs/zh-CN.js.map +1 -1
- package/dist/app/i18n/catalogs/zh-TW.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/zh-TW.js +12 -0
- package/dist/app/i18n/catalogs/zh-TW.js.map +1 -1
- package/dist/app/org/OrgSwitcher.d.ts.map +1 -1
- package/dist/app/org/OrgSwitcher.js +3 -2
- package/dist/app/org/OrgSwitcher.js.map +1 -1
- package/dist/app/resources/McpAccessSettings.d.ts +9 -2
- package/dist/app/resources/McpAccessSettings.d.ts.map +1 -1
- package/dist/app/resources/McpAccessSettings.js +264 -86
- package/dist/app/resources/McpAccessSettings.js.map +1 -1
- package/dist/app/settings/api-keys/ApiKeyDialogs.d.ts +6 -0
- package/dist/app/settings/api-keys/ApiKeyDialogs.d.ts.map +1 -1
- package/dist/app/settings/api-keys/ApiKeyDialogs.js +74 -2
- package/dist/app/settings/api-keys/ApiKeyDialogs.js.map +1 -1
- package/dist/app/settings/api-keys/ApiKeysSettingsPage.d.ts.map +1 -1
- package/dist/app/settings/api-keys/ApiKeysSettingsPage.js +23 -9
- package/dist/app/settings/api-keys/ApiKeysSettingsPage.js.map +1 -1
- package/dist/app/settings/api-keys/api-keys-client.d.ts +10 -1
- package/dist/app/settings/api-keys/api-keys-client.d.ts.map +1 -1
- package/dist/app/settings/api-keys/api-keys-client.js +19 -1
- package/dist/app/settings/api-keys/api-keys-client.js.map +1 -1
- package/dist/app/settings/shell/pages/mcp.d.ts +1 -1
- package/dist/app/settings/shell/pages/mcp.d.ts.map +1 -1
- package/dist/app/settings/shell/pages/mcp.js +26 -20
- package/dist/app/settings/shell/pages/mcp.js.map +1 -1
- package/dist/app/sharing/ShareButton.d.ts +2 -0
- package/dist/app/sharing/ShareButton.d.ts.map +1 -1
- package/dist/app/sharing/ShareButton.js +4 -3
- package/dist/app/sharing/ShareButton.js.map +1 -1
- package/dist/composer/TiptapComposer.js +3 -0
- package/dist/composer/TiptapComposer.js.map +1 -1
- package/dist/sharing/ShareControls.d.ts +2 -0
- package/dist/sharing/ShareControls.d.ts.map +1 -1
- package/dist/sharing/ShareControls.js +7 -2
- package/dist/sharing/ShareControls.js.map +1 -1
- package/dist/ui/index.d.ts +1 -0
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +1 -0
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/numbered-steps.d.ts +14 -0
- package/dist/ui/numbered-steps.d.ts.map +1 -0
- package/dist/ui/numbered-steps.js +19 -0
- package/dist/ui/numbered-steps.js.map +1 -0
- package/package.json +4 -4
- package/src/app/agent-page/AgentTabFrame.tsx +21 -10
- package/src/app/chat/AgentPanel.header.spec.ts +4 -1
- package/src/app/chat/AgentPanel.tsx +19 -14
- package/src/app/chat/AgentSidebar.spec.tsx +167 -0
- package/src/app/chat/AgentSidebar.tsx +170 -101
- package/src/app/chat/chat/surface-types.ts +35 -31
- package/src/app/extensions/EmbeddedExtension.height.spec.tsx +45 -0
- package/src/app/extensions/EmbeddedExtension.tsx +6 -3
- package/src/app/extensions/ExtensionViewer.spec.tsx +28 -0
- package/src/app/extensions/ExtensionViewer.tsx +6 -2
- package/src/app/extensions/InlineExtensionFrame.spec.tsx +23 -0
- package/src/app/extensions/InlineExtensionFrame.tsx +23 -15
- package/src/app/extensions/use-extension-chat-submission.tsx +101 -0
- package/src/app/i18n/catalogs/ar-SA.ts +17 -0
- package/src/app/i18n/catalogs/de-DE.ts +15 -0
- package/src/app/i18n/catalogs/en-US.ts +13 -0
- package/src/app/i18n/catalogs/es-ES.ts +16 -0
- package/src/app/i18n/catalogs/fr-FR.ts +16 -0
- package/src/app/i18n/catalogs/hi-IN.ts +13 -0
- package/src/app/i18n/catalogs/ja-JP.ts +15 -0
- package/src/app/i18n/catalogs/ko-KR.ts +14 -0
- package/src/app/i18n/catalogs/pt-BR.ts +15 -0
- package/src/app/i18n/catalogs/zh-CN.ts +13 -0
- package/src/app/i18n/catalogs/zh-TW.ts +13 -0
- package/src/app/integrations/IntegrationsPanel.spec.tsx +1 -1
- package/src/app/org/OrgSwitcher.spec.tsx +43 -0
- package/src/app/org/OrgSwitcher.tsx +29 -24
- package/src/app/resources/McpAccessSettings.spec.tsx +354 -278
- package/src/app/resources/McpAccessSettings.tsx +1012 -323
- package/src/app/settings/api-keys/ApiKeyDialogs.tsx +148 -1
- package/src/app/settings/api-keys/ApiKeysSettingsPage.spec.tsx +190 -0
- package/src/app/settings/api-keys/ApiKeysSettingsPage.tsx +40 -1
- package/src/app/settings/api-keys/api-keys-client.spec.ts +49 -0
- package/src/app/settings/api-keys/api-keys-client.ts +32 -0
- package/src/app/settings/shell/pages/app-group-pages.spec.tsx +31 -21
- package/src/app/settings/shell/pages/mcp.tsx +50 -42
- package/src/app/sharing/ShareButton.tsx +10 -3
- package/src/composer/TiptapComposer.tsx +2 -0
- package/src/composer/TiptapComposer.voice-toolbar.spec.tsx +16 -0
- package/src/sharing/ShareControls.tsx +44 -24
- package/src/ui/index.ts +1 -0
- package/src/ui/numbered-steps.tsx +104 -0
|
@@ -73,7 +73,7 @@ import React, {
|
|
|
73
73
|
lazy,
|
|
74
74
|
Suspense,
|
|
75
75
|
} from "react";
|
|
76
|
-
import { flushSync } from "react-dom";
|
|
76
|
+
import { createPortal, flushSync } from "react-dom";
|
|
77
77
|
|
|
78
78
|
import { setComposerReferenceEventTarget } from "../../composer/runtime-adapters.js";
|
|
79
79
|
import { Skeleton } from "../../ui/skeleton.js";
|
|
@@ -296,6 +296,12 @@ export interface AgentSidebarProps {
|
|
|
296
296
|
forceOverlay?: boolean;
|
|
297
297
|
defaultOpen?: boolean;
|
|
298
298
|
disableChatShortcut?: boolean;
|
|
299
|
+
/**
|
|
300
|
+
* Draws the panel inside this element instead of beside the page, for an app
|
|
301
|
+
* whose own sidebar holds the agent. The app then owns the panel's width,
|
|
302
|
+
* motion and close button, and the key that toggles the sidebar.
|
|
303
|
+
*/
|
|
304
|
+
panelHost?: HTMLElement | null;
|
|
299
305
|
showCollapseButton?: boolean;
|
|
300
306
|
animateMobile?: boolean;
|
|
301
307
|
animateDesktop?: boolean;
|
|
@@ -376,6 +382,7 @@ export function AgentSidebar({
|
|
|
376
382
|
forceOverlay = false,
|
|
377
383
|
defaultOpen,
|
|
378
384
|
disableChatShortcut = false,
|
|
385
|
+
panelHost,
|
|
379
386
|
showCollapseButton = true,
|
|
380
387
|
animateMobile = true,
|
|
381
388
|
animateDesktop = true,
|
|
@@ -644,9 +651,18 @@ export function AgentSidebar({
|
|
|
644
651
|
!isPerAppChatHosted &&
|
|
645
652
|
!presentationMode &&
|
|
646
653
|
(!frameCodeMode || !shouldParentFrameOwnAgentPanel());
|
|
654
|
+
const hostedPanel = ownsPanel && panelHost ? panelHost : null;
|
|
655
|
+
// A host switches between the agent and its other sections, so the chat
|
|
656
|
+
// stays mounted behind them once it has opened.
|
|
657
|
+
const [hostedPanelOpened, setHostedPanelOpened] = useState(false);
|
|
658
|
+
useEffect(() => {
|
|
659
|
+
if (!hostedPanel) setHostedPanelOpened(false);
|
|
660
|
+
else if (open) setHostedPanelOpened(true);
|
|
661
|
+
}, [hostedPanel, open]);
|
|
647
662
|
const shouldMountPanel =
|
|
648
663
|
ownsPanel &&
|
|
649
664
|
(open ||
|
|
665
|
+
hostedPanelOpened ||
|
|
650
666
|
backgroundPanelActive ||
|
|
651
667
|
runningTabIds.size > 0 ||
|
|
652
668
|
hasPendingPanelEvents);
|
|
@@ -714,7 +730,7 @@ export function AgentSidebar({
|
|
|
714
730
|
return (
|
|
715
731
|
pending.order < navigation.order &&
|
|
716
732
|
!isPanelNavigationEvent(pending.event) &&
|
|
717
|
-
!submit
|
|
733
|
+
!sendsToOwnTab(submit)
|
|
718
734
|
);
|
|
719
735
|
}),
|
|
720
736
|
);
|
|
@@ -844,7 +860,11 @@ export function AgentSidebar({
|
|
|
844
860
|
pending.targetId == null &&
|
|
845
861
|
!pending.reference &&
|
|
846
862
|
!isComposerReferenceEvent(pending.event) &&
|
|
847
|
-
!isPanelNavigationEvent(pending.event)
|
|
863
|
+
!isPanelNavigationEvent(pending.event) &&
|
|
864
|
+
!(
|
|
865
|
+
pending.event instanceof MessageEvent &&
|
|
866
|
+
sendsToOwnTab(parseSubmitChatMessage(pending.event))
|
|
867
|
+
)
|
|
848
868
|
)
|
|
849
869
|
pending.targetId = targetId;
|
|
850
870
|
}
|
|
@@ -855,7 +875,7 @@ export function AgentSidebar({
|
|
|
855
875
|
pending.event instanceof MessageEvent
|
|
856
876
|
? parseSubmitChatMessage(pending.event)
|
|
857
877
|
: null;
|
|
858
|
-
if (submit
|
|
878
|
+
if (sendsToOwnTab(submit)) return false;
|
|
859
879
|
const recipient =
|
|
860
880
|
pending.referenceTargetId ??
|
|
861
881
|
pending.reference?.referenceTargetId ??
|
|
@@ -978,10 +998,12 @@ export function AgentSidebar({
|
|
|
978
998
|
: !presentationMode && (frameOwned ? frameSidebarOpen : open)),
|
|
979
999
|
source: frameOwned ? "frame" : "app",
|
|
980
1000
|
mode: frameOwned ? "code" : "app",
|
|
1001
|
+
hosted: Boolean(hostedPanel),
|
|
981
1002
|
});
|
|
982
1003
|
}, [
|
|
983
1004
|
frameCodeMode,
|
|
984
1005
|
frameSidebarOpen,
|
|
1006
|
+
hostedPanel,
|
|
985
1007
|
open,
|
|
986
1008
|
presentationMode,
|
|
987
1009
|
hasFrameSidebarState,
|
|
@@ -1125,12 +1147,13 @@ export function AgentSidebar({
|
|
|
1125
1147
|
: recipient
|
|
1126
1148
|
: undefined,
|
|
1127
1149
|
navigation:
|
|
1128
|
-
submit
|
|
1150
|
+
sendsToOwnTab(submit) || isPanelNavigationEvent(event)
|
|
1129
1151
|
? undefined
|
|
1130
1152
|
: navigation,
|
|
1131
1153
|
targetId:
|
|
1132
1154
|
submit?.targetTabId ??
|
|
1133
1155
|
(navigation ||
|
|
1156
|
+
sendsToOwnTab(submit) ||
|
|
1134
1157
|
isPanelNavigationEvent(event) ||
|
|
1135
1158
|
isComposerReferenceEvent(event)
|
|
1136
1159
|
? undefined
|
|
@@ -1139,7 +1162,7 @@ export function AgentSidebar({
|
|
|
1139
1162
|
: recipient),
|
|
1140
1163
|
reference:
|
|
1141
1164
|
!isPanelNavigationEvent(event) &&
|
|
1142
|
-
!submit
|
|
1165
|
+
!sendsToOwnTab(submit) &&
|
|
1143
1166
|
reference &&
|
|
1144
1167
|
isComposerReferenceEvent(reference.event)
|
|
1145
1168
|
? reference
|
|
@@ -1468,14 +1491,22 @@ export function AgentSidebar({
|
|
|
1468
1491
|
useEffect(() => {
|
|
1469
1492
|
if (!enabled) return;
|
|
1470
1493
|
const handleKeyDown = (e: KeyboardEvent) => {
|
|
1471
|
-
|
|
1494
|
+
// A host's element that isn't on the page yet, such as one a loading
|
|
1495
|
+
// page's skeleton holds, has no panel to answer ⌘\, so the shell does.
|
|
1496
|
+
if (!panelHost?.isConnected && isAgentSidebarToggleShortcut(e)) {
|
|
1472
1497
|
e.preventDefault();
|
|
1473
1498
|
window.dispatchEvent(
|
|
1474
1499
|
new CustomEvent("agent-panel:toggle", { detail: { focus: true } }),
|
|
1475
1500
|
);
|
|
1476
1501
|
return;
|
|
1477
1502
|
}
|
|
1478
|
-
|
|
1503
|
+
// A Mac reports ⇧⌘I with a lowercase key, and a hosting page's panel
|
|
1504
|
+
// owns that key.
|
|
1505
|
+
if (
|
|
1506
|
+
!disableChatShortcut &&
|
|
1507
|
+
isAgentPanelChatShortcut(e) &&
|
|
1508
|
+
!(panelHost && e.shiftKey)
|
|
1509
|
+
) {
|
|
1479
1510
|
e.preventDefault();
|
|
1480
1511
|
let selectionText = "";
|
|
1481
1512
|
try {
|
|
@@ -1500,7 +1531,7 @@ export function AgentSidebar({
|
|
|
1500
1531
|
};
|
|
1501
1532
|
document.addEventListener("keydown", handleKeyDown);
|
|
1502
1533
|
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
1503
|
-
}, [disableChatShortcut, enabled]);
|
|
1534
|
+
}, [disableChatShortcut, enabled, panelHost]);
|
|
1504
1535
|
|
|
1505
1536
|
useEffect(() => {
|
|
1506
1537
|
const handler = (event: MessageEvent) => {
|
|
@@ -1602,12 +1633,12 @@ export function AgentSidebar({
|
|
|
1602
1633
|
}, [persistWidth]);
|
|
1603
1634
|
|
|
1604
1635
|
const isLeft = effectivePosition === "left";
|
|
1605
|
-
const isOverlay = isMobile || forceOverlay;
|
|
1606
|
-
const wideDrawerEnabled = isWideDrawer && !isOverlay;
|
|
1636
|
+
const isOverlay = !hostedPanel && (isMobile || forceOverlay);
|
|
1637
|
+
const wideDrawerEnabled = isWideDrawer && !isOverlay && !hostedPanel;
|
|
1607
1638
|
const mobileAnimationEnabled =
|
|
1608
1639
|
!presentationMode && isOverlay && animateMobile;
|
|
1609
1640
|
const desktopAnimationEnabled =
|
|
1610
|
-
!presentationMode && !isOverlay && effectiveAnimateDesktop;
|
|
1641
|
+
!presentationMode && !isOverlay && !hostedPanel && effectiveAnimateDesktop;
|
|
1611
1642
|
const sidebarAnimationEnabled =
|
|
1612
1643
|
mobileAnimationEnabled || desktopAnimationEnabled;
|
|
1613
1644
|
const [renderAnimatedPanel, setRenderAnimatedPanel] =
|
|
@@ -1713,7 +1744,119 @@ export function AgentSidebar({
|
|
|
1713
1744
|
};
|
|
1714
1745
|
}
|
|
1715
1746
|
|
|
1716
|
-
const
|
|
1747
|
+
const panelBody = (
|
|
1748
|
+
<LazyChunkErrorBoundary
|
|
1749
|
+
fallback={<LazyChunkRetryFallback />}
|
|
1750
|
+
shouldHandleError={isPanelImportError}
|
|
1751
|
+
onError={onPanelLoadFailed}
|
|
1752
|
+
>
|
|
1753
|
+
<Suspense
|
|
1754
|
+
fallback={
|
|
1755
|
+
<div
|
|
1756
|
+
aria-hidden="true"
|
|
1757
|
+
className="flex min-h-0 flex-1 flex-col gap-3 p-3"
|
|
1758
|
+
>
|
|
1759
|
+
<Skeleton className="h-8 w-full" />
|
|
1760
|
+
<div className="flex-1" />
|
|
1761
|
+
<Skeleton className="h-28 w-full rounded-xl" />
|
|
1762
|
+
</div>
|
|
1763
|
+
}
|
|
1764
|
+
>
|
|
1765
|
+
<AgentSidebarPanel
|
|
1766
|
+
onReadyChange={onPanelReadyChange}
|
|
1767
|
+
onReferenceTargetChange={onReferenceTargetChange}
|
|
1768
|
+
onNavigationChange={onNavigationChange}
|
|
1769
|
+
onTabsClosing={onTabsClosing}
|
|
1770
|
+
emptyStateText={emptyStateText}
|
|
1771
|
+
mcpSuggestionExcludedIntegrationIds={
|
|
1772
|
+
mcpSuggestionExcludedIntegrationIds
|
|
1773
|
+
}
|
|
1774
|
+
suggestions={suggestions}
|
|
1775
|
+
dynamicSuggestions={dynamicSuggestions}
|
|
1776
|
+
suggestionPlacement="context-chips"
|
|
1777
|
+
composerToolbarSlot={composerToolbarSlot}
|
|
1778
|
+
composerSlot={composerSlot}
|
|
1779
|
+
// A host's tab opens the chat without taking focus from the tab.
|
|
1780
|
+
{...(hostedPanel ? { composerAutoFocus: false } : {})}
|
|
1781
|
+
composerContextProvider={composerContextProvider}
|
|
1782
|
+
onComposerTextChange={onComposerTextChange}
|
|
1783
|
+
imageModelMenu={imageModelMenu}
|
|
1784
|
+
availableAgents={effectiveAvailableAgents}
|
|
1785
|
+
availableModels={availableModels}
|
|
1786
|
+
modelListLoading={modelListLoading}
|
|
1787
|
+
selectedAgent={effectiveSelectedAgent}
|
|
1788
|
+
onAgentChange={effectiveOnAgentChange}
|
|
1789
|
+
hostedHarness={hostedHarnessEnabled}
|
|
1790
|
+
onConnectProvider={onConnectProvider}
|
|
1791
|
+
builderConnectTransport={builderConnectTransport}
|
|
1792
|
+
onConnectLocalRuntime={onConnectLocalRuntime}
|
|
1793
|
+
runtime={runtime}
|
|
1794
|
+
adapterReloadKey={adapterReloadKey}
|
|
1795
|
+
threadFooterSlot={threadFooterSlot}
|
|
1796
|
+
apiUrl={apiUrl}
|
|
1797
|
+
agentChatSurface={agentChatSurface}
|
|
1798
|
+
desktopIdentityUnauthenticated={desktopIdentityUnauthenticated}
|
|
1799
|
+
desktopIdentityAuthenticated={desktopIdentityAuthenticated}
|
|
1800
|
+
showTabBar={effectiveShowTabBar}
|
|
1801
|
+
suppressInlineOpenApp={suppressInlineOpenApp}
|
|
1802
|
+
composerPlaceholder={composerPlaceholder}
|
|
1803
|
+
showMissingApiKeySetup={showMissingApiKeySetup}
|
|
1804
|
+
setupCardOwner={setupCardOwner}
|
|
1805
|
+
showGuidedQuestions={showGuidedQuestions}
|
|
1806
|
+
missingApiKeySetupLayout="sidebar"
|
|
1807
|
+
defaultMode={defaultMode}
|
|
1808
|
+
onCollapse={() => setOpenPersisted(false)}
|
|
1809
|
+
showCollapseButton={!hostedPanel && showCollapseButton}
|
|
1810
|
+
onSnapTo75Percent={
|
|
1811
|
+
isOverlay || hostedPanel ? undefined : snapTo75Percent
|
|
1812
|
+
}
|
|
1813
|
+
isWideDrawer={wideDrawerEnabled}
|
|
1814
|
+
onExitWideDrawer={
|
|
1815
|
+
isOverlay || hostedPanel ? undefined : exitWideDrawer
|
|
1816
|
+
}
|
|
1817
|
+
onFullViewRequest={onFullscreenRequest}
|
|
1818
|
+
onOpenSettings={onOpenSettings}
|
|
1819
|
+
onNewCliTab={onNewCliTab}
|
|
1820
|
+
onNewUiTab={onNewUiTab}
|
|
1821
|
+
renderCliTab={renderCliTab}
|
|
1822
|
+
newTabMode={newTabMode}
|
|
1823
|
+
newCliTabLabel={newCliTabLabel}
|
|
1824
|
+
newUiTabLabel={newUiTabLabel}
|
|
1825
|
+
storageKey={storageKey}
|
|
1826
|
+
restoreActiveThread={restoreActiveThread}
|
|
1827
|
+
scope={scope}
|
|
1828
|
+
{...(chatHistory ? { chatHistory } : {})}
|
|
1829
|
+
isolateHistoryByScope={isolateHistoryByScope}
|
|
1830
|
+
showScopeBadge={showScopeBadge}
|
|
1831
|
+
browserTabId={resolvedBrowserTabId}
|
|
1832
|
+
threadUrlSync={threadUrlSync}
|
|
1833
|
+
agentPageHref={agentPageHref}
|
|
1834
|
+
thinkingDisplay={thinkingDisplay}
|
|
1835
|
+
showModelSelector={showModelSelector}
|
|
1836
|
+
chatOnly={chatOnly}
|
|
1837
|
+
/>
|
|
1838
|
+
</Suspense>
|
|
1839
|
+
</LazyChunkErrorBoundary>
|
|
1840
|
+
);
|
|
1841
|
+
|
|
1842
|
+
const sidebar = !shouldRenderPanel ? null : hostedPanel ? (
|
|
1843
|
+
createPortal(
|
|
1844
|
+
<div
|
|
1845
|
+
className="agent-sidebar-panel agent-kit-density flex min-h-0 flex-1 flex-col overflow-hidden"
|
|
1846
|
+
data-agent-sidebar-layout="hosted"
|
|
1847
|
+
data-agent-sidebar-state={panelOpen ? "open" : "closed"}
|
|
1848
|
+
inert={!panelOpen || undefined}
|
|
1849
|
+
>
|
|
1850
|
+
<div
|
|
1851
|
+
ref={panelElementRef}
|
|
1852
|
+
className="agent-sidebar-panel-inner relative flex min-h-0 flex-1 flex-col"
|
|
1853
|
+
>
|
|
1854
|
+
{panelBody}
|
|
1855
|
+
</div>
|
|
1856
|
+
</div>,
|
|
1857
|
+
hostedPanel,
|
|
1858
|
+
)
|
|
1859
|
+
) : (
|
|
1717
1860
|
<>
|
|
1718
1861
|
{showResizeHandle && !isLeft && (
|
|
1719
1862
|
<ResizeHandle
|
|
@@ -1766,92 +1909,7 @@ export function AgentSidebar({
|
|
|
1766
1909
|
ref={panelElementRef}
|
|
1767
1910
|
className="agent-sidebar-panel-inner relative flex min-h-0 flex-1 flex-col"
|
|
1768
1911
|
>
|
|
1769
|
-
|
|
1770
|
-
fallback={<LazyChunkRetryFallback />}
|
|
1771
|
-
shouldHandleError={isPanelImportError}
|
|
1772
|
-
onError={onPanelLoadFailed}
|
|
1773
|
-
>
|
|
1774
|
-
<Suspense
|
|
1775
|
-
fallback={
|
|
1776
|
-
<div
|
|
1777
|
-
aria-hidden="true"
|
|
1778
|
-
className="flex min-h-0 flex-1 flex-col gap-3 p-3"
|
|
1779
|
-
>
|
|
1780
|
-
<Skeleton className="h-8 w-full" />
|
|
1781
|
-
<div className="flex-1" />
|
|
1782
|
-
<Skeleton className="h-28 w-full rounded-xl" />
|
|
1783
|
-
</div>
|
|
1784
|
-
}
|
|
1785
|
-
>
|
|
1786
|
-
<AgentSidebarPanel
|
|
1787
|
-
onReadyChange={onPanelReadyChange}
|
|
1788
|
-
onReferenceTargetChange={onReferenceTargetChange}
|
|
1789
|
-
onNavigationChange={onNavigationChange}
|
|
1790
|
-
onTabsClosing={onTabsClosing}
|
|
1791
|
-
emptyStateText={emptyStateText}
|
|
1792
|
-
mcpSuggestionExcludedIntegrationIds={
|
|
1793
|
-
mcpSuggestionExcludedIntegrationIds
|
|
1794
|
-
}
|
|
1795
|
-
suggestions={suggestions}
|
|
1796
|
-
dynamicSuggestions={dynamicSuggestions}
|
|
1797
|
-
suggestionPlacement="context-chips"
|
|
1798
|
-
composerToolbarSlot={composerToolbarSlot}
|
|
1799
|
-
composerSlot={composerSlot}
|
|
1800
|
-
composerContextProvider={composerContextProvider}
|
|
1801
|
-
onComposerTextChange={onComposerTextChange}
|
|
1802
|
-
imageModelMenu={imageModelMenu}
|
|
1803
|
-
availableAgents={effectiveAvailableAgents}
|
|
1804
|
-
availableModels={availableModels}
|
|
1805
|
-
modelListLoading={modelListLoading}
|
|
1806
|
-
selectedAgent={effectiveSelectedAgent}
|
|
1807
|
-
onAgentChange={effectiveOnAgentChange}
|
|
1808
|
-
hostedHarness={hostedHarnessEnabled}
|
|
1809
|
-
onConnectProvider={onConnectProvider}
|
|
1810
|
-
builderConnectTransport={builderConnectTransport}
|
|
1811
|
-
onConnectLocalRuntime={onConnectLocalRuntime}
|
|
1812
|
-
runtime={runtime}
|
|
1813
|
-
adapterReloadKey={adapterReloadKey}
|
|
1814
|
-
threadFooterSlot={threadFooterSlot}
|
|
1815
|
-
apiUrl={apiUrl}
|
|
1816
|
-
agentChatSurface={agentChatSurface}
|
|
1817
|
-
desktopIdentityUnauthenticated={desktopIdentityUnauthenticated}
|
|
1818
|
-
desktopIdentityAuthenticated={desktopIdentityAuthenticated}
|
|
1819
|
-
showTabBar={effectiveShowTabBar}
|
|
1820
|
-
suppressInlineOpenApp={suppressInlineOpenApp}
|
|
1821
|
-
composerPlaceholder={composerPlaceholder}
|
|
1822
|
-
showMissingApiKeySetup={showMissingApiKeySetup}
|
|
1823
|
-
setupCardOwner={setupCardOwner}
|
|
1824
|
-
showGuidedQuestions={showGuidedQuestions}
|
|
1825
|
-
missingApiKeySetupLayout="sidebar"
|
|
1826
|
-
defaultMode={defaultMode}
|
|
1827
|
-
onCollapse={() => setOpenPersisted(false)}
|
|
1828
|
-
showCollapseButton={showCollapseButton}
|
|
1829
|
-
onSnapTo75Percent={isOverlay ? undefined : snapTo75Percent}
|
|
1830
|
-
isWideDrawer={isOverlay ? false : isWideDrawer}
|
|
1831
|
-
onExitWideDrawer={isOverlay ? undefined : exitWideDrawer}
|
|
1832
|
-
onFullViewRequest={onFullscreenRequest}
|
|
1833
|
-
onOpenSettings={onOpenSettings}
|
|
1834
|
-
onNewCliTab={onNewCliTab}
|
|
1835
|
-
onNewUiTab={onNewUiTab}
|
|
1836
|
-
renderCliTab={renderCliTab}
|
|
1837
|
-
newTabMode={newTabMode}
|
|
1838
|
-
newCliTabLabel={newCliTabLabel}
|
|
1839
|
-
newUiTabLabel={newUiTabLabel}
|
|
1840
|
-
storageKey={storageKey}
|
|
1841
|
-
restoreActiveThread={restoreActiveThread}
|
|
1842
|
-
scope={scope}
|
|
1843
|
-
chatHistory={chatHistory}
|
|
1844
|
-
isolateHistoryByScope={isolateHistoryByScope}
|
|
1845
|
-
showScopeBadge={showScopeBadge}
|
|
1846
|
-
browserTabId={resolvedBrowserTabId}
|
|
1847
|
-
threadUrlSync={threadUrlSync}
|
|
1848
|
-
agentPageHref={agentPageHref}
|
|
1849
|
-
thinkingDisplay={thinkingDisplay}
|
|
1850
|
-
showModelSelector={showModelSelector}
|
|
1851
|
-
chatOnly={chatOnly}
|
|
1852
|
-
/>
|
|
1853
|
-
</Suspense>
|
|
1854
|
-
</LazyChunkErrorBoundary>
|
|
1912
|
+
{panelBody}
|
|
1855
1913
|
</div>
|
|
1856
1914
|
</div>
|
|
1857
1915
|
{showResizeHandle && isLeft && (
|
|
@@ -1866,7 +1924,7 @@ export function AgentSidebar({
|
|
|
1866
1924
|
/>
|
|
1867
1925
|
)}
|
|
1868
1926
|
</>
|
|
1869
|
-
)
|
|
1927
|
+
);
|
|
1870
1928
|
|
|
1871
1929
|
const drawerPlaceholder =
|
|
1872
1930
|
wideDrawerEnabled && !presentationMode && panelOpen ? (
|
|
@@ -1928,7 +1986,9 @@ export function AgentSidebar({
|
|
|
1928
1986
|
className="agent-sidebar-main-surface flex flex-1 flex-col overflow-auto min-w-0"
|
|
1929
1987
|
data-agent-sidebar-main-position={effectivePosition}
|
|
1930
1988
|
data-agent-sidebar-main-state={
|
|
1931
|
-
!isOverlay && !presentationMode && panelOpen
|
|
1989
|
+
!isOverlay && !hostedPanel && !presentationMode && panelOpen
|
|
1990
|
+
? "open"
|
|
1991
|
+
: "closed"
|
|
1932
1992
|
}
|
|
1933
1993
|
data-agent-sidebar-resizing={isResizing ? "true" : undefined}
|
|
1934
1994
|
>
|
|
@@ -1972,6 +2032,15 @@ function isComposerReferenceEvent(event: Event): boolean {
|
|
|
1972
2032
|
);
|
|
1973
2033
|
}
|
|
1974
2034
|
|
|
2035
|
+
// A send that names its tab, or opens a new one, already knows where it lands.
|
|
2036
|
+
// The chat the panel happens to show meanwhile is not its recipient, so a
|
|
2037
|
+
// switch away from that chat must not cancel it.
|
|
2038
|
+
function sendsToOwnTab(
|
|
2039
|
+
submit: ReturnType<typeof parseSubmitChatMessage>,
|
|
2040
|
+
): boolean {
|
|
2041
|
+
return Boolean(submit?.targetTabId || submit?.newTab);
|
|
2042
|
+
}
|
|
2043
|
+
|
|
1975
2044
|
function isPanelNavigationEvent(event: Event): boolean {
|
|
1976
2045
|
return (
|
|
1977
2046
|
event.type === "agent-chat:open-thread" || event.type === "agent-task-open"
|
|
@@ -195,7 +195,7 @@ export interface AssistantChatAdapterContext {
|
|
|
195
195
|
|
|
196
196
|
export interface AssistantChatProps {
|
|
197
197
|
/** API endpoint URL. Default: "/_agent-native/agent-chat" */
|
|
198
|
-
apiUrl?: string;
|
|
198
|
+
apiUrl?: string | undefined;
|
|
199
199
|
/** Optional Nitro response-streaming endpoint, usually supplied by VITE_AGENT_NATIVE_AGENT_CHAT_STREAM_URL. */
|
|
200
200
|
streamingUrl?: string;
|
|
201
201
|
/** Stable tab identifier passed to the adapter for event correlation */
|
|
@@ -218,21 +218,21 @@ export interface AssistantChatProps {
|
|
|
218
218
|
* Identifies which surface hosts this chat. Defaults to "app", which keeps
|
|
219
219
|
* dev filesystem/bash code-editing tools out of in-product sidebars.
|
|
220
220
|
*/
|
|
221
|
-
agentChatSurface?: AgentChatSurfaceKind;
|
|
221
|
+
agentChatSurface?: AgentChatSurfaceKind | undefined;
|
|
222
222
|
/** Whether the desktop host is currently showing its unauthenticated identity gate. */
|
|
223
|
-
desktopIdentityUnauthenticated?: boolean;
|
|
223
|
+
desktopIdentityUnauthenticated?: boolean | undefined;
|
|
224
224
|
/** Whether the desktop host has just established its authenticated identity session. */
|
|
225
|
-
desktopIdentityAuthenticated?: boolean;
|
|
225
|
+
desktopIdentityAuthenticated?: boolean | undefined;
|
|
226
226
|
/** Route completed first-party open_app calls through the host app pane. */
|
|
227
|
-
suppressInlineOpenApp?: boolean;
|
|
227
|
+
suppressInlineOpenApp?: boolean | undefined;
|
|
228
228
|
/** Placeholder text for empty state */
|
|
229
|
-
emptyStateText?: string;
|
|
229
|
+
emptyStateText?: string | undefined;
|
|
230
230
|
/** Initial empty-thread starters. Completed turns use the runtime's model-authored suggestions. */
|
|
231
|
-
suggestions?: AgentSuggestionInput[];
|
|
231
|
+
suggestions?: AgentSuggestionInput[] | undefined;
|
|
232
232
|
/** Initial empty-thread suggestion behavior; never disables or replaces runtime follow-ups. */
|
|
233
|
-
dynamicSuggestions?: AgentDynamicSuggestionsOption;
|
|
233
|
+
dynamicSuggestions?: AgentDynamicSuggestionsOption | undefined;
|
|
234
234
|
/** Exclude providers whose connection flow is handled by the host app. */
|
|
235
|
-
mcpSuggestionExcludedIntegrationIds?: readonly string[];
|
|
235
|
+
mcpSuggestionExcludedIntegrationIds?: readonly string[] | undefined;
|
|
236
236
|
/** Where suggestions appear. Context chips use a next-action bar at the thread base. */
|
|
237
237
|
suggestionPlacement?:
|
|
238
238
|
| "empty-state"
|
|
@@ -298,7 +298,9 @@ export interface AssistantChatProps {
|
|
|
298
298
|
/** Optional ordering policy for assistant message text and attached widgets. */
|
|
299
299
|
resolveMessageContentOrder?: AgentMessageContentOrderResolver;
|
|
300
300
|
/** App-owned context controller, mounted separately for each chat thread. */
|
|
301
|
-
composerContextProvider?:
|
|
301
|
+
composerContextProvider?:
|
|
302
|
+
| React.ComponentType<AssistantChatComposerContextProviderProps>
|
|
303
|
+
| undefined;
|
|
302
304
|
/** Optional home content rendered above the composer on an empty chat. */
|
|
303
305
|
homeIntroSlot?: React.ReactNode;
|
|
304
306
|
/** Optional content rendered below the composer on an empty chat. */
|
|
@@ -309,17 +311,17 @@ export interface AssistantChatProps {
|
|
|
309
311
|
* Host apps can use this to render contextual, non-destructive affordances
|
|
310
312
|
* beside the shared composer without replacing the composer stack.
|
|
311
313
|
*/
|
|
312
|
-
onComposerTextChange?: (text: string) => void;
|
|
314
|
+
onComposerTextChange?: ((text: string) => void) | undefined;
|
|
313
315
|
/** Class applied to the shared composer area for host-specific sizing/skin. */
|
|
314
316
|
composerAreaClassName?: string;
|
|
315
317
|
/** Placeholder for the shared composer in its normal idle state. */
|
|
316
|
-
composerPlaceholder?: string;
|
|
318
|
+
composerPlaceholder?: string | undefined;
|
|
317
319
|
/** Controls the compactness of the provider setup panel attached above the composer. */
|
|
318
320
|
missingApiKeySetupLayout?: BuilderSetupCardLayout;
|
|
319
321
|
/** Hide the provider setup panel when another host surface owns that prompt. */
|
|
320
|
-
showMissingApiKeySetup?: boolean;
|
|
322
|
+
showMissingApiKeySetup?: boolean | undefined;
|
|
321
323
|
/** Keep chat-owned recovery cards hidden when the host renders the setup card. */
|
|
322
|
-
setupCardOwner?: "chat" | "host";
|
|
324
|
+
setupCardOwner?: "chat" | "host" | undefined;
|
|
323
325
|
/** Visual density for the shared composer shell. */
|
|
324
326
|
composerLayoutVariant?: AgentComposerLayoutVariant;
|
|
325
327
|
/** Center the composer on a fresh empty chat instead of pinning it low. */
|
|
@@ -331,7 +333,7 @@ export interface AssistantChatProps {
|
|
|
331
333
|
/** Optional action rendered beside the voice/send controls. */
|
|
332
334
|
composerExtraActionButton?: React.ReactNode;
|
|
333
335
|
/** Show the framework model picker in the shared composer. Defaults to true. */
|
|
334
|
-
showModelSelector?: boolean;
|
|
336
|
+
showModelSelector?: boolean | undefined;
|
|
335
337
|
/** Disable the composer for capability-gated surfaces while still showing history. */
|
|
336
338
|
composerDisabled?: boolean;
|
|
337
339
|
/** Block sending while keeping the composer editable. */
|
|
@@ -357,14 +359,16 @@ export interface AssistantChatProps {
|
|
|
357
359
|
/** Selected effort override for this conversation */
|
|
358
360
|
selectedEffort?: ReasoningEffort;
|
|
359
361
|
/** Available engine/model list for the model picker */
|
|
360
|
-
availableModels?:
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
362
|
+
availableModels?:
|
|
363
|
+
| Array<{
|
|
364
|
+
engine: string;
|
|
365
|
+
label: string;
|
|
366
|
+
models: string[];
|
|
367
|
+
configured: boolean;
|
|
368
|
+
}>
|
|
369
|
+
| undefined;
|
|
366
370
|
/** Whether the model list is still being resolved. */
|
|
367
|
-
modelListLoading?: boolean;
|
|
371
|
+
modelListLoading?: boolean | undefined;
|
|
368
372
|
/** Whether the model list failed to load. */
|
|
369
373
|
modelListError?: boolean;
|
|
370
374
|
/** Retry loading a host-managed model list. */
|
|
@@ -374,24 +378,24 @@ export interface AssistantChatProps {
|
|
|
374
378
|
/** Callback when user picks an effort from the picker */
|
|
375
379
|
onEffortChange?: (effort: ReasoningEffort) => void;
|
|
376
380
|
/** Local or hosted agent runtimes shown above the model list. */
|
|
377
|
-
availableAgents?: ComposerAgentOption[];
|
|
381
|
+
availableAgents?: ComposerAgentOption[] | undefined;
|
|
378
382
|
/** Selected agent runtime identifier. */
|
|
379
|
-
selectedAgent?: string;
|
|
383
|
+
selectedAgent?: string | undefined;
|
|
380
384
|
/** Mark the selected runtime as the hosted tools-only harness mode. */
|
|
381
385
|
hostedHarness?: boolean;
|
|
382
386
|
/** Callback when the user picks an agent runtime. */
|
|
383
|
-
onAgentChange?: (agent: string) => void;
|
|
387
|
+
onAgentChange?: ((agent: string) => void) | undefined;
|
|
384
388
|
/**
|
|
385
389
|
* Optional secondary model menu (e.g. an image-generation model) shown inside
|
|
386
390
|
* the composer's model picker. Opt-in; chat-only apps omit it.
|
|
387
391
|
*/
|
|
388
|
-
imageModelMenu?: ComposerImageModelMenu;
|
|
392
|
+
imageModelMenu?: ComposerImageModelMenu | undefined;
|
|
389
393
|
/** Callback when user clicks "Fork Chat" in the message actions menu */
|
|
390
394
|
onForkChat?: () => void | boolean | Promise<void | boolean>;
|
|
391
395
|
/** Override Builder/provider connect routing for embedded hosts. */
|
|
392
|
-
onConnectProvider?: () => void;
|
|
396
|
+
onConnectProvider?: (() => void) | undefined;
|
|
393
397
|
/** Route local runtime setup through the host's native bridge. */
|
|
394
|
-
onConnectLocalRuntime?: (engine: string) => void;
|
|
398
|
+
onConnectLocalRuntime?: ((engine: string) => void) | undefined;
|
|
395
399
|
/**
|
|
396
400
|
* Controls the shared composer + menu. Sidebar keeps the full menu by default;
|
|
397
401
|
* hosts without the sidebar provider stack can use upload-only.
|
|
@@ -400,13 +404,13 @@ export interface AssistantChatProps {
|
|
|
400
404
|
/** Replace the built-in transport with an AgentKit-native BYO transport. */
|
|
401
405
|
createTransport?: (context: AssistantChatAdapterContext) => AgentTransport;
|
|
402
406
|
/** Hide the default guided-question card when another host owns its flow. */
|
|
403
|
-
showGuidedQuestions?: boolean;
|
|
407
|
+
showGuidedQuestions?: boolean | undefined;
|
|
404
408
|
/**
|
|
405
409
|
* Bring-your-own agent runtime. When supplied, AssistantChat keeps the
|
|
406
410
|
* standard composer/transcript/tool rendering shell but sends turns through
|
|
407
411
|
* this runtime instead of the built-in Agent-Native SSE endpoint.
|
|
408
412
|
*/
|
|
409
|
-
runtime?: AgentChatRuntime;
|
|
413
|
+
runtime?: AgentChatRuntime | undefined;
|
|
410
414
|
/**
|
|
411
415
|
* Explicitly recreate an injected adapter or runtime when its identity
|
|
412
416
|
* changes. Omit for the production sidebar so parent rerenders do not reset
|
|
@@ -446,5 +450,5 @@ export interface AssistantChatProps {
|
|
|
446
450
|
* let the reader's own preference apply, which is what surfaces the in-chat
|
|
447
451
|
* control — a pinned mode hides it rather than leaving a dead menu item.
|
|
448
452
|
*/
|
|
449
|
-
thinkingDisplay?: ThinkingDisplay;
|
|
453
|
+
thinkingDisplay?: ThinkingDisplay | undefined;
|
|
450
454
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// @vitest-environment happy-dom
|
|
2
|
+
import { sendToAgentChat } from "@agent-native/core/client/agent-chat";
|
|
2
3
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
3
4
|
import { act } from "react";
|
|
4
5
|
import { createRoot, type Root } from "react-dom/client";
|
|
@@ -6,6 +7,10 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
6
7
|
|
|
7
8
|
import { EmbeddedExtension } from "./EmbeddedExtension.js";
|
|
8
9
|
|
|
10
|
+
vi.mock("@agent-native/core/client/agent-chat", () => ({
|
|
11
|
+
sendToAgentChat: vi.fn(),
|
|
12
|
+
}));
|
|
13
|
+
|
|
9
14
|
vi.mock("./extension-links.js", () => ({
|
|
10
15
|
extensionFrameNameWithLinkNonce: (nonce: string) => `frame-${nonce}`,
|
|
11
16
|
// No nonce leaves the frame without a src, so nothing loads.
|
|
@@ -17,6 +22,7 @@ describe("EmbeddedExtension height reports", () => {
|
|
|
17
22
|
let root: Root;
|
|
18
23
|
|
|
19
24
|
beforeEach(() => {
|
|
25
|
+
vi.mocked(sendToAgentChat).mockClear();
|
|
20
26
|
vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);
|
|
21
27
|
vi.stubGlobal(
|
|
22
28
|
"fetch",
|
|
@@ -35,6 +41,45 @@ describe("EmbeddedExtension height reports", () => {
|
|
|
35
41
|
root = createRoot(container);
|
|
36
42
|
});
|
|
37
43
|
|
|
44
|
+
it("holds a frame-submitted chat turn for host confirmation", async () => {
|
|
45
|
+
await act(async () => {
|
|
46
|
+
root.render(
|
|
47
|
+
<QueryClientProvider client={new QueryClient()}>
|
|
48
|
+
<EmbeddedExtension
|
|
49
|
+
extensionId="extension-1"
|
|
50
|
+
slotId="dashboard-panel-status"
|
|
51
|
+
/>
|
|
52
|
+
</QueryClientProvider>,
|
|
53
|
+
);
|
|
54
|
+
});
|
|
55
|
+
await vi.waitFor(() =>
|
|
56
|
+
expect(container.querySelector("iframe")).not.toBeNull(),
|
|
57
|
+
);
|
|
58
|
+
const iframe = container.querySelector("iframe");
|
|
59
|
+
await act(async () => {
|
|
60
|
+
window.dispatchEvent(
|
|
61
|
+
new MessageEvent("message", {
|
|
62
|
+
source: iframe?.contentWindow,
|
|
63
|
+
data: {
|
|
64
|
+
type: "agent-native-send-to-chat",
|
|
65
|
+
message: "Forged on load",
|
|
66
|
+
submit: true,
|
|
67
|
+
},
|
|
68
|
+
}),
|
|
69
|
+
);
|
|
70
|
+
});
|
|
71
|
+
expect(sendToAgentChat).not.toHaveBeenCalled();
|
|
72
|
+
const dialog = document.querySelector('[role="alertdialog"]');
|
|
73
|
+
expect(dialog?.textContent).toContain("Forged on load");
|
|
74
|
+
const send = Array.from(dialog?.querySelectorAll("button") ?? []).find(
|
|
75
|
+
(button) => button.textContent === "Send to agent",
|
|
76
|
+
);
|
|
77
|
+
await act(async () => send?.click());
|
|
78
|
+
expect(sendToAgentChat).toHaveBeenCalledWith(
|
|
79
|
+
expect.objectContaining({ message: "Forged on load", submit: true }),
|
|
80
|
+
);
|
|
81
|
+
});
|
|
82
|
+
|
|
38
83
|
afterEach(() => {
|
|
39
84
|
act(() => root.unmount());
|
|
40
85
|
container.remove();
|