@agent-native/core 0.157.6 → 0.157.8

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 (93) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/agent-native.config.ts +5 -0
  3. package/corpus/templates/analytics/netlify.toml +1 -0
  4. package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +23 -5
  5. package/corpus/templates/analytics/server/plugins/agent-chat.ts +4 -0
  6. package/corpus/templates/assets/netlify.toml +3 -0
  7. package/corpus/templates/brain/netlify.toml +3 -0
  8. package/corpus/templates/calendar/agent-native.config.ts +5 -0
  9. package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +4 -1
  10. package/corpus/templates/calendar/netlify.toml +3 -0
  11. package/corpus/templates/chat/agent-native.config.ts +5 -0
  12. package/corpus/templates/chat/netlify.toml +3 -0
  13. package/corpus/templates/clips/actions/lib/meeting-content.ts +28 -0
  14. package/corpus/templates/clips/actions/list-meetings.ts +33 -11
  15. package/corpus/templates/clips/app/i18n/en-US.ts +1 -0
  16. package/corpus/templates/clips/app/lib/meeting-history-query.ts +11 -0
  17. package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +47 -21
  18. package/corpus/templates/clips/netlify.toml +4 -0
  19. package/corpus/templates/content/netlify.toml +3 -0
  20. package/corpus/templates/design/app/i18n-data.ts +2 -0
  21. package/corpus/templates/design/netlify.toml +3 -0
  22. package/corpus/templates/dispatch/netlify.toml +3 -0
  23. package/corpus/templates/factory/netlify.toml +3 -0
  24. package/corpus/templates/forms/netlify.toml +3 -0
  25. package/corpus/templates/macros/netlify.toml +3 -0
  26. package/corpus/templates/mail/agent-native.config.ts +5 -0
  27. package/corpus/templates/mail/netlify.toml +3 -0
  28. package/corpus/templates/plan/netlify.toml +3 -0
  29. package/corpus/templates/slides/netlify.toml +3 -0
  30. package/dist/agent/harness/acp-adapter.js +17 -2
  31. package/dist/agent/harness/ai-sdk-adapter.js +14 -3
  32. package/dist/agent/harness/background.js +10 -5
  33. package/dist/agent/harness/hosted.d.ts +20 -0
  34. package/dist/agent/harness/hosted.js +100 -0
  35. package/dist/agent/harness/runner.js +100 -77
  36. package/dist/agent/observational-memory/observer.js +12 -0
  37. package/dist/agent/production-agent.d.ts +3 -0
  38. package/dist/agent/production-agent.js +74 -4
  39. package/dist/agent/thread-data-builder.d.ts +12 -0
  40. package/dist/agent/thread-data-builder.js +23 -0
  41. package/dist/agent/types.d.ts +6 -0
  42. package/dist/client/AgentPanel.d.ts +5 -1
  43. package/dist/client/AgentPanel.js +113 -17
  44. package/dist/client/AgentTaskCard.d.ts +2 -2
  45. package/dist/client/AgentTaskCard.js +8 -22
  46. package/dist/client/AssistantChat.d.ts +8 -0
  47. package/dist/client/AssistantChat.js +106 -59
  48. package/dist/client/MultiTabAssistantChat.js +50 -6
  49. package/dist/client/NewWorkspaceAppFlow.js +7 -1
  50. package/dist/client/agent-chat-adapter.d.ts +6 -0
  51. package/dist/client/agent-chat-adapter.js +36 -8
  52. package/dist/client/app-chat-sidebar.d.ts +5 -0
  53. package/dist/client/app-chat-sidebar.js +53 -9
  54. package/dist/client/chat/composer-draft.d.ts +4 -0
  55. package/dist/client/chat/composer-draft.js +63 -0
  56. package/dist/client/chat-first/apps-rail.js +10 -1
  57. package/dist/client/chat-first/primary-nav.js +10 -5
  58. package/dist/client/frame-protocol.d.ts +1 -0
  59. package/dist/client/hooks/index.d.ts +1 -1
  60. package/dist/client/hooks/index.js +1 -1
  61. package/dist/client/i18n.js +5 -2
  62. package/dist/client/progress/RunsTray.js +129 -16
  63. package/dist/client/settings/SettingsRow.js +1 -1
  64. package/dist/client/use-chat-threads.js +11 -6
  65. package/dist/config.d.ts +11 -0
  66. package/dist/config.js +52 -0
  67. package/dist/extensions/actions.js +22 -1
  68. package/dist/hosted-harness/actions/get-hosted-harness-config.d.ts +2 -0
  69. package/dist/hosted-harness/actions/get-hosted-harness-config.js +13 -0
  70. package/dist/hosted-harness/actions/set-hosted-harness-enabled.d.ts +4 -0
  71. package/dist/hosted-harness/actions/set-hosted-harness-enabled.js +32 -0
  72. package/dist/localization/default-messages.d.ts +4 -1
  73. package/dist/localization/default-messages.js +5 -2
  74. package/dist/notifications/routes.d.ts +1 -1
  75. package/dist/provider-api/actions/custom-provider-registration.d.ts +6 -6
  76. package/dist/provider-api/actions/provider-api.d.ts +4 -4
  77. package/dist/server/action-discovery.js +12 -0
  78. package/dist/server/agent-chat-plugin.js +24 -4
  79. package/dist/server/agent-teams.d.ts +20 -12
  80. package/dist/server/agent-teams.js +69 -35
  81. package/dist/server/hosted-harness-policy.d.ts +17 -0
  82. package/dist/server/hosted-harness-policy.js +38 -0
  83. package/dist/server/poll.d.ts +4 -4
  84. package/dist/server/poll.js +45 -13
  85. package/dist/server/realtime-token.d.ts +1 -1
  86. package/dist/server/request-context.d.ts +4 -0
  87. package/dist/styles/agent-native.css +39 -0
  88. package/dist/templates/chat/agent-native.config.ts +5 -0
  89. package/dist/templates/chat/netlify.toml +3 -0
  90. package/dist/vite/action-types-plugin.js +8 -0
  91. package/package.json +5 -3
  92. package/src/templates/chat/agent-native.config.ts +5 -0
  93. package/src/templates/chat/netlify.toml +3 -0
@@ -25,6 +25,7 @@ import { Tooltip as DesignSystemTooltip } from "@agent-native/toolkit/design-sys
25
25
  import { IconMessageCircle, IconMessageDots, IconTerminal2, IconSettings, IconLayoutSidebarRightCollapse, IconLayoutGrid, IconCheck, IconPlus, IconX, IconDotsVertical, IconHistory, IconArrowsHorizontal, IconArrowsMaximize, IconExternalLink, IconShare3, } from "@tabler/icons-react";
26
26
  import React, { useState, useEffect, useRef, useCallback, useMemo, lazy, Suspense, startTransition, } from "react";
27
27
  import { flushSync } from "react-dom";
28
+ import { hostedHarnessAgentOption, isHostedHarnessConfigured, isHostedHarnessRuntime, normalizeHostedHarnessRuntimes, } from "../agent/harness/hosted.js";
28
29
  import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuTrigger, } from "./components/ui/dropdown-menu.js";
29
30
  import { normalizeTooltipText } from "./components/ui/tooltip.js";
30
31
  import { ErrorReportActions } from "./ErrorReportActions.js";
@@ -44,7 +45,8 @@ import { withBuilderUtmTrackingParams } from "../shared/builder-link-tracking.js
44
45
  import { AGENT_SIDEBAR_MIN_WIDTH, consumeAgentSidebarUrlOpenOverride, clampAgentSidebarWidth, dispatchAgentSidebarStateChange, getAgentSidebarMaxWidth, getInitialAgentSidebarOpen, getAgentSidebarWideWidth, setAgentSidebarOpenPreference, subscribeAgentSidebarUrlChanges, SIDEBAR_STATE_CHANGE_EVENT, } from "./agent-sidebar-state.js";
45
46
  import { trackEvent } from "./analytics.js";
46
47
  import { agentNativePath, appPath, isWorkspaceAppPath } from "./api-path.js";
47
- import { APP_CHAT_SIDEBAR_STATE_EVENT, APP_CHAT_SIDEBAR_STATE_REQUEST_MESSAGE, buildAppChatSidebarStateMessage, isPerAppChatStorageKey, } from "./app-chat-sidebar.js";
48
+ import { APP_CHAT_SIDEBAR_STATE_EVENT, APP_CHAT_SIDEBAR_STATE_REQUEST_MESSAGE, buildAppChatSidebarStateMessage, isPerAppChatStorageKey, requestPerAppChatCommand, usePerAppChatState, } from "./app-chat-sidebar.js";
49
+ import { injectedAgentNativeConfig } from "./app-config.js";
48
50
  import { readClientAppState } from "./application-state.js";
49
51
  import { assistantUiRecoverableRenderErrorKind } from "./assistant-ui-recovery.js";
50
52
  import { shouldParentFrameOwnAgentPanel } from "./builder-frame.js";
@@ -58,6 +60,7 @@ import { useFirstRunOnboardingGateOwnsSurface } from "./onboarding/first-run-sta
58
60
  import { useOnboardingPreviewMode } from "./onboarding/use-preview-mode.js";
59
61
  import { recoverFromStaleChunkError } from "./route-chunk-recovery.js";
60
62
  import { withBuilderConnectTrackingParams } from "./settings/useBuilderStatus.js";
63
+ import { useActionQuery } from "./use-action.js";
61
64
  import { useScreenRefreshKey } from "./use-db-sync.js";
62
65
  import { useDevMode } from "./use-dev-mode.js";
63
66
  import { cn } from "./utils.js";
@@ -957,6 +960,7 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
957
960
  __html: "@media (hover:hover) and (pointer:fine){" +
958
961
  ".agent-sidebar-chat-header[data-agent-sidebar-chat-header]{opacity:0;pointer-events:none;transition:opacity 150ms ease-out;}" +
959
962
  ".agent-panel-root:hover .agent-sidebar-chat-header[data-agent-sidebar-chat-header],.agent-panel-root:focus-within .agent-sidebar-chat-header[data-agent-sidebar-chat-header],.agent-sidebar-chat-header[data-agent-sidebar-chat-header][data-agent-sidebar-chat-header-active]{opacity:1;pointer-events:auto;}" +
963
+ ".agent-sidebar-panel[data-agent-sidebar-per-app-chat='true'] .agent-sidebar-chat-header[data-agent-sidebar-chat-header]{opacity:1;pointer-events:auto;transition:none;}" +
960
964
  "}" +
961
965
  ".agent-tab-close{opacity:0}.agent-tab:hover .agent-tab-close{opacity:1}" +
962
966
  ".agent-tabs-scroll{scrollbar-width:none;-ms-overflow-style:none;}" +
@@ -1414,9 +1418,43 @@ export function AgentChatSurface({ mode = "panel", className, defaultMode = "cha
1414
1418
  * Wraps app content with a toggleable agent sidebar.
1415
1419
  * Use AgentToggleButton in your header to open/close it.
1416
1420
  */
1417
- export function AgentSidebar({ children, emptyStateText = "How can I help you?", suggestions, dynamicSuggestions, composerToolbarSlot, composerSlot, onComposerTextChange, imageModelMenu, availableAgents, selectedAgent, onAgentChange, onConnectLocalRuntime, runtime, adapterReloadKey, threadFooterSlot, defaultSidebarWidth, sidebarWidth, position = "right", defaultOpen = false, animateMobile = true, animateDesktop = true, chatViewTransition = false, chatViewTransitionHandoff = false, storageKey, openStorageKey, apiUrl, agentChatSurface, showTabBar = true, suppressInlineOpenApp, composerPlaceholder, openOnChatRunning = false, onFullscreenRequest, scope, showScopeBadge, browserTabId, threadUrlSync, agentPageHref, suppressFirstRunOnboarding = false, }) {
1421
+ export function AgentSidebar({ children, emptyStateText = "How can I help you?", suggestions, dynamicSuggestions, composerToolbarSlot, composerSlot, onComposerTextChange, imageModelMenu, availableAgents, availableModels, modelListLoading, selectedAgent, onAgentChange, onConnectLocalRuntime, runtime, adapterReloadKey, threadFooterSlot, defaultSidebarWidth, sidebarWidth, position = "right", defaultOpen = false, animateMobile = true, animateDesktop = true, chatViewTransition = false, chatViewTransitionHandoff = false, storageKey, openStorageKey, apiUrl, agentChatSurface, showTabBar = true, suppressInlineOpenApp, composerPlaceholder, openOnChatRunning = false, onFullscreenRequest, scope, showScopeBadge, browserTabId, threadUrlSync, agentPageHref, suppressFirstRunOnboarding = false, }) {
1422
+ const staticHostedHarnessEnabled = isHostedHarnessConfigured(injectedAgentNativeConfig().harness);
1423
+ const hostedHarnessQuery = useActionQuery("get-hosted-harness-config", undefined, { enabled: staticHostedHarnessEnabled });
1424
+ const hostedHarnessStatus = hostedHarnessQuery.data;
1425
+ const hostedHarnessEnabled = hostedHarnessStatus?.enabled === true;
1426
+ const hostedHarnessRuntimes = useMemo(() => hostedHarnessEnabled
1427
+ ? normalizeHostedHarnessRuntimes(hostedHarnessStatus?.runtimes)
1428
+ : [], [hostedHarnessEnabled, hostedHarnessStatus?.runtimes]);
1429
+ const hostedHarnessUi = hostedHarnessEnabled;
1430
+ const hostedHarnessStorageKey = `agent-native-hosted-harness${storageKey ? `:${storageKey}` : ""}`;
1431
+ const [hostedHarnessRuntime, setHostedHarnessRuntime] = useState("claude-code");
1432
+ const hostedHarnessAgentOptions = useMemo(() => hostedHarnessRuntimes.map(hostedHarnessAgentOption), [hostedHarnessRuntimes]);
1433
+ const effectiveAvailableAgents = hostedHarnessEnabled
1434
+ ? [
1435
+ ...hostedHarnessAgentOptions,
1436
+ ...(availableAgents ?? []).filter((agent) => !isHostedHarnessRuntime(agent.id)),
1437
+ ]
1438
+ : availableAgents;
1439
+ const effectiveSelectedAgent = hostedHarnessEnabled
1440
+ ? hostedHarnessRuntime
1441
+ : selectedAgent;
1442
+ const effectiveOnAgentChange = hostedHarnessEnabled
1443
+ ? (agent) => {
1444
+ if (isHostedHarnessRuntime(agent)) {
1445
+ setHostedHarnessRuntime(agent);
1446
+ }
1447
+ onAgentChange?.(agent);
1448
+ }
1449
+ : onAgentChange;
1450
+ const effectivePosition = hostedHarnessUi ? "left" : position;
1451
+ const effectiveDefaultOpen = hostedHarnessUi || defaultOpen;
1452
+ const effectiveShowTabBar = hostedHarnessUi || showTabBar;
1453
+ const effectiveAnimateDesktop = hostedHarnessUi ? false : animateDesktop;
1418
1454
  const sidebarOpenStorageKey = openStorageKey ?? storageKey;
1419
1455
  const isPerAppChatSidebar = isPerAppChatStorageKey(sidebarOpenStorageKey);
1456
+ const perAppChatState = usePerAppChatState(!isPerAppChatSidebar);
1457
+ const isPerAppChatHosted = !isPerAppChatSidebar && perAppChatState.hosted === true;
1420
1458
  const onboardingPreviewMode = useOnboardingPreviewMode();
1421
1459
  const firstRunOnboardingGateOwnsSurface = useFirstRunOnboardingGateOwnsSurface();
1422
1460
  const showFirstRunOnboarding = !firstRunOnboardingGateOwnsSurface &&
@@ -1424,7 +1462,7 @@ export function AgentSidebar({ children, emptyStateText = "How can I help you?",
1424
1462
  (SHOW_FIRST_RUN_ONBOARDING || onboardingPreviewMode);
1425
1463
  const initialWidth = defaultSidebarWidth ?? sidebarWidth ?? 380;
1426
1464
  const [open, setOpen] = useState(() => openOnChatRunning ||
1427
- getInitialAgentSidebarOpen(defaultOpen, sidebarOpenStorageKey));
1465
+ getInitialAgentSidebarOpen(effectiveDefaultOpen, sidebarOpenStorageKey));
1428
1466
  const [presentationMode, setPresentationMode] = useState(false);
1429
1467
  const [width, setWidth] = useState(initialWidth);
1430
1468
  const [isWideDrawer, setIsWideDrawer] = useState(() => {
@@ -1485,6 +1523,45 @@ export function AgentSidebar({ children, emptyStateText = "How can I help you?",
1485
1523
  return value;
1486
1524
  });
1487
1525
  }, [sidebarOpenStorageKey]);
1526
+ useEffect(() => {
1527
+ try {
1528
+ const saved = localStorage.getItem(hostedHarnessStorageKey);
1529
+ if (saved && isHostedHarnessRuntime(saved)) {
1530
+ setHostedHarnessRuntime(saved);
1531
+ }
1532
+ }
1533
+ catch {
1534
+ // coercion-ok: localStorage is optional persistence; memory state remains authoritative.
1535
+ // The picker falls back to Claude Code when storage is unavailable.
1536
+ }
1537
+ }, [hostedHarnessStorageKey]);
1538
+ useEffect(() => {
1539
+ if (!hostedHarnessEnabled || hostedHarnessRuntimes.length === 0)
1540
+ return;
1541
+ const next = hostedHarnessRuntimes.includes(hostedHarnessRuntime)
1542
+ ? hostedHarnessRuntime
1543
+ : hostedHarnessRuntimes[0];
1544
+ if (!next)
1545
+ return;
1546
+ if (next !== hostedHarnessRuntime)
1547
+ setHostedHarnessRuntime(next);
1548
+ try {
1549
+ localStorage.setItem(hostedHarnessStorageKey, next);
1550
+ }
1551
+ catch {
1552
+ // coercion-ok: localStorage is optional persistence; memory state remains authoritative.
1553
+ // The selected runtime remains in memory for this tab.
1554
+ }
1555
+ }, [
1556
+ hostedHarnessEnabled,
1557
+ hostedHarnessRuntimes,
1558
+ hostedHarnessRuntime,
1559
+ hostedHarnessStorageKey,
1560
+ ]);
1561
+ useEffect(() => {
1562
+ if (hostedHarnessUi)
1563
+ setOpenPersisted(true);
1564
+ }, [hostedHarnessUi, setOpenPersisted]);
1488
1565
  const applyUrlOpenOverride = useCallback(() => {
1489
1566
  const override = consumeAgentSidebarUrlOpenOverride(sidebarOpenStorageKey);
1490
1567
  if (override !== null)
@@ -1495,9 +1572,9 @@ export function AgentSidebar({ children, emptyStateText = "How can I help you?",
1495
1572
  return subscribeAgentSidebarUrlChanges(applyUrlOpenOverride);
1496
1573
  }, [applyUrlOpenOverride]);
1497
1574
  useEffect(() => {
1498
- if (openOnChatRunning)
1575
+ if (openOnChatRunning && !isPerAppChatHosted)
1499
1576
  setOpen(true);
1500
- }, [openOnChatRunning]);
1577
+ }, [isPerAppChatHosted, openOnChatRunning]);
1501
1578
  // Track whether the frame is controlling the sidebar (code mode = frame active).
1502
1579
  // Default to true when inside an iframe — assume the frame sidebar is active
1503
1580
  // until told otherwise. This prevents both sidebars flashing after hot reloads.
@@ -1519,7 +1596,8 @@ export function AgentSidebar({ children, emptyStateText = "How can I help you?",
1519
1596
  const [hasFrameSidebarState, setHasFrameSidebarState] = useState(false);
1520
1597
  const [backgroundPanelActive, setBackgroundPanelActive] = useState(false);
1521
1598
  const [runningTabIds, setRunningTabIds] = useState(() => new Set());
1522
- const shouldMountPanel = !presentationMode &&
1599
+ const shouldMountPanel = !isPerAppChatHosted &&
1600
+ !presentationMode &&
1523
1601
  (!frameCodeMode || !shouldParentFrameOwnAgentPanel()) &&
1524
1602
  (open || backgroundPanelActive || runningTabIds.size > 0);
1525
1603
  const shouldMountPanelRef = useRef(shouldMountPanel);
@@ -1531,10 +1609,12 @@ export function AgentSidebar({ children, emptyStateText = "How can I help you?",
1531
1609
  // Skip the initial emit in frame-owned mode — wait until the frame has
1532
1610
  // sent us its real sidebar state. Once we know, this effect re-runs and
1533
1611
  // dispatches the correct value.
1534
- if (frameOwned && !hasFrameSidebarState)
1612
+ if (frameOwned && !hasFrameSidebarState && !isPerAppChatHosted)
1535
1613
  return;
1536
1614
  dispatchAgentSidebarStateChange({
1537
- open: !presentationMode && (frameOwned ? frameSidebarOpen : open),
1615
+ open: isPerAppChatHosted
1616
+ ? perAppChatState.open
1617
+ : !presentationMode && (frameOwned ? frameSidebarOpen : open),
1538
1618
  source: frameOwned ? "frame" : "app",
1539
1619
  mode: frameOwned ? "code" : "app",
1540
1620
  });
@@ -1544,6 +1624,8 @@ export function AgentSidebar({ children, emptyStateText = "How can I help you?",
1544
1624
  open,
1545
1625
  presentationMode,
1546
1626
  hasFrameSidebarState,
1627
+ isPerAppChatHosted,
1628
+ perAppChatState.open,
1547
1629
  ]);
1548
1630
  useEffect(() => {
1549
1631
  if (!isPerAppChatSidebar)
@@ -1583,7 +1665,7 @@ export function AgentSidebar({ children, emptyStateText = "How can I help you?",
1583
1665
  ? detail.tabId
1584
1666
  : "__default__";
1585
1667
  if (detail?.isRunning === true) {
1586
- if (openOnChatRunning)
1668
+ if (openOnChatRunning && !isPerAppChatHosted)
1587
1669
  setOpen(true);
1588
1670
  setRunningTabIds((prev) => {
1589
1671
  const next = new Set(prev);
@@ -1609,7 +1691,7 @@ export function AgentSidebar({ children, emptyStateText = "How can I help you?",
1609
1691
  window.removeEventListener(AGENT_PANEL_PREPARE_EVENT, preparePanel);
1610
1692
  window.removeEventListener(AGENT_CHAT_RUNNING_EVENT, handleChatRunning);
1611
1693
  };
1612
- }, [openOnChatRunning, setOpenPersisted]);
1694
+ }, [isPerAppChatHosted, openOnChatRunning, setOpenPersisted]);
1613
1695
  useEffect(() => {
1614
1696
  const replayAfterMount = (type, event) => {
1615
1697
  if (shouldMountPanelRef.current)
@@ -1639,6 +1721,10 @@ export function AgentSidebar({ children, emptyStateText = "How can I help you?",
1639
1721
  }, [setOpenPersisted]);
1640
1722
  useEffect(() => {
1641
1723
  const toggleHandler = () => {
1724
+ if (isPerAppChatHosted) {
1725
+ requestPerAppChatCommand("toggle");
1726
+ return;
1727
+ }
1642
1728
  if (frameCodeMode && shouldParentFrameOwnAgentPanel()) {
1643
1729
  // Forward toggle to frame parent — the frame sidebar handles it
1644
1730
  window.parent.postMessage({ type: "agentNative.toggleSidebar" }, parentFrameTargetOrigin());
@@ -1648,6 +1734,10 @@ export function AgentSidebar({ children, emptyStateText = "How can I help you?",
1648
1734
  }
1649
1735
  };
1650
1736
  const openHandler = () => {
1737
+ if (isPerAppChatHosted) {
1738
+ requestPerAppChatCommand("open");
1739
+ return;
1740
+ }
1651
1741
  if (frameCodeMode && shouldParentFrameOwnAgentPanel()) {
1652
1742
  window.parent.postMessage({ type: "agentNative.toggleSidebar", data: { open: true } }, parentFrameTargetOrigin());
1653
1743
  }
@@ -1656,6 +1746,10 @@ export function AgentSidebar({ children, emptyStateText = "How can I help you?",
1656
1746
  }
1657
1747
  };
1658
1748
  const closeHandler = () => {
1749
+ if (isPerAppChatHosted) {
1750
+ requestPerAppChatCommand("close");
1751
+ return;
1752
+ }
1659
1753
  if (frameCodeMode && shouldParentFrameOwnAgentPanel()) {
1660
1754
  window.parent.postMessage({ type: "agentNative.toggleSidebar", data: { open: false } }, parentFrameTargetOrigin());
1661
1755
  }
@@ -1671,7 +1765,7 @@ export function AgentSidebar({ children, emptyStateText = "How can I help you?",
1671
1765
  window.removeEventListener("agent-panel:open", openHandler);
1672
1766
  window.removeEventListener("agent-panel:close", closeHandler);
1673
1767
  };
1674
- }, [setOpenPersisted, frameCodeMode]);
1768
+ }, [setOpenPersisted, frameCodeMode, isPerAppChatHosted]);
1675
1769
  // Listen for sidebar mode commands from the frame parent.
1676
1770
  // When frame is in "code" mode, hide the app sidebar.
1677
1771
  // When frame is in "app" mode, show the app sidebar, sync width and panel mode.
@@ -1848,10 +1942,10 @@ export function AgentSidebar({ children, emptyStateText = "How can I help you?",
1848
1942
  }, [runDrawerMorph, drawerPlaceholderWidth, isWideDrawer]);
1849
1943
  const handleResizeStart = useCallback(() => setIsResizing(true), []);
1850
1944
  const handleResizeEnd = useCallback(() => setIsResizing(false), []);
1851
- const isLeft = position === "left";
1945
+ const isLeft = effectivePosition === "left";
1852
1946
  const wideDrawerEnabled = isWideDrawer && !isMobile;
1853
1947
  const mobileAnimationEnabled = !presentationMode && isMobile && animateMobile;
1854
- const desktopAnimationEnabled = !presentationMode && !isMobile && animateDesktop;
1948
+ const desktopAnimationEnabled = !presentationMode && !isMobile && effectiveAnimateDesktop;
1855
1949
  const sidebarAnimationEnabled = mobileAnimationEnabled || desktopAnimationEnabled;
1856
1950
  const [renderAnimatedPanel, setRenderAnimatedPanel] = useState(shouldMountPanel);
1857
1951
  useEffect(() => {
@@ -1940,6 +2034,7 @@ export function AgentSidebar({ children, emptyStateText = "How can I help you?",
1940
2034
  background: "var(--agent-sidebar-background)",
1941
2035
  width: desktopAnimationEnabled ? undefined : width,
1942
2036
  maxHeight: "var(--agent-native-viewport-height, 100vh)",
2037
+ zIndex: hostedHarnessUi ? SIDEBAR_OVERLAY_Z_INDEX : undefined,
1943
2038
  borderLeft: !panelOpen || isLeft || showResizeHandle
1944
2039
  ? "none"
1945
2040
  : "1px solid hsl(var(--border))",
@@ -1956,17 +2051,18 @@ export function AgentSidebar({ children, emptyStateText = "How can I help you?",
1956
2051
  }
1957
2052
  // Mount the live chat surface only while visible or actively needed. Keeping
1958
2053
  // it mounted while closed starts app-state polling on every public page view.
1959
- const sidebar = shouldRenderPanel ? (_jsxs(_Fragment, { children: [showResizeHandle && !isLeft && (_jsx(ResizeHandle, { position: position, onDrag: handleDrag, onResizeStart: handleResizeStart, onResizeEnd: handleResizeEnd })), _jsx("div", { className: cn("agent-sidebar-panel flex shrink-0 flex-col overflow-hidden text-[13px] leading-[1.2] antialiased", chatViewTransition && AGENT_CHAT_VIEW_TRANSITION_CLASS), "data-agent-sidebar-animation": wideDrawerEnabled
2054
+ const sidebar = shouldRenderPanel ? (_jsxs(_Fragment, { children: [showResizeHandle && !isLeft && (_jsx(ResizeHandle, { position: effectivePosition, onDrag: handleDrag, onResizeStart: handleResizeStart, onResizeEnd: handleResizeEnd })), _jsx("div", { className: cn("agent-sidebar-panel flex shrink-0 flex-col overflow-hidden text-[13px] leading-[1.2] antialiased", chatViewTransition && AGENT_CHAT_VIEW_TRANSITION_CLASS), "data-agent-sidebar-animation": wideDrawerEnabled
1960
2055
  ? "drawer"
1961
2056
  : mobileAnimationEnabled
1962
2057
  ? "mobile"
1963
2058
  : desktopAnimationEnabled
1964
2059
  ? "desktop"
1965
- : undefined, "data-agent-sidebar-layout": panelLayout, "data-agent-sidebar-position": position, "data-agent-sidebar-state": panelOpen ? "open" : "closed", "data-agent-sidebar-per-app-chat": isPerAppChatSidebar ? "true" : undefined, "data-agent-sidebar-resizing": isResizing ? "true" : undefined, "data-agent-sidebar-chat-handoff": chatViewTransitionHandoff ? "true" : undefined, style: chatViewTransition
2060
+ : undefined, "data-agent-sidebar-layout": panelLayout, "data-agent-sidebar-position": effectivePosition, "data-agent-native-hosted-harness-ui": hostedHarnessUi ? "desktop" : undefined, "data-agent-sidebar-state": panelOpen ? "open" : "closed", "data-agent-sidebar-per-app-chat": isPerAppChatSidebar ? "true" : undefined, "data-agent-sidebar-resizing": isResizing ? "true" : undefined, "data-agent-sidebar-chat-handoff": chatViewTransitionHandoff ? "true" : undefined, style: chatViewTransition
1966
2061
  ? getAgentChatViewTransitionStyle(panelStyle)
1967
- : panelStyle, inert: sidebarAnimationEnabled && !panelOpen ? true : undefined, "aria-hidden": sidebarAnimationEnabled && !panelOpen ? true : undefined, children: _jsx("div", { className: "agent-sidebar-panel-inner flex min-h-0 flex-1 flex-col", children: _jsx(AgentPanel, { emptyStateText: emptyStateText, suggestions: suggestions, dynamicSuggestions: dynamicSuggestions, composerToolbarSlot: composerToolbarSlot, composerSlot: composerSlot, onComposerTextChange: onComposerTextChange, imageModelMenu: imageModelMenu, availableAgents: availableAgents, selectedAgent: selectedAgent, onAgentChange: onAgentChange, onConnectLocalRuntime: onConnectLocalRuntime, runtime: runtime, adapterReloadKey: adapterReloadKey, threadFooterSlot: threadFooterSlot, apiUrl: apiUrl, agentChatSurface: agentChatSurface, showTabBar: showTabBar, suppressInlineOpenApp: suppressInlineOpenApp, composerPlaceholder: composerPlaceholder, missingApiKeySetupLayout: "sidebar", onCollapse: () => setOpenPersisted(false), onSnapTo75Percent: isMobile ? undefined : snapTo75Percent, isWideDrawer: isMobile ? false : isWideDrawer, onExitWideDrawer: isMobile ? undefined : exitWideDrawer, onFullViewRequest: onFullscreenRequest, storageKey: storageKey, scope: scope, showScopeBadge: showScopeBadge, browserTabId: browserTabId, threadUrlSync: threadUrlSync, agentPageHref: agentPageHref, allowSettingsMode: false, chatOnly: true }) }) }), showResizeHandle && isLeft && (_jsx(ResizeHandle, { position: position, onDrag: handleDrag, onResizeStart: handleResizeStart, onResizeEnd: handleResizeEnd }))] })) : null;
2062
+ : panelStyle, inert: sidebarAnimationEnabled && !panelOpen ? true : undefined, "aria-hidden": sidebarAnimationEnabled && !panelOpen ? true : undefined, children: _jsx("div", { className: "agent-sidebar-panel-inner flex min-h-0 flex-1 flex-col", children: _jsx(AgentPanel, { emptyStateText: emptyStateText, suggestions: suggestions, dynamicSuggestions: dynamicSuggestions, composerToolbarSlot: composerToolbarSlot, composerSlot: composerSlot, onComposerTextChange: onComposerTextChange, imageModelMenu: imageModelMenu, availableAgents: effectiveAvailableAgents, availableModels: availableModels, modelListLoading: modelListLoading, selectedAgent: effectiveSelectedAgent, onAgentChange: effectiveOnAgentChange, hostedHarness: hostedHarnessEnabled, onConnectLocalRuntime: onConnectLocalRuntime, runtime: runtime, adapterReloadKey: adapterReloadKey, threadFooterSlot: threadFooterSlot, apiUrl: apiUrl, agentChatSurface: agentChatSurface, showTabBar: effectiveShowTabBar, suppressInlineOpenApp: suppressInlineOpenApp, composerPlaceholder: composerPlaceholder, missingApiKeySetupLayout: "sidebar", onCollapse: () => setOpenPersisted(false), onSnapTo75Percent: isMobile ? undefined : snapTo75Percent, isWideDrawer: isMobile ? false : isWideDrawer, onExitWideDrawer: isMobile ? undefined : exitWideDrawer, onFullViewRequest: onFullscreenRequest, storageKey: storageKey, scope: scope, showScopeBadge: showScopeBadge, browserTabId: browserTabId, threadUrlSync: threadUrlSync, agentPageHref: agentPageHref, allowSettingsMode: false, chatOnly: true }) }) }), showResizeHandle && isLeft && (_jsx(ResizeHandle, { position: effectivePosition, onDrag: handleDrag, onResizeStart: handleResizeStart, onResizeEnd: handleResizeEnd }))] })) : null;
1968
2063
  const drawerPlaceholder = wideDrawerEnabled && !presentationMode && panelOpen ? (_jsx("div", { "aria-hidden": "true", className: "agent-sidebar-drawer-placeholder shrink-0", "data-agent-sidebar-placeholder": "true", style: { width: drawerPlaceholderWidth + 1 } })) : null;
1969
- return (_jsx(AgentSidebarOnboardingContext.Provider, { value: true, children: _jsxs(RealtimeVoiceModeProvider, { browserTabId: browserTabId, children: [showFirstRunOnboarding && (_jsx(Suspense, { fallback: null, children: _jsx(FirstRunOnboarding, {}) })), _jsxs("div", { className: "agent-sidebar-shell flex min-w-0 flex-1 h-screen overflow-hidden", "data-agent-sidebar-position": position, "data-agent-sidebar-resizing": isResizing ? "true" : undefined, children: [isMobile &&
2064
+ return (_jsx(AgentSidebarOnboardingContext.Provider, { value: true, children: _jsxs(RealtimeVoiceModeProvider, { browserTabId: browserTabId, children: [showFirstRunOnboarding && (_jsx(Suspense, { fallback: null, children: _jsx(FirstRunOnboarding, {}) })), _jsxs("div", { className: "agent-sidebar-shell flex min-w-0 flex-1 h-screen overflow-hidden", "data-agent-sidebar-position": effectivePosition, "data-agent-native-hosted-harness-ui": hostedHarnessUi ? "desktop" : undefined, "data-agent-native-hosted-chat": isPerAppChatHosted ? "true" : undefined, "data-agent-sidebar-resizing": isResizing ? "true" : undefined, children: [isMobile &&
2065
+ !isPerAppChatHosted &&
1970
2066
  !presentationMode &&
1971
2067
  (mobileAnimationEnabled ? shouldRenderPanel : open) && (_jsx("div", { className: cn("agent-sidebar-backdrop fixed inset-0 bg-foreground/40", mobileAnimationEnabled && !panelOpen && "pointer-events-none"), "data-agent-sidebar-animation": mobileAnimationEnabled ? "mobile" : undefined, "data-agent-sidebar-state": panelOpen ? "open" : "closed", style: { zIndex: SIDEBAR_OVERLAY_Z_INDEX - 1 }, onClick: () => setOpenPersisted(false) })), shouldMountPanel ? _jsx(URLSync, { browserTabId: browserTabId }) : null, isResizing ? (_jsx("div", { "aria-hidden": "true", className: "agent-sidebar-resize-overlay" })) : null, isLeft && !presentationMode ? sidebar : null, isLeft && !presentationMode ? drawerPlaceholder : null, _jsx("div", { className: "agent-sidebar-main-surface flex flex-1 flex-col overflow-auto min-w-0", "data-agent-sidebar-main-position": position, "data-agent-sidebar-main-state": !isMobile && !presentationMode && panelOpen ? "open" : "closed", "data-agent-sidebar-resizing": isResizing ? "true" : undefined, children: _jsx(ScreenRefreshBoundary, { children: children }) }), !isLeft && !presentationMode ? drawerPlaceholder : null, !isLeft && !presentationMode ? sidebar : null] })] }) }));
1972
2068
  }
@@ -6,7 +6,7 @@ export interface AgentTaskCardProps {
6
6
  onOpen?: (threadId: string) => void;
7
7
  }
8
8
  /**
9
- * Rich preview card for a sub-agent task. Listens for agent-task-event
10
- * CustomEvents to update its state in real-time.
9
+ * Inline tool-call presentation for a spawned sub-agent. Listens for
10
+ * agent-task-event CustomEvents to update its streamed output in real-time.
11
11
  */
12
12
  export declare function AgentTaskCard({ taskId, threadId, description, onOpen, }: AgentTaskCardProps): React.JSX.Element;
@@ -1,5 +1,5 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { IconLoader2, IconCheck, IconChevronRight, IconExternalLink, IconAlertCircle, IconPlayerStop, IconSubtask, } from "@tabler/icons-react";
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { IconLoader2, IconChevronRight, IconExternalLink, IconAlertCircle, IconPlayerStop, IconSubtask, } from "@tabler/icons-react";
3
3
  import { useState, useEffect, useRef, useCallback } from "react";
4
4
  import ReactMarkdown from "react-markdown";
5
5
  import remarkGfm from "remark-gfm";
@@ -7,8 +7,8 @@ import { agentNativePath } from "./api-path.js";
7
7
  import { useT } from "./i18n.js";
8
8
  import { cn } from "./utils.js";
9
9
  /**
10
- * Rich preview card for a sub-agent task. Listens for agent-task-event
11
- * CustomEvents to update its state in real-time.
10
+ * Inline tool-call presentation for a spawned sub-agent. Listens for
11
+ * agent-task-event CustomEvents to update its streamed output in real-time.
12
12
  */
13
13
  export function AgentTaskCard({ taskId, threadId, description, onOpen, }) {
14
14
  const t = useT();
@@ -127,24 +127,10 @@ export function AgentTaskCard({ taskId, threadId, description, onOpen, }) {
127
127
  const isError = status === "errored";
128
128
  const taskTitle = description.trim() || "Task";
129
129
  const currentStepText = currentStep.trim();
130
- const statusLabel = isRunning ? "Running" : isError ? "Error" : "Done";
131
- const statusClassName = cn("inline-flex h-5 shrink-0 items-center gap-1 rounded-md px-1.5 text-[10px] font-medium", isError
132
- ? "bg-destructive/10 text-destructive"
133
- : isComplete
134
- ? "bg-emerald-500/10 text-emerald-600 dark:text-emerald-400"
135
- : "bg-muted text-muted-foreground");
136
130
  const displayText = isComplete && summary ? summary : preview;
137
131
  const hasContent = displayText.length > 0;
138
- const emptyMessage = isRunning
139
- ? "Waiting for updates"
140
- : isError
141
- ? "No error details yet"
142
- : "No summary available";
143
- return (_jsxs("div", { className: cn("my-2 overflow-hidden rounded-lg border bg-background/50 transition-colors", isError
144
- ? "border-destructive/30"
145
- : isComplete
146
- ? "border-emerald-500/20"
147
- : "border-border"), children: [_jsxs("button", { type: "button", "aria-expanded": expanded, className: "flex w-full items-center gap-2 px-3 py-2 text-start transition-colors hover:bg-muted/45", onClick: () => setExpanded(!expanded), children: [_jsxs("span", { className: "inline-flex h-5 shrink-0 items-center gap-1 rounded-md border border-border/60 bg-background/70 px-1.5 text-[10px] font-medium text-muted-foreground", children: [_jsx(IconSubtask, { className: "h-3 w-3" }), t("agentTask.backgroundTask")] }), _jsx("span", { className: "min-w-0 flex-1 truncate text-xs font-medium text-foreground", children: taskTitle }), _jsxs("span", { className: statusClassName, children: [isRunning ? (_jsx(IconLoader2, { className: "h-3 w-3 animate-spin" })) : isError ? (_jsx(IconAlertCircle, { className: "h-3 w-3" })) : (_jsx(IconCheck, { className: "h-3 w-3" })), statusLabel] }), _jsx(IconChevronRight, { className: cn("h-3 w-3 shrink-0 text-muted-foreground/40 transition-transform duration-150", expanded && "rotate-90", "rtl:-scale-x-100") })] }), expanded && isRunning && currentStepText && (_jsxs("div", { className: "flex gap-1.5 border-t border-border/60 px-3 py-1.5 text-[11px] text-muted-foreground", children: [_jsx("span", { className: "shrink-0 font-medium text-foreground/70", children: "Now:" }), _jsx("span", { className: "min-w-0 break-words", children: currentStepText })] })), expanded && hasContent && (_jsx("div", { className: "px-3 pb-2 pt-1", children: _jsx("div", { ref: previewRef, className: "agent-markdown prose prose-sm prose-invert max-h-48 max-w-none overflow-y-auto break-words rounded-md border border-border/50 bg-muted/25 px-3 py-2 text-xs text-muted-foreground", children: _jsx(ReactMarkdown, { remarkPlugins: [remarkGfm], children: displayText.length > 800
148
- ? "..." + displayText.slice(-800)
149
- : displayText }) }) })), expanded && (_jsxs("div", { className: "flex items-center justify-between gap-2 px-3 pb-2", children: [_jsx("span", { className: "min-w-0 flex-1 truncate text-[10px] text-muted-foreground/60", children: !hasContent ? emptyMessage : "" }), _jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [isRunning && (_jsxs("button", { onClick: handleStop, className: "inline-flex cursor-pointer items-center gap-1 rounded-md px-2 py-1 text-[11px] font-medium text-muted-foreground hover:bg-muted hover:text-destructive", "aria-label": t("agentTask.stop"), children: [_jsx(IconPlayerStop, { className: "h-3 w-3" }), "Stop"] })), _jsxs("button", { onClick: handleOpen, className: "inline-flex cursor-pointer items-center gap-1 rounded-md px-2 py-1 text-[11px] font-medium text-muted-foreground hover:bg-muted hover:text-foreground", children: [t("agentTask.openThread"), _jsx(IconExternalLink, { className: "h-3 w-3" })] })] })] }))] }));
132
+ const statusLabel = isRunning ? "Running" : isError ? "Error" : "Done";
133
+ return (_jsxs("div", { className: "group/agent my-0.5 w-full", children: [_jsxs("button", { type: "button", "aria-expanded": expanded, className: "flex w-full items-center gap-1.5 rounded-md py-0.5 text-left text-[13px] text-muted-foreground transition-colors hover:text-foreground", onClick: () => setExpanded(!expanded), children: [_jsx("span", { className: "relative flex size-4 shrink-0 items-center justify-center", children: isRunning ? (_jsx(IconLoader2, { className: "size-3.5 animate-spin" })) : isError ? (_jsx(IconAlertCircle, { className: "size-3.5 text-destructive" })) : (_jsxs(_Fragment, { children: [_jsx(IconSubtask, { className: cn("size-3.5 transition-opacity", "group-hover/agent:opacity-0") }), _jsx(IconChevronRight, { className: cn("absolute size-3.5 opacity-0 transition-[opacity,transform] group-hover/agent:opacity-100", expanded && "rotate-90") })] })) }), _jsxs("span", { className: cn("min-w-0 truncate font-normal", isRunning && "agent-running-shimmer"), children: [t("agentTask.spawnedAgent"), ": ", taskTitle] }), _jsx("span", { className: "sr-only", children: statusLabel })] }), expanded && (_jsxs("div", { className: "ms-1 border-s border-border/50 ps-2 pt-1", children: [isRunning && currentStepText && (_jsx("p", { className: "ps-5 pb-1 text-xs text-muted-foreground", "aria-live": "polite", children: currentStepText })), hasContent && (_jsx("div", { className: "ps-5 pb-1", children: _jsx("div", { ref: previewRef, "aria-live": isRunning ? "polite" : undefined, "data-streaming": isRunning ? "true" : undefined, className: "agent-markdown prose prose-sm prose-invert max-h-48 max-w-none overflow-y-auto break-words text-xs text-muted-foreground", children: _jsx(ReactMarkdown, { remarkPlugins: [remarkGfm], children: displayText.length > 800
134
+ ? "..." + displayText.slice(-800)
135
+ : displayText }) }) })), _jsxs("div", { className: "flex items-center gap-1 ps-5 pb-1", children: [isRunning && (_jsxs("button", { onClick: handleStop, className: "inline-flex cursor-pointer items-center gap-1 rounded-md px-1.5 py-0.5 text-xs text-muted-foreground transition-colors hover:bg-muted hover:text-destructive", "aria-label": t("agentTask.stop"), children: [_jsx(IconPlayerStop, { className: "size-3" }), "Stop"] })), _jsxs("button", { onClick: handleOpen, className: "inline-flex cursor-pointer items-center gap-1 rounded-md px-1.5 py-0.5 text-xs text-muted-foreground transition-colors hover:bg-muted hover:text-foreground", children: [t("agentTask.openThread"), _jsx(IconExternalLink, { className: "size-3" })] })] })] }))] }));
150
136
  }
@@ -242,6 +242,12 @@ export interface AssistantChatAdapterContext {
242
242
  effortRef: {
243
243
  current: ReasoningEffort | undefined;
244
244
  };
245
+ harnessRef?: {
246
+ current: string | undefined;
247
+ };
248
+ hostedHarnessRef?: {
249
+ current: boolean;
250
+ };
245
251
  execModeRef: {
246
252
  current: "build" | "plan" | undefined;
247
253
  };
@@ -369,6 +375,8 @@ export interface AssistantChatProps {
369
375
  availableAgents?: ComposerAgentOption[];
370
376
  /** Selected agent runtime identifier. */
371
377
  selectedAgent?: string;
378
+ /** Mark the selected runtime as the hosted tools-only harness mode. */
379
+ hostedHarness?: boolean;
372
380
  /** Callback when the user picks an agent runtime. */
373
381
  onAgentChange?: (agent: string) => void;
374
382
  /**