@datalayer/agent-runtimes 1.3.89 → 1.3.91

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 (265) hide show
  1. package/lib/Agent.js +2 -18
  2. package/lib/AgentDocument.js +5 -55
  3. package/lib/AgentNode.js +31 -208
  4. package/lib/AgentNotebook.js +5 -59
  5. package/lib/agent-node/AgentNodeGallery.js +23 -111
  6. package/lib/agents/AgentDetails.js +36 -274
  7. package/lib/agents/AgentRuntimeChat.js +1 -8
  8. package/lib/chat/Chat.js +7 -46
  9. package/lib/chat/ChatFloating.js +15 -100
  10. package/lib/chat/ChatInline.js +5 -47
  11. package/lib/chat/ChatPopupStandalone.js +5 -53
  12. package/lib/chat/ChatSidebar.js +4 -51
  13. package/lib/chat/ChatStandalone.js +4 -45
  14. package/lib/chat/EphemeralSurfaceControl.js +5 -25
  15. package/lib/chat/assistant/AssistantContextMenu.d.ts +8 -0
  16. package/lib/chat/assistant/AssistantContextMenu.js +17 -1
  17. package/lib/chat/assistant/AssistantStage.js +6 -25
  18. package/lib/chat/assistant/BalloonParts.js +8 -40
  19. package/lib/chat/assistant/BalloonVisual.js +2 -2
  20. package/lib/chat/assistant/ConversationBalloon.js +2 -11
  21. package/lib/chat/assistant/DecisionAsk.js +3 -3
  22. package/lib/chat/assistant/SandboxDetailsDialog.js +3 -17
  23. package/lib/chat/assistant/SpeechBalloon.js +14 -78
  24. package/lib/chat/base/ChatBase.js +37 -172
  25. package/lib/chat/display/EmptyState.js +7 -35
  26. package/lib/chat/display/FloatingBrandButton.js +4 -34
  27. package/lib/chat/display/PoweredByTag.js +3 -14
  28. package/lib/chat/document/EphemeralDocument.js +3 -18
  29. package/lib/chat/header/ChatHeader.js +1 -17
  30. package/lib/chat/header/ChatHeaderBase.js +2 -24
  31. package/lib/chat/header/ChatViewModeToggle.js +7 -29
  32. package/lib/chat/indicators/McpStatusIndicator.js +3 -12
  33. package/lib/chat/indicators/SandboxStatusIndicator.js +6 -34
  34. package/lib/chat/indicators/SkillsStatusIndicator.js +3 -12
  35. package/lib/chat/indicators/TypingDots.js +1 -11
  36. package/lib/chat/messages/ChatMessageList.js +58 -185
  37. package/lib/chat/messages/ChatMessages.js +15 -79
  38. package/lib/chat/messages/FormSubmissionMessage.js +2 -33
  39. package/lib/chat/messages/NotebookToolSurfaces.js +12 -41
  40. package/lib/chat/messages/TurnFooter.js +4 -10
  41. package/lib/chat/notebook/EphemeralNotebook.js +2 -10
  42. package/lib/chat/parts/ReasoningPart.js +2 -16
  43. package/lib/chat/parts/TextPart.js +2 -12
  44. package/lib/chat/parts/ToolPart.js +16 -90
  45. package/lib/chat/presence/Presence.js +5 -33
  46. package/lib/chat/prompt/FloatingCard.js +1 -13
  47. package/lib/chat/prompt/InputPrompt.js +1 -6
  48. package/lib/chat/prompt/InputPromptBase.js +4 -17
  49. package/lib/chat/prompt/InputPromptLexical.js +44 -45
  50. package/lib/chat/prompt/InputPromptText.js +1 -1
  51. package/lib/chat/prompt/footer/InPromptFooter.js +1 -8
  52. package/lib/chat/prompt/menus/AgentsMenu.js +1 -1
  53. package/lib/chat/prompt/menus/InlineAgentsMenu.js +1 -1
  54. package/lib/chat/prompt/menus/ModelSelector.js +1 -5
  55. package/lib/chat/prompt/menus/SkillsMenu.js +3 -30
  56. package/lib/chat/prompt/menus/SuggestionsMenu.js +1 -1
  57. package/lib/chat/prompt/menus/ToolsMenu.js +4 -48
  58. package/lib/chat/prompt/plugins/AgentMentionPlugin.js +2 -9
  59. package/lib/chat/prompt/plugins/CommandPlugin.js +2 -9
  60. package/lib/chat/prompt/plugins/MentionChip.js +1 -15
  61. package/lib/chat/prompt/stack.js +1 -19
  62. package/lib/chat/tools/A2AAgentDialog.js +9 -42
  63. package/lib/chat/tools/SubagentActivity.js +5 -22
  64. package/lib/chat/tools/ToolApprovalBanner.js +4 -34
  65. package/lib/chat/tools/ToolApprovalDialog.js +4 -19
  66. package/lib/chat/tools/ToolCallDisplay.js +12 -97
  67. package/lib/chat/usage/ContextPie.js +4 -45
  68. package/lib/chat/words.d.ts +7 -0
  69. package/lib/chat/words.js +12 -0
  70. package/lib/components/a2ui/datalayer/Chart.js +4 -10
  71. package/lib/components/a2ui/datalayer/Chat.js +2 -10
  72. package/lib/components/a2ui/datalayer/Download.js +1 -1
  73. package/lib/components/a2ui/datalayer/Evidence.js +1 -15
  74. package/lib/components/a2ui/datalayer/FileUpload.js +1 -12
  75. package/lib/components/a2ui/datalayer/Table.js +9 -17
  76. package/lib/components/a2ui/datalayer/formWidgets.js +3 -2
  77. package/lib/components/a2ui/datalayer/parts.js +1 -16
  78. package/lib/components/a2ui/styles.js +16 -5
  79. package/lib/components/agents/AgentSummary.js +1 -51
  80. package/lib/components/cards/NotificationEventCard.js +6 -72
  81. package/lib/components/cards/OutputCard.js +4 -48
  82. package/lib/components/cards/ToolApprovalCard.js +2 -35
  83. package/lib/components/code-sandboxes/CodeSandboxCellVariables.js +1 -1
  84. package/lib/components/code-sandboxes/CodeSandboxEnvironmentSelect.js +4 -14
  85. package/lib/components/code-sandboxes/CodeSandboxPicker.js +16 -21
  86. package/lib/components/code-sandboxes/CodeSandboxVariables.js +2 -2
  87. package/lib/components/scheduler/ScheduleMenu.js +5 -10
  88. package/lib/components/specs/SpecPayloadPreview.js +1 -26
  89. package/lib/components/teams/A2ATeamGraph.d.ts +4 -3
  90. package/lib/components/teams/A2ATeamGraph.js +25 -71
  91. package/lib/components/teams/AnswerSurfacesView.js +2 -2
  92. package/lib/components/teams/NotebookPreview.js +1 -10
  93. package/lib/components/teams/NotebookPreviewView.js +2 -3
  94. package/lib/components/teams/SceneTranscript.js +3 -17
  95. package/lib/components/teams/SceneView.js +1 -8
  96. package/lib/components/teams/TeamNotebook.js +5 -13
  97. package/lib/components/teams/TeamNotebookView.js +2 -12
  98. package/lib/components/teams/index.d.ts +1 -0
  99. package/lib/components/teams/index.js +1 -0
  100. package/lib/components/teams/useBalloonRoom.d.ts +39 -0
  101. package/lib/components/teams/useBalloonRoom.js +89 -0
  102. package/lib/config/AgentConfiguration.js +22 -225
  103. package/lib/context/ContextDistribution.js +7 -41
  104. package/lib/context/ContextInspector.js +9 -107
  105. package/lib/context/ContextPanel.js +11 -86
  106. package/lib/context/ContextUsage.js +6 -34
  107. package/lib/context/CostTracker.js +7 -42
  108. package/lib/context/MessageHistory.js +3 -37
  109. package/lib/context/TurnGraphChart.js +9 -41
  110. package/lib/examples/A2UiAgentExample.js +6 -108
  111. package/lib/examples/A2UiComponentsGalleryExample.js +1 -1
  112. package/lib/examples/A2UiContactCardExample.js +1 -1
  113. package/lib/examples/A2UiJupyterOutputExample.js +25 -125
  114. package/lib/examples/A2UiRestaurantExample.js +1 -1
  115. package/lib/examples/A2UiViewerExample.js +1 -1
  116. package/lib/examples/AgUiAgenticExample.js +3 -35
  117. package/lib/examples/AgUiBackendToolRenderingExample.js +2 -25
  118. package/lib/examples/AgUiHaikuGenUiExample.js +2 -32
  119. package/lib/examples/AgUiHumanInTheLoopExample.js +5 -59
  120. package/lib/examples/AgUiSharedStateExample.js +6 -56
  121. package/lib/examples/AgUiToolsBasedGenUiExample.js +25 -120
  122. package/lib/examples/AgentA2AExample.js +1 -15
  123. package/lib/examples/AgentA2ATeamExample.js +6 -30
  124. package/lib/examples/AgentCheckpointsExample.js +11 -145
  125. package/lib/examples/AgentCodeSandboxExample.js +5 -108
  126. package/lib/examples/AgentCodeSandboxesExample.js +3 -30
  127. package/lib/examples/AgentCodemodeExample.js +9 -85
  128. package/lib/examples/AgentCompactionExample.js +3 -64
  129. package/lib/examples/AgentDecideExample.js +1 -13
  130. package/lib/examples/AgentEvalsExample.js +5 -60
  131. package/lib/examples/AgentGuardrailsExample.js +4 -28
  132. package/lib/examples/AgentHooksExample.js +1 -1
  133. package/lib/examples/AgentInferenceProviderExample.js +5 -96
  134. package/lib/examples/AgentMCPExample.js +7 -105
  135. package/lib/examples/AgentMemoryExample.js +5 -74
  136. package/lib/examples/AgentMonitoringExample.js +7 -53
  137. package/lib/examples/AgentNotificationsExample.js +3 -61
  138. package/lib/examples/AgentOtelExample.js +3 -72
  139. package/lib/examples/AgentOutputsExample.js +6 -81
  140. package/lib/examples/AgentParametersExample.js +2 -37
  141. package/lib/examples/AgentSkillsExample.js +3 -45
  142. package/lib/examples/AgentSubagentsExample.js +6 -56
  143. package/lib/examples/AgentToolApprovalsExample.js +1 -11
  144. package/lib/examples/AgentTriggersExample.js +29 -239
  145. package/lib/examples/AgentspecsExample.js +6 -60
  146. package/lib/examples/AssistantExample.js +5 -5
  147. package/lib/examples/AssistantGalleryExample.js +8 -65
  148. package/lib/examples/CellExample.js +1 -6
  149. package/lib/examples/ChatCustomExample.js +2 -31
  150. package/lib/examples/ChatExample.js +1 -9
  151. package/lib/examples/ChatStandaloneExample.js +3 -37
  152. package/lib/examples/CopilotKitLexicalExample.js +1 -24
  153. package/lib/examples/DecksAgent.js +1 -1
  154. package/lib/examples/DocumentPageAgent.js +1 -1
  155. package/lib/examples/HomeExample.js +14 -62
  156. package/lib/examples/Lexical2Example.js +3 -32
  157. package/lib/examples/LexicalAgentExample.js +2 -34
  158. package/lib/examples/LexicalAgentSidebarExample.js +3 -34
  159. package/lib/examples/LoopAppComputerExample.js +1 -1
  160. package/lib/examples/LoopShellExample.js +2 -2
  161. package/lib/examples/LoopStrategyExample.js +15 -87
  162. package/lib/examples/LoopWorkspaceEmbed.js +2 -18
  163. package/lib/examples/LoopWorkspaceExample.js +2 -2
  164. package/lib/examples/NotebookAgentExample.js +2 -33
  165. package/lib/examples/NotebookAgentSidebarExample.js +3 -46
  166. package/lib/examples/NotebookCollaborationExample.js +1 -31
  167. package/lib/examples/NotebookExample.js +1 -18
  168. package/lib/examples/NotebookPageAgent.js +1 -1
  169. package/lib/examples/ScenesExample.js +5 -24
  170. package/lib/examples/VoiceChatExample.js +1 -1
  171. package/lib/examples/components/AuthRequiredView.js +1 -7
  172. package/lib/examples/components/ErrorView.js +1 -8
  173. package/lib/examples/components/ExampleErrorBoundary.js +1 -14
  174. package/lib/examples/components/FooterMetrics.js +1 -7
  175. package/lib/examples/components/Header.js +12 -51
  176. package/lib/examples/components/HeaderControls.js +1 -9
  177. package/lib/examples/components/LexicalEditor.js +1 -8
  178. package/lib/examples/components/MainContent.js +1 -13
  179. package/lib/examples/components/MockFileBrowser.js +4 -40
  180. package/lib/examples/components/SessionTabs.js +1 -1
  181. package/lib/examples/components/TimeTravel.js +1 -13
  182. package/lib/examples/main.js +13 -81
  183. package/lib/examples/scenes/A2UiComponentsGalleryScene.js +3 -34
  184. package/lib/examples/scenes/A2UiContactCardScene.js +3 -35
  185. package/lib/examples/scenes/A2UiRestaurantScene.js +3 -53
  186. package/lib/examples/scenes/A2UiViewerScene.js +3 -34
  187. package/lib/examples/utils/AssistantGalleryGrid.js +6 -35
  188. package/lib/examples2/DatalayerNotebookExample.js +3 -33
  189. package/lib/examples2/NativeNavigationExample.js +4 -10
  190. package/lib/examples2/NotebookMutationsKernel.js +2 -1
  191. package/lib/examples2/NotebookMutationsServiceManager.js +2 -1
  192. package/lib/examples2/ReactRouterExample.js +14 -42
  193. package/lib/hooks/useToolApprovals.d.ts +2 -34
  194. package/lib/hooks/useToolApprovals.js +1 -64
  195. package/lib/identity/AgentIdentity.js +17 -62
  196. package/lib/identity/IdentityConnect.js +13 -59
  197. package/lib/identity/OAuthCallback.js +6 -44
  198. package/lib/lexical/ChatInlinePlugin.js +6 -14
  199. package/lib/loop/apps/AppFeedback.js +12 -3
  200. package/lib/loop/apps/AppRenderer.d.ts +4 -3
  201. package/lib/loop/apps/AppRenderer.js +11 -12
  202. package/lib/loop/apps/appspec.js +6 -3
  203. package/lib/loop/apps/feedback.d.ts +3 -2
  204. package/lib/loop/apps/feedback.js +4 -2
  205. package/lib/loop/core/index.d.ts +19 -0
  206. package/lib/loop/core/index.js +27 -0
  207. package/lib/loop/embed/AppEmbed.d.ts +1 -1
  208. package/lib/loop/embed/AppEmbed.js +2 -1
  209. package/lib/loop/embed/LoopEmbed.js +1 -7
  210. package/lib/loop/embed/embedConfig.d.ts +3 -3
  211. package/lib/loop/embed/embedConfig.js +2 -3
  212. package/lib/loop/embed/embedTheme.d.ts +4 -4
  213. package/lib/loop/embed/embedTheme.js +11 -7
  214. package/lib/loop/plugins/a2a-sidebar/A2ASidebar.js +7 -34
  215. package/lib/loop/plugins/a2ui/A2uiView.js +4 -12
  216. package/lib/loop/plugins/a2ui-surface/InlineSurface.js +1 -16
  217. package/lib/loop/plugins/a2ui-surface/SurfaceToolResult.js +2 -12
  218. package/lib/loop/plugins/agents/AnonymousKeyBadge.js +3 -2
  219. package/lib/loop/plugins/agents/SandboxSelector.js +3 -7
  220. package/lib/loop/plugins/agents/SandboxView.js +4 -27
  221. package/lib/loop/plugins/agents/TeamMemberPicker.js +2 -2
  222. package/lib/loop/plugins/agentspecs/AgentspecPicker.js +3 -2
  223. package/lib/loop/plugins/app-activity/AppActivity.js +1 -1
  224. package/lib/loop/plugins/app-computer/AppComputer.js +32 -27
  225. package/lib/loop/plugins/app-elements/AppElements.js +2 -31
  226. package/lib/loop/plugins/app-page/AppPage.js +26 -8
  227. package/lib/loop/plugins/app-rules/AppRulesCard.js +4 -20
  228. package/lib/loop/plugins/assistant/index.js +1 -13
  229. package/lib/loop/plugins/chat/ChatView.js +89 -130
  230. package/lib/loop/plugins/checkpoints-sidebar/CheckpointsSidebar.js +2 -13
  231. package/lib/loop/plugins/decks/DeckSurface.js +2 -2
  232. package/lib/loop/plugins/document/DocumentView.js +4 -12
  233. package/lib/loop/plugins/document-toolbar/SandboxStatusItem.js +3 -8
  234. package/lib/loop/plugins/graph/GraphView.js +2 -2
  235. package/lib/loop/plugins/input-prompt/ComposerView.js +1 -1
  236. package/lib/loop/plugins/notebook/NotebookView.js +3 -11
  237. package/lib/loop/plugins/page-layout/SplitLayout.js +11 -34
  238. package/lib/loop/plugins/page-layout/TurnPanel.js +9 -35
  239. package/lib/loop/plugins/shell/useEditorPreviews.js +3 -2
  240. package/lib/loop/plugins/subagent-activity/SubagentPulse.js +1 -13
  241. package/lib/loop/plugins/window-frame/WindowFrame.js +10 -44
  242. package/lib/loop/plugins/window-frame/index.js +1 -1
  243. package/lib/loop/shell/LoopWorkspace.js +34 -77
  244. package/lib/loop/shell/PluginToggles.js +4 -15
  245. package/lib/loop/shell/SidebarRail.js +8 -40
  246. package/lib/loop/shell/ViewSwitcher.js +4 -24
  247. package/lib/loop-main.js +2 -3
  248. package/lib/mcp/McpServerManager.js +6 -37
  249. package/lib/portable/index.d.ts +11 -0
  250. package/lib/portable/index.js +20 -0
  251. package/lib/protocols/AGUIAdapter.js +2 -2
  252. package/lib/protocols/BaseProtocolAdapter.d.ts +2 -0
  253. package/lib/protocols/BaseProtocolAdapter.js +4 -0
  254. package/lib/specs/apps.js +6 -0
  255. package/lib/specs/appspecSchema.js +11 -4
  256. package/lib/stories/loop/ReferenceScreens.js +17 -91
  257. package/lib/stories/loop/pictures-main.js +1 -1
  258. package/lib/types/agentspecs.d.ts +5 -2
  259. package/lib/types/protocol.d.ts +2 -0
  260. package/lib/utils/approvals.d.ts +59 -0
  261. package/lib/utils/approvals.js +101 -0
  262. package/lib/voice/VoiceInput.js +3 -39
  263. package/package.json +2 -2
  264. package/lib/shims/primerAddonsBox.d.ts +0 -1
  265. package/lib/shims/primerAddonsBox.js +0 -7
@@ -147,10 +147,10 @@ export function CodeSandboxVariables(props) {
147
147
  },
148
148
  },
149
149
  ];
150
- return (_jsxs(Box, { className: className, sx: { paddingTop: '10px' }, children: [_jsxs(FormControl, { layout: "horizontal", children: [_jsx(FormControl.Label, { children: trans.__('Transfer variables') }), _jsx(ToggleSwitch, { checked: transferVariables, size: "small", onClick: e => {
150
+ return (_jsxs(Box, { className: className, paddingTop: "10px", children: [_jsxs(FormControl, { layout: "horizontal", children: [_jsx(FormControl.Label, { children: trans.__('Transfer variables') }), _jsx(ToggleSwitch, { checked: transferVariables, size: "small", onClick: e => {
151
151
  e.preventDefault();
152
152
  setTransferVariable(!transferVariables);
153
153
  }, "aria-labelledby": "kernel-toggle-variables" })] }), transferVariables && (_jsxs(Table.Container, { sx: { flex: '1 1 auto', marginTop: 3 }, children: [_jsx(Table.Subtitle, { as: "p", id: "dla-kernel-variables-subtitle", children: trans.__('The list of transferable runtime variables.') }), kernelVariables ? (Object.keys(kernelVariables ?? {}).length ? (_jsx(DataTable, { "aria-labelledby": "dla-kernel-variables", "aria-describedby": "dla-kernel-variables-subtitle", data: Object.entries(kernelVariables ?? {})
154
154
  .map(([name, type], id) => ({ id, name, type }))
155
- .sort((a, b) => (a.name > b.name ? 1 : -1)), columns: columns, cellPadding: "condensed" })) : (_jsx(Box, { sx: { gridArea: 'table' }, children: _jsx(Blankslate, { border: true, children: _jsx(Blankslate.Heading, { children: trans.__('No eligible variables.') }) }) }))) : (_jsx(Table.Skeleton, { "aria-labelledby": "dla-kernel-variables", "aria-describedby": "dla-kernel-variables-subtitle", columns: columns, rows: 5 }))] }))] }));
155
+ .sort((a, b) => (a.name > b.name ? 1 : -1)), columns: columns, cellPadding: "condensed" })) : (_jsx(Box, { gridArea: "table", children: _jsx(Blankslate, { border: true, children: _jsx(Blankslate.Heading, { children: trans.__('No eligible variables.') }) }) }))) : (_jsx(Table.Skeleton, { "aria-labelledby": "dla-kernel-variables", "aria-describedby": "dla-kernel-variables-subtitle", columns: columns, rows: 5 }))] }))] }));
156
156
  }
@@ -4,7 +4,8 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
4
4
  * Distributed under the terms of the Modified BSD License.
5
5
  */
6
6
  import { useEffect, useMemo, useState } from 'react';
7
- import { ActionList, ActionMenu, Box, Button, Dialog, FormControl, IconButton, Spinner, Text, TextInput, } from '@primer/react';
7
+ import { Box } from '@datalayer/primer-addons';
8
+ import { ActionList, ActionMenu, Button, Dialog, FormControl, IconButton, Spinner, Text, TextInput, } from '@primer/react';
8
9
  import { ClockIcon, TrashIcon } from '@primer/octicons-react';
9
10
  import { disableSchedule, updateSchedule, upsertSchedule, } from '../../api/scheduler/schedules';
10
11
  import { DEFAULT_SERVICE_URLS } from '@datalayer/core/lib/api/constants';
@@ -130,23 +131,17 @@ export const ScheduleMenu = ({ notebookUid, scheduleUid, token, baseUrl = DEFAUL
130
131
  ? `${ariaLabel} (saving…)`
131
132
  : isEnabled
132
133
  ? ariaLabel
133
- : `${ariaLabel} (disabled)` }) }), _jsxs(ActionMenu.Overlay, { width: "medium", sx: { minWidth: 300 }, children: [_jsx(Box, { sx: {
134
- px: 3,
135
- pt: 3,
136
- pb: 2,
137
- borderBottom: '1px solid',
138
- borderColor: 'border.default',
139
- }, children: _jsx(Text, { as: "p", sx: { fontWeight: 600 }, children: "Schedule" }) }), _jsx(ActionList, { selectionVariant: "single", showDividers: true, children: SCHEDULE_PRESETS.map(option => (_jsxs(ActionList.Item, { selected: preset === option.id, disabled: !isEnabled, onSelect: () => selectPreset(option.id), children: [option.label, _jsx(ActionList.Description, { variant: "block", children: option.cron })] }, option.id))) }), _jsxs(Box, { sx: { p: 3, borderTop: '1px solid', borderColor: 'border.default' }, children: [_jsx(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted', mb: 2 }, children: "Cron Expression" }), _jsx(TextInput, { value: cronExpression, onChange: event => {
134
+ : `${ariaLabel} (disabled)` }) }), _jsxs(ActionMenu.Overlay, { width: "medium", sx: { minWidth: 300 }, children: [_jsx(Box, { px: 3, pt: 3, pb: 2, borderBottom: "1px solid", borderColor: "border.default", children: _jsx(Text, { as: "p", sx: { fontWeight: 600 }, children: "Schedule" }) }), _jsx(ActionList, { selectionVariant: "single", showDividers: true, children: SCHEDULE_PRESETS.map(option => (_jsxs(ActionList.Item, { selected: preset === option.id, disabled: !isEnabled, onSelect: () => selectPreset(option.id), children: [option.label, _jsx(ActionList.Description, { variant: "block", children: option.cron })] }, option.id))) }), _jsxs(Box, { p: 3, borderTop: "1px solid", borderColor: "border.default", children: [_jsx(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted', mb: 2 }, children: "Cron Expression" }), _jsx(TextInput, { value: cronExpression, onChange: event => {
140
135
  const value = event.currentTarget.value;
141
136
  setHasExplicitCron(value.trim().length > 0);
142
137
  setCronExpression(value);
143
- }, placeholder: "* * * * *", "aria-label": "Cron expression", block: true, disabled: !isEnabled }), _jsxs(Box, { sx: { mt: 2, display: 'flex', gap: 2, flexWrap: 'wrap' }, children: [_jsx(Button, { size: "small", onClick: applyCustomCron, disabled: !isEnabled, children: "Apply Cron" }), scheduleUid ? (_jsx(Button, { size: "small", variant: "danger", leadingVisual: TrashIcon, onClick: () => setIsDeleteDialogOpen(true), disabled: !isEnabled, children: "Delete Schedule" })) : null] }), _jsxs(Text, { as: "p", sx: { mt: 2, fontSize: 0, color: 'fg.muted' }, children: ["Current: ", selectedPresetDescription] })] })] })] }), isDeleteDialogOpen && scheduleUid ? (_jsx(Dialog, { title: "Delete schedule", onClose: () => {
138
+ }, placeholder: "* * * * *", "aria-label": "Cron expression", block: true, disabled: !isEnabled }), _jsxs(Box, { mt: 2, display: "flex", gap: 2, flexWrap: "wrap", children: [_jsx(Button, { size: "small", onClick: applyCustomCron, disabled: !isEnabled, children: "Apply Cron" }), scheduleUid ? (_jsx(Button, { size: "small", variant: "danger", leadingVisual: TrashIcon, onClick: () => setIsDeleteDialogOpen(true), disabled: !isEnabled, children: "Delete Schedule" })) : null] }), _jsxs(Text, { as: "p", sx: { mt: 2, fontSize: 0, color: 'fg.muted' }, children: ["Current: ", selectedPresetDescription] })] })] })] }), isDeleteDialogOpen && scheduleUid ? (_jsx(Dialog, { title: "Delete schedule", onClose: () => {
144
139
  if (isDeleting) {
145
140
  return;
146
141
  }
147
142
  setIsDeleteDialogOpen(false);
148
143
  setDeleteConfirmUid('');
149
- }, width: "medium", children: _jsxs(Box, { sx: { display: 'grid', gap: 3 }, children: [_jsxs(Text, { children: ["This action will disable the schedule and remove planned runs. Type", ' ', _jsx(Text, { as: "span", sx: { fontWeight: 700 }, children: scheduleUid }), ' ', "to confirm."] }), _jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Schedule UID" }), _jsx(TextInput, { value: deleteConfirmUid, onChange: event => setDeleteConfirmUid(event.currentTarget.value), placeholder: scheduleUid, autoFocus: true })] }), _jsxs(Box, { sx: { display: 'flex', justifyContent: 'flex-end', gap: 2 }, children: [_jsx(Button, { variant: "default", onClick: () => {
144
+ }, width: "medium", children: _jsxs(Box, { display: "grid", gap: 3, children: [_jsxs(Text, { children: ["This action will disable the schedule and remove planned runs. Type", ' ', _jsx(Text, { as: "span", sx: { fontWeight: 700 }, children: scheduleUid }), ' ', "to confirm."] }), _jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Schedule UID" }), _jsx(TextInput, { value: deleteConfirmUid, onChange: event => setDeleteConfirmUid(event.currentTarget.value), placeholder: scheduleUid, autoFocus: true })] }), _jsxs(Box, { display: "flex", justifyContent: "flex-end", gap: 2, children: [_jsx(Button, { variant: "default", onClick: () => {
150
145
  setIsDeleteDialogOpen(false);
151
146
  setDeleteConfirmUid('');
152
147
  }, disabled: isDeleting, children: "Cancel" }), _jsx(Button, { variant: "danger", onClick: () => void performDeleteSchedule(), disabled: isDeleting || deleteConfirmUid !== scheduleUid, children: "Delete schedule" })] })] }) })) : null] }));
@@ -72,31 +72,6 @@ export function SpecPayloadPreview({ spec, onClose, title = 'Spec Payload Previe
72
72
  document.addEventListener('keydown', onKeyDown);
73
73
  return () => document.removeEventListener('keydown', onKeyDown);
74
74
  }, [onClose]);
75
- return (_jsxs(Box, { role: "dialog", "aria-label": title, "aria-modal": "true", sx: {
76
- position: 'fixed',
77
- inset: 24,
78
- zIndex: 300,
79
- bg: 'canvas.default',
80
- border: '1px solid',
81
- borderColor: 'border.default',
82
- borderRadius: 1,
83
- boxShadow: 'shadow.large',
84
- display: 'flex',
85
- flexDirection: 'column',
86
- }, children: [_jsxs(Box, { sx: {
87
- display: 'flex',
88
- alignItems: 'center',
89
- justifyContent: 'space-between',
90
- px: 3,
91
- py: 2,
92
- borderBottom: '1px solid',
93
- borderColor: 'border.default',
94
- }, children: [_jsx(Text, { sx: { fontWeight: 'bold' }, children: title }), _jsx(IconButton, { icon: XIcon, "aria-label": "Close spec preview", size: "small", variant: "invisible", onClick: onClose })] }), _jsx(Box, { sx: { p: 3, overflow: 'auto', flex: 1 }, children: _jsx(Box, { as: "pre", sx: {
95
- m: 0,
96
- whiteSpace: 'pre',
97
- fontFamily: 'monospace',
98
- fontSize: 0,
99
- lineHeight: '20px',
100
- }, children: specToYaml(spec) }) })] }));
75
+ return (_jsxs(Box, { role: "dialog", "aria-label": title, "aria-modal": "true", position: "fixed", inset: 24, zIndex: 300, bg: "canvas.default", border: "1px solid", borderColor: "border.default", borderRadius: 1, boxShadow: "shadow.large", display: "flex", flexDirection: "column", children: [_jsxs(Box, { display: "flex", alignItems: "center", justifyContent: "space-between", px: 3, py: 2, borderBottom: "1px solid", borderColor: "border.default", children: [_jsx(Text, { sx: { fontWeight: 'bold' }, children: title }), _jsx(IconButton, { icon: XIcon, "aria-label": "Close spec preview", size: "small", variant: "invisible", onClick: onClose })] }), _jsx(Box, { p: 3, overflow: "auto", flex: 1, children: _jsx(Box, { as: "pre", m: 0, whiteSpace: "pre", fontFamily: "monospace", fontSize: 0, lineHeight: "20px", children: specToYaml(spec) }) })] }));
101
76
  }
102
77
  export default SpecPayloadPreview;
@@ -160,9 +160,10 @@ export type A2ATeamGraphProps = {
160
160
  /** The tool calls running now, to the members' connections (`useA2ATeam`). */
161
161
  calls?: A2ATeamCall[];
162
162
  /**
163
- * The room above the members for their balloons, in pixels at full scale:
164
- * a page that shows suggestions, *more* and a notebook in them gives more.
165
- * A notebook in a balloon gets at least its own.
163
+ * The least room above the members for their balloons, in pixels at full
164
+ * scale: the graph keeps what its balloons take now (`useBalloonRoom`) —
165
+ * suggestions, *more* unfolded — and never less than this. A notebook in
166
+ * a balloon gets at least its own.
166
167
  */
167
168
  balloonRoom?: number;
168
169
  };
@@ -11,6 +11,7 @@ import { SpecMark } from '../../chat/marks/SpecMark';
11
11
  import { toolWords, } from './a2aTeamFlow';
12
12
  import { NotebookPreview } from './NotebookPreview';
13
13
  import { notebookBalloonVisual } from './TeamNotebook';
14
+ import { useBalloonRoom } from './useBalloonRoom';
14
15
  import { toolLineText } from '../../chat/assistant/toolLine';
15
16
  /** The graph's own coordinates: the members, and room above them for their balloons. */
16
17
  const NODE_WIDTH = 200;
@@ -201,17 +202,9 @@ const MemberNode = memo(function MemberNode({ data, }) {
201
202
  // nor selected (`pointer-events: none` on its wrapper): the character,
202
203
  // its balloon and its menu take it back, and are left to themselves —
203
204
  // no drag, no pan, no wheel.
204
- className: "nodrag nopan nowheel", sx: {
205
- width: NODE_WIDTH,
206
- display: 'flex',
207
- flexDirection: 'column',
208
- alignItems: 'center',
209
- gap: 1,
210
- cursor: 'default',
211
- pointerEvents: 'all',
212
- }, "data-team-member": member.id, "data-member-balloon": shown, "data-member-moved": offset.dx || offset.dy
205
+ className: "nodrag nopan nowheel", width: NODE_WIDTH, display: "flex", flexDirection: "column", alignItems: "center", gap: 1, cursor: "default", pointerEvents: "all", "data-team-member": member.id, "data-member-balloon": shown, "data-member-moved": offset.dx || offset.dy
213
206
  ? `${Math.round(offset.dx)},${Math.round(offset.dy)}`
214
- : undefined, "data-member-state": persona.state, children: [_jsx(Handle, { id: MEMBER_HANDLES.inLeft, type: "target", position: Position.Left, style: HANDLE(size), isConnectable: false }), _jsx(Handle, { id: MEMBER_HANDLES.inRight, type: "target", position: Position.Right, style: HANDLE(size), isConnectable: false }), _jsx(Handle, { id: MEMBER_HANDLES.inTop, type: "target", position: Position.Top, style: { ...HANDLE(size), top: 0 }, isConnectable: false }), _jsx(Handle, { id: MEMBER_HANDLES.inBottom, type: "target", position: Position.Bottom, style: { ...HANDLE(size), top: size }, isConnectable: false }), _jsx(Box, { sx: { width: size, height: size, position: 'relative' }, children: persona.away ? (_jsxs(Button, { size: "small", sx: { position: 'absolute', top: size / 2 - 16, left: -24 }, onClick: () => member.onAway?.(false), children: ["Call ", member.name, " back"] })) : (_jsx(AssistantStage, { character: member.character, state: persona.state, size: size,
207
+ : undefined, "data-member-state": persona.state, children: [_jsx(Handle, { id: MEMBER_HANDLES.inLeft, type: "target", position: Position.Left, style: HANDLE(size), isConnectable: false }), _jsx(Handle, { id: MEMBER_HANDLES.inRight, type: "target", position: Position.Right, style: HANDLE(size), isConnectable: false }), _jsx(Handle, { id: MEMBER_HANDLES.inTop, type: "target", position: Position.Top, style: { ...HANDLE(size), top: 0 }, isConnectable: false }), _jsx(Handle, { id: MEMBER_HANDLES.inBottom, type: "target", position: Position.Bottom, style: { ...HANDLE(size), top: size }, isConnectable: false }), _jsx(Box, { width: size, height: size, position: "relative", children: persona.away ? (_jsxs(Button, { size: "small", sx: { position: 'absolute', top: size / 2 - 16, left: -24 }, onClick: () => member.onAway?.(false), children: ["Call ", member.name, " back"] })) : (_jsx(AssistantStage, { character: member.character, state: persona.state, size: size,
215
208
  // In the node, not over the page; the balloon opens toward the
216
209
  // middle of the graph: rightward from the left member.
217
210
  place: side === 'left'
@@ -312,42 +305,16 @@ const ConnectionNode = memo(function ConnectionNode({ id, data, }) {
312
305
  if (!connection) {
313
306
  return null;
314
307
  }
315
- return (_jsxs(Box, { className: "nodrag nopan nowheel", sx: {
316
- width: CONNECTION_WIDTH,
317
- display: 'flex',
318
- flexDirection: 'column',
319
- alignItems: 'center',
320
- gap: '2px',
321
- cursor: 'default',
322
- pointerEvents: 'all',
323
- }, title: connection.name, "data-team-connection": connection.id, "data-connection-busy": tool ? 'true' : 'false', children: [_jsx(Handle, { type: "target", position: Position.Left, style: { ...HANDLE(size), left: 0 }, isConnectable: false }), _jsx(Box, { as: "button", type: "button", className: tool ? 'a2a-team-connection-busy' : undefined, "aria-label": connectionLabel(connection, owner?.name), "aria-expanded": told, "aria-controls": detailsId, "data-connection-figure": "", onClick: () => setTold(shown => !shown), onKeyDown: (event) => {
308
+ return (_jsxs(Box, { className: "nodrag nopan nowheel", width: CONNECTION_WIDTH, display: "flex", flexDirection: "column", alignItems: "center", gap: "2px", cursor: "default", pointerEvents: "all", title: connection.name, "data-team-connection": connection.id, "data-connection-busy": tool ? 'true' : 'false', children: [_jsx(Handle, { type: "target", position: Position.Left, style: { ...HANDLE(size), left: 0 }, isConnectable: false }), _jsx(Box, { as: "button", type: "button", className: tool ? 'a2a-team-connection-busy' : undefined, "aria-label": connectionLabel(connection, owner?.name), "aria-expanded": told, "aria-controls": detailsId, "data-connection-figure": "", onClick: () => setTold(shown => !shown), onKeyDown: (event) => {
324
309
  if (event.key === 'Escape' && told) {
325
310
  event.stopPropagation();
326
311
  setTold(false);
327
312
  }
328
- }, sx: {
329
- width: size,
330
- height: size,
331
- p: 0,
332
- display: 'flex',
333
- alignItems: 'center',
334
- justifyContent: 'center',
335
- borderRadius: 2,
336
- border: '1px solid',
337
- borderColor: tool ? 'accent.emphasis' : 'border.default',
338
- bg: 'canvas.default',
339
- cursor: 'pointer',
340
- '&:focus-visible': {
341
- outline: '2px solid',
342
- outlineColor: 'var(--focus-outlineColor, var(--fgColor-accent))',
343
- outlineOffset: 2,
344
- },
345
- }, children: _jsx(SpecMark, { icon: connection.icon, emoji: connection.emoji, size: Math.round(size * 0.66) }) }), _jsx(Text, { sx: { fontWeight: 600, fontSize: 1, textAlign: 'center' }, children: connection.label }), connection.via && (_jsx(Text, { sx: { fontSize: '10px', color: 'fg.muted', textAlign: 'center' }, "data-connection-via": "", children: connection.via })), _jsx(Box, { id: detailsId, hidden: !told, "data-connection-details": "", sx: {
346
- fontSize: '10px',
347
- color: 'fg.muted',
348
- textAlign: 'center',
349
- maxWidth: CONNECTION_WIDTH + 40,
350
- }, children: connectionDetails(connection, owner?.name, tool) })] }));
313
+ }, width: size, height: size, p: 0, display: "flex", alignItems: "center", justifyContent: "center", borderRadius: 2, border: "1px solid", borderColor: tool ? 'accent.emphasis' : 'border.default', bg: "canvas.default", cursor: "pointer", focusVisible: {
314
+ outline: '2px solid',
315
+ outlineColor: 'var(--focus-outlineColor, var(--fgColor-accent))',
316
+ outlineOffset: 2,
317
+ }, children: _jsx(SpecMark, { icon: connection.icon, emoji: connection.emoji, size: Math.round(size * 0.66) }) }), _jsx(Text, { sx: { fontWeight: 600, fontSize: 1, textAlign: 'center' }, children: connection.label }), connection.via && (_jsx(Text, { sx: { fontSize: '10px', color: 'fg.muted', textAlign: 'center' }, "data-connection-via": "", children: connection.via })), _jsx(Box, { id: detailsId, hidden: !told, "data-connection-details": "", fontSize: "10px", color: "fg.muted", textAlign: "center", maxWidth: CONNECTION_WIDTH + 40, children: connectionDetails(connection, owner?.name, tool) })] }));
351
318
  });
352
319
  /** What a connection's details say: the server, who reaches it, and the call running now. */
353
320
  export function connectionDetails(connection, member, calling) {
@@ -399,12 +366,7 @@ const LinkEdge = memo(function LinkEdge({ id, sourceX, sourceY, targetX, targetY
399
366
  strokeWidth: 2,
400
367
  strokeDasharray: data?.connected ? undefined : '6 6',
401
368
  opacity: flow === 'still' ? 0.6 : 0.25,
402
- } }), flow !== 'still' && (_jsxs("g", { "data-a2a-edge-flow": flow, children: [_jsx("path", { d: path, fill: "none", className: `a2a-team-flow a2a-team-flow-${flow}`, stroke: "var(--fgColor-accent, #0969da)", strokeWidth: 3, strokeLinecap: "round", strokeDasharray: "10 14" }), _jsx("path", { d: arrow, fill: "var(--fgColor-accent, #0969da)" })] })), _jsx(EdgeLabelRenderer, { children: _jsx(Box, { className: "nodrag nopan", sx: {
403
- position: 'absolute',
404
- transform: `translate(-50%, 12px) translate(${(sourceX + targetX) / 2}px, ${(sourceY + targetY) / 2}px)`,
405
- pointerEvents: 'none',
406
- textAlign: 'center',
407
- }, children: _jsx(Label, { variant: data?.connected ? 'accent' : 'secondary', children: data?.label }) }) })] }));
369
+ } }), flow !== 'still' && (_jsxs("g", { "data-a2a-edge-flow": flow, children: [_jsx("path", { d: path, fill: "none", className: `a2a-team-flow a2a-team-flow-${flow}`, stroke: "var(--fgColor-accent, #0969da)", strokeWidth: 3, strokeLinecap: "round", strokeDasharray: "10 14" }), _jsx("path", { d: arrow, fill: "var(--fgColor-accent, #0969da)" })] })), _jsx(EdgeLabelRenderer, { children: _jsx(Box, { className: "nodrag nopan", position: "absolute", transform: `translate(-50%, 12px) translate(${(sourceX + targetX) / 2}px, ${(sourceY + targetY) / 2}px)`, pointerEvents: "none", textAlign: "center", children: _jsx(Label, { variant: data?.connected ? 'accent' : 'secondary', children: data?.label }) }) })] }));
408
370
  });
409
371
  /** A member's link to a connection: still, or flowing toward it while a call runs. */
410
372
  export const CallEdge = memo(function CallEdge({ id, sourceX, sourceY, targetX, targetY, data, }) {
@@ -415,13 +377,9 @@ export const CallEdge = memo(function CallEdge({ id, sourceX, sourceY, targetX,
415
377
  stroke: 'var(--borderColor-default, #d0d7de)',
416
378
  strokeWidth: 2,
417
379
  opacity: calling ? 0.3 : 0.8,
418
- } }), calling && (_jsxs("g", { "data-mcp-edge-call": data?.calling, children: [_jsx("path", { d: path, fill: "none", className: "a2a-team-flow a2a-team-call", stroke: "var(--fgColor-accent, #0969da)", strokeWidth: 3, strokeLinecap: "round", strokeDasharray: "6 8" }), _jsx("path", { d: arrow, fill: "var(--fgColor-accent, #0969da)" })] })), calling && (_jsx(EdgeLabelRenderer, { children: _jsx(Box, { className: "nodrag nopan", sx: {
419
- position: 'absolute',
420
- // Beside the edge, toward the middle of the graph.
421
- transform: `translate(calc(-100% - 10px), -50%) translate(${(sourceX + targetX) / 2}px, ${(sourceY + targetY) / 2}px)`,
422
- pointerEvents: 'none',
423
- whiteSpace: 'nowrap',
424
- }, children: _jsx(Label, { variant: "accent", children: data?.calling }) }) }))] }));
380
+ } }), calling && (_jsxs("g", { "data-mcp-edge-call": data?.calling, children: [_jsx("path", { d: path, fill: "none", className: "a2a-team-flow a2a-team-call", stroke: "var(--fgColor-accent, #0969da)", strokeWidth: 3, strokeLinecap: "round", strokeDasharray: "6 8" }), _jsx("path", { d: arrow, fill: "var(--fgColor-accent, #0969da)" })] })), calling && (_jsx(EdgeLabelRenderer, { children: _jsx(Box, { className: "nodrag nopan", position: "absolute",
381
+ // Beside the edge, toward the middle of the graph.
382
+ transform: `translate(calc(-100% - 10px), -50%) translate(${(sourceX + targetX) / 2}px, ${(sourceY + targetY) / 2}px)`, pointerEvents: "none", whiteSpace: "nowrap", children: _jsx(Label, { variant: "accent", children: data?.calling }) }) }))] }));
425
383
  });
426
384
  const NODE_TYPES = { member: MemberNode, connection: ConnectionNode };
427
385
  const EDGE_TYPES = { a2a: LinkEdge, mcp: CallEdge };
@@ -534,10 +492,16 @@ export function A2ATeamGraph({ entry, peer, peers: more = NO_PEERS, flow, flows,
534
492
  connections: (member.connections ?? []).map(connection => connection.id),
535
493
  }));
536
494
  const placedKey = JSON.stringify(placed);
537
- // A notebook in a balloon: more room above the members.
495
+ // What the balloons take now, at least the room the page gives; a
496
+ // notebook in a balloon, at least its own.
497
+ const measured = useBalloonRoom(box, {
498
+ anchor: '[data-team-member]',
499
+ zoom: viewport.zoom,
500
+ floor: balloonRoom,
501
+ });
538
502
  const room = members.some(member => member.persona.notebook)
539
- ? Math.max(NOTEBOOK_BALLOON_ROOM, balloonRoom)
540
- : balloonRoom;
503
+ ? Math.max(NOTEBOOK_BALLOON_ROOM, measured)
504
+ : measured;
541
505
  // Beside a member, its connections may reach below it: the row takes them.
542
506
  const reach = Math.max(0, ...placed.map(({ connections }) => connectionsReach(size, connections.length, connectionHeight)));
543
507
  const rowHeight = Math.max(memberHeight, reach);
@@ -711,10 +675,7 @@ export function A2ATeamGraph({ entry, peer, peers: more = NO_PEERS, flow, flows,
711
675
  ], [linkKey, placedKey, busy]);
712
676
  const heard = [...words, ...busy.said].filter(Boolean).join('. ');
713
677
  const flowNow = flowOfAll(peers.map(one => flowOf(one.id)));
714
- return (_jsxs(Box, { ref: box, "data-a2a-team-graph": "", "data-a2a-flow": flowNow, "data-a2a-calls": calls.length, "data-a2a-members": members.length, sx: {
715
- width: '100%',
716
- height,
717
- position: 'relative',
678
+ return (_jsxs(Box, { ref: box, "data-a2a-team-graph": "", "data-a2a-flow": flowNow, "data-a2a-calls": calls.length, "data-a2a-members": members.length, width: "100%", height: height, position: "relative", sx: {
718
679
  '@keyframes a2aTeamFlow': {
719
680
  from: { strokeDashoffset: 24 },
720
681
  to: { strokeDashoffset: 0 },
@@ -732,7 +693,7 @@ export function A2ATeamGraph({ entry, peer, peers: more = NO_PEERS, flow, flows,
732
693
  '@keyframes a2aTeamPulse': {
733
694
  '0%, 100%': { boxShadow: '0 0 0 0 transparent' },
734
695
  '50%': {
735
- boxShadow: '0 0 0 4px var(--bgColor-accent-muted, #ddf4ff)',
696
+ boxShadow: '0 0 0 4px var(--bgColor-accent-muted)',
736
697
  },
737
698
  },
738
699
  '& .a2a-team-call': {
@@ -756,14 +717,7 @@ export function A2ATeamGraph({ entry, peer, peers: more = NO_PEERS, flow, flows,
756
717
  '& [data-team-member] [data-assistant-figure]:active': {
757
718
  cursor: 'grabbing',
758
719
  },
759
- }, children: [_jsx(Box, { as: "span", "aria-live": "polite", sx: {
760
- position: 'absolute',
761
- width: 1,
762
- height: 1,
763
- overflow: 'hidden',
764
- clip: 'rect(0 0 0 0)',
765
- whiteSpace: 'nowrap',
766
- }, children: heard }), _jsx(Moving.Provider, { value: movingValue, children: _jsx(Members.Provider, { value: membersById, children: _jsx(Busy.Provider, { value: busy.byNode, children: _jsx(ReactFlow, { nodes: nodes, edges: edges, nodeTypes: NODE_TYPES, edgeTypes: EDGE_TYPES, viewport: viewport, nodesDraggable: false, nodesConnectable: false, nodesFocusable: false, edgesFocusable: false, elementsSelectable: false, deleteKeyCode: null, selectionKeyCode: null, multiSelectionKeyCode: null, panOnDrag: false, panOnScroll: false, zoomOnScroll: false, zoomOnPinch: false, zoomOnDoubleClick: false, preventScrolling: false, style: { overflow: 'visible', background: 'transparent' },
720
+ }, children: [_jsx(Box, { as: "span", "aria-live": "polite", position: "absolute", width: 1, height: 1, overflow: "hidden", clip: "rect(0 0 0 0)", whiteSpace: "nowrap", children: heard }), _jsx(Moving.Provider, { value: movingValue, children: _jsx(Members.Provider, { value: membersById, children: _jsx(Busy.Provider, { value: busy.byNode, children: _jsx(ReactFlow, { nodes: nodes, edges: edges, nodeTypes: NODE_TYPES, edgeTypes: EDGE_TYPES, viewport: viewport, nodesDraggable: false, nodesConnectable: false, nodesFocusable: false, edgesFocusable: false, elementsSelectable: false, deleteKeyCode: null, selectionKeyCode: null, multiSelectionKeyCode: null, panOnDrag: false, panOnScroll: false, zoomOnScroll: false, zoomOnPinch: false, zoomOnDoubleClick: false, preventScrolling: false, style: { overflow: 'visible', background: 'transparent' },
767
721
  // The library is MIT: its credit is not required on the page.
768
722
  proOptions: { hideAttribution: true }, "aria-label": `${entry.name} and ${peers.map(one => one.name).join(', ')}, over A2A` }) }) }) })] }));
769
723
  }
@@ -22,9 +22,9 @@ function OneSurface({ surface, name, onPress, }) {
22
22
  }));
23
23
  }, [answered, onPress, surface]);
24
24
  const title = parsed?.title || surface.artifact.name;
25
- return (_jsxs(Box, { as: "section", "aria-label": name ? `${name}: ${title}` : title, "data-answer-surface": surface.id, sx: { display: 'flex', flexDirection: 'column', gap: 2, minWidth: 0 }, children: [_jsx(Text, { sx: { fontWeight: 'bold', fontSize: 1 }, children: name ? `${name} · ${title}` : title }), parsed?.messages?.length ? (_jsx(InlineSurface, { messages: parsed.messages, onAction: onAction })) : (_jsx(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: "This could not be drawn: it holds no surface." })), answered ? (_jsxs(Box, { role: "status", "data-answer-reply": "", sx: { display: 'flex', flexDirection: 'column', gap: 1, fontSize: 1 }, children: [_jsxs(Text, { sx: { color: 'fg.muted' }, children: ["You chose: ", answered.chose] }), answered.waiting ? (_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(Spinner, { size: "small" }), _jsx(Text, { sx: { color: 'fg.muted' }, children: name ? `Asking ${name}…` : 'Asking…' })] })) : answered.reply ? (_jsx(Text, { children: name ? `${name}: ${answered.reply}` : answered.reply })) : null] })) : null] }));
25
+ return (_jsxs(Box, { as: "section", "aria-label": name ? `${name}: ${title}` : title, "data-answer-surface": surface.id, display: "flex", flexDirection: "column", gap: 2, minWidth: 0, children: [_jsx(Text, { sx: { fontWeight: 'bold', fontSize: 1 }, children: name ? `${name} · ${title}` : title }), parsed?.messages?.length ? (_jsx(InlineSurface, { messages: parsed.messages, onAction: onAction })) : (_jsx(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: "This could not be drawn: it holds no surface." })), answered ? (_jsxs(Box, { role: "status", "data-answer-reply": "", display: "flex", flexDirection: "column", gap: 1, fontSize: 1, children: [_jsxs(Text, { sx: { color: 'fg.muted' }, children: ["You chose: ", answered.chose] }), answered.waiting ? (_jsxs(Box, { display: "flex", alignItems: "center", gap: 2, children: [_jsx(Spinner, { size: "small" }), _jsx(Text, { sx: { color: 'fg.muted' }, children: name ? `Asking ${name}…` : 'Asking…' })] })) : answered.reply ? (_jsx(Text, { children: name ? `${name}: ${answered.reply}` : answered.reply })) : null] })) : null] }));
26
26
  }
27
27
  export function AnswerSurfacesView({ surfaces, names = {}, onPress, }) {
28
- return (_jsx(Box, { "data-answer-surfaces": "", sx: { display: 'flex', flexDirection: 'column', gap: 3, minWidth: 0 }, children: surfaces.map(surface => (_jsx(OneSurface, { surface: surface, name: names[surface.giver], onPress: onPress }, surface.id))) }));
28
+ return (_jsx(Box, { "data-answer-surfaces": "", display: "flex", flexDirection: "column", gap: 3, minWidth: 0, children: surfaces.map(surface => (_jsx(OneSurface, { surface: surface, name: names[surface.giver], onPress: onPress }, surface.id))) }));
29
29
  }
30
30
  export default AnswerSurfacesView;
@@ -32,16 +32,7 @@ export function NotebookPreview({ notebook, title, maxHeight = 220, onOpen: onOp
32
32
  if (!doc) {
33
33
  return null;
34
34
  }
35
- return (_jsxs(Box, { "data-notebook-preview": "", sx: { display: 'flex', flexDirection: 'column', gap: 1, minWidth: 0 }, children: [_jsx(Box, { role: "region", "aria-label": `${title}, read-only`, onClick: onOpen, "data-notebook-preview-cells": doc.cells.length, sx: {
36
- position: 'relative',
37
- height: maxHeight,
38
- overflow: 'hidden',
39
- border: '1px solid',
40
- borderColor: 'border.muted',
41
- borderRadius: 2,
42
- bg: 'canvas.default',
43
- cursor: onOpen ? 'pointer' : 'default',
44
- }, children: _jsx(Suspense, { fallback: _jsx(Text, { as: "p", sx: { color: 'fg.muted', fontSize: 0, m: 2 }, children: "Opening the notebook\u2026" }), children: _jsx(NotebookPreviewView, { nbformat: doc, height: maxHeight }) }) }), onOpen && (onOpenGiven || openLabel) ? (_jsx(Text, { as: "button", type: "button", onClick: onOpen, "data-notebook-preview-open": "", sx: {
35
+ return (_jsxs(Box, { "data-notebook-preview": "", display: "flex", flexDirection: "column", gap: 1, minWidth: 0, children: [_jsx(Box, { role: "region", "aria-label": `${title}, read-only`, onClick: onOpen, "data-notebook-preview-cells": doc.cells.length, position: "relative", height: maxHeight, overflow: "hidden", border: "1px solid", borderColor: "border.muted", borderRadius: 2, bg: "canvas.default", cursor: onOpen ? 'pointer' : 'default', children: _jsx(Suspense, { fallback: _jsx(Text, { as: "p", sx: { color: 'fg.muted', fontSize: 0, m: 2 }, children: "Opening the notebook\u2026" }), children: _jsx(NotebookPreviewView, { nbformat: doc, height: maxHeight }) }) }), onOpen && (onOpenGiven || openLabel) ? (_jsx(Text, { as: "button", type: "button", onClick: onOpen, "data-notebook-preview-open": "", sx: {
45
36
  alignSelf: 'flex-start',
46
37
  p: 0,
47
38
  border: 0,
@@ -18,14 +18,13 @@ export function NotebookPreviewView({ nbformat, height, }) {
18
18
  const content = useMemo(() => JSON.parse(JSON.stringify(nbformat)), [nbformat]);
19
19
  const { colorScheme } = useTheme();
20
20
  const mode = colorScheme?.startsWith('dark') ? 'dark' : 'light';
21
- return (_jsxs(Box, { "data-notebook-preview-theme": mode, sx: { height },
21
+ return (_jsxs(Box, { "data-notebook-preview-theme": mode, height: height,
22
22
  // JupyterLab writes its theme for the whole page, so two previews in
23
23
  // two modes would share the last one written: each carries its own
24
24
  // mode's variables on its own subtree.
25
25
  style: (mode === 'dark'
26
26
  ? JUPYTER_DARK_VARIABLES
27
- : JUPYTER_LIGHT_VARIABLES), children: [_jsx("span", { "data-jupyter-react-theme-root": "notebook-preview", hidden: true }), _jsx(JupyterReactTheme, { colormode: mode, children: _jsx(Box, { "data-notebook-preview-view": id, sx: {
28
- height,
27
+ : JUPYTER_LIGHT_VARIABLES), children: [_jsx("span", { "data-jupyter-react-theme-root": "notebook-preview", hidden: true }), _jsx(JupyterReactTheme, { colormode: mode, children: _jsx(Box, { "data-notebook-preview-view": id, height: height, sx: {
29
28
  // No toolbar: no room kept for one.
30
29
  '& .datalayer-NotebookPanel-header': {
31
30
  display: 'none',
@@ -26,29 +26,15 @@ export function SceneTranscript({ lines, emptyText = 'What the scene says and do
26
26
  // The clipboard refused: nothing to say but the text, still on screen.
27
27
  }
28
28
  };
29
- return (_jsxs(Box, { "data-scene-transcript": "", "data-scene-lines": lines.length, children: [lines.length === 0 ? (_jsx(Text, { as: "p", sx: { color: 'fg.muted', fontSize: 1, m: 0 }, children: emptyText })) : (_jsx(Box, { as: "ol", "aria-label": "Transcript", sx: {
30
- listStyle: 'none',
31
- m: 0,
32
- p: 0,
33
- fontSize: 1,
34
- ...(maxHeight ? { maxHeight, overflowY: 'auto' } : {}),
35
- }, children: lines.map(line => (_jsxs(Box, { as: "li", "data-transcript-line": line.kind, "data-transcript-from": line.from, "data-transcript-to": line.to, "aria-busy": line.open ? 'true' : undefined, sx: {
36
- display: 'grid',
37
- gridTemplateColumns: 'auto 1fr',
38
- gap: 2,
39
- py: 1,
40
- borderBottom: '1px solid',
41
- borderColor: 'border.muted',
42
- opacity: line.open ? 0.75 : 1,
43
- }, children: [_jsx(Text, { as: "time", sx: {
29
+ return (_jsxs(Box, { "data-scene-transcript": "", "data-scene-lines": lines.length, children: [lines.length === 0 ? (_jsx(Text, { as: "p", sx: { color: 'fg.muted', fontSize: 1, m: 0 }, children: emptyText })) : (_jsx(Box, { as: "ol", "aria-label": "Transcript", listStyle: "none", m: 0, p: 0, fontSize: 1, sx: maxHeight ? { maxHeight, overflowY: 'auto' } : {}, children: lines.map(line => (_jsxs(Box, { as: "li", "data-transcript-line": line.kind, "data-transcript-from": line.from, "data-transcript-to": line.to, "aria-busy": line.open ? 'true' : undefined, display: "grid", gridTemplateColumns: "auto 1fr", gap: 2, py: 1, borderBottom: "1px solid", borderColor: "border.muted", opacity: line.open ? 0.75 : 1, children: [_jsx(Text, { as: "time", sx: {
44
30
  color: 'fg.muted',
45
31
  fontFamily: 'mono',
46
32
  fontSize: 0,
47
33
  pt: '2px',
48
34
  whiteSpace: 'nowrap',
49
- }, dateTime: new Date(line.at).toISOString(), children: timeText(line.at) }), _jsxs(Box, { sx: { minWidth: 0, overflowWrap: 'anywhere' }, children: [_jsxs(Text, { sx: { fontWeight: 600 }, children: [lineHeading(line), ": "] }), _jsxs(Text, { sx: {
35
+ }, dateTime: new Date(line.at).toISOString(), children: timeText(line.at) }), _jsxs(Box, { minWidth: 0, overflowWrap: "anywhere", children: [_jsxs(Text, { sx: { fontWeight: 600 }, children: [lineHeading(line), ": "] }), _jsxs(Text, { sx: {
50
36
  fontFamily: line.kind === 'called' ? 'mono' : undefined,
51
37
  color: line.failed ? 'danger.fg' : undefined,
52
- }, children: [line.text, line.open ? '…' : '', line.failed ? ' (failed)' : ''] })] })] }, line.key))) })), copy && lines.length > 0 && (_jsx(Box, { sx: { mt: 2 }, children: _jsx(Button, { size: "small", onClick: () => void onCopy(), "data-transcript-copy": "", children: copied ? 'Copied' : 'Copy as text' }) }))] }));
38
+ }, children: [line.text, line.open ? '…' : '', line.failed ? ' (failed)' : ''] })] })] }, line.key))) })), copy && lines.length > 0 && (_jsx(Box, { mt: 2, children: _jsx(Button, { size: "small", onClick: () => void onCopy(), "data-transcript-copy": "", children: copied ? 'Copied' : 'Copy as text' }) }))] }));
53
39
  }
54
40
  export default SceneTranscript;
@@ -14,14 +14,7 @@ export function SceneView({ children, members = NO_MEMBERS, tracer, lines, defau
14
14
  };
15
15
  const live = useSceneTranscript(lines ? null : tracer, members);
16
16
  const transcript = lines ?? live;
17
- return (_jsxs(Box, { "data-scene-view": shown, children: [_jsxs(Box, { sx: {
18
- display: 'flex',
19
- alignItems: 'center',
20
- justifyContent: 'space-between',
21
- gap: 2,
22
- flexWrap: 'wrap',
23
- mb: 2,
24
- }, children: [_jsxs(SegmentedControl, { "aria-label": "Scene view", size: "small", children: [_jsx(SegmentedControl.Button, { selected: shown === 'graph', onClick: () => choose('graph'), "data-scene-choice": "graph", children: "Graph" }), _jsx(SegmentedControl.Button, { selected: shown === 'transcript', onClick: () => choose('transcript'), "data-scene-choice": "transcript", children: transcript.length
17
+ return (_jsxs(Box, { "data-scene-view": shown, children: [_jsxs(Box, { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 2, flexWrap: "wrap", mb: 2, children: [_jsxs(SegmentedControl, { "aria-label": "Scene view", size: "small", children: [_jsx(SegmentedControl.Button, { selected: shown === 'graph', onClick: () => choose('graph'), "data-scene-choice": "graph", children: "Graph" }), _jsx(SegmentedControl.Button, { selected: shown === 'transcript', onClick: () => choose('transcript'), "data-scene-choice": "transcript", children: transcript.length
25
18
  ? `Transcript (${transcript.length})`
26
19
  : 'Transcript' })] }), aside] }), _jsx(Box, { hidden: shown !== 'graph', "data-scene-graph": "", children: children }), shown === 'transcript' && (_jsx(SceneTranscript, { lines: transcript, emptyText: emptyText, maxHeight: maxHeight }))] }));
27
20
  }
@@ -19,19 +19,11 @@ export function notebookFileName(notebook) {
19
19
  export function TeamNotebook({ notebook, title, height = 560, hideTitle = false, }) {
20
20
  return (_jsxs(Box, { as: "section", "aria-label": title, "data-team-notebook": "",
21
21
  // Focused when the notebook in a balloon is clicked (`focusExpanded`).
22
- tabIndex: -1, sx: {
23
- display: 'flex',
24
- flexDirection: 'column',
25
- gap: 2,
26
- minWidth: 0,
27
- scrollMarginTop: '16px',
28
- '&:focus': { outline: 'none' },
29
- '&:focus-visible': {
30
- outline: '2px solid',
31
- outlineColor: 'var(--focus-outlineColor, var(--fgColor-accent))',
32
- outlineOffset: 4,
33
- borderRadius: 2,
34
- },
22
+ tabIndex: -1, display: "flex", flexDirection: "column", gap: 2, minWidth: 0, scrollMarginTop: "16px", focus: { outline: 'none' }, focusVisible: {
23
+ outline: '2px solid',
24
+ outlineColor: 'var(--focus-outlineColor, var(--fgColor-accent))',
25
+ outlineOffset: 4,
26
+ borderRadius: 2,
35
27
  }, children: [!hideTitle && (_jsx(Heading, { as: "h3", sx: { fontSize: 2, m: 0 }, children: title })), _jsx(Suspense, { fallback: _jsx(Text, { as: "p", sx: { color: 'fg.muted', fontSize: 1, m: 0 }, children: "Opening the notebook\u2026" }), children: _jsx(TeamNotebookView, { notebook: notebook, fileName: notebookFileName(notebook), height: height }) })] }));
36
28
  }
37
29
  /**
@@ -72,21 +72,11 @@ export function TeamNotebookView({ notebook, fileName, height, }) {
72
72
  }
73
73
  };
74
74
  }, [running, service]);
75
- return (_jsx(QueryClientProvider, { client: queries, children: _jsxs(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 2 }, children: [_jsxs(Box, { sx: {
76
- display: 'flex',
77
- alignItems: 'center',
78
- gap: 2,
79
- flexWrap: 'wrap',
80
- }, children: [_jsx(Text, { sx: { color: 'fg.muted', fontSize: 1, flex: '1 1 auto' }, children: running
75
+ return (_jsx(QueryClientProvider, { client: queries, children: _jsxs(Box, { display: "flex", flexDirection: "column", gap: 2, children: [_jsxs(Box, { display: "flex", alignItems: "center", gap: 2, flexWrap: "wrap", children: [_jsx(Text, { sx: { color: 'fg.muted', fontSize: 1, flex: '1 1 auto' }, children: running
81
76
  ? 'It runs in your browser, with Python (Pyodide): run its cells, change them, add your own.'
82
- : 'Starting Python in your browser…' }), _jsx(Button, { size: "small", leadingVisual: DownloadIcon, onClick: save, "data-team-notebook-download": "", children: "Download .ipynb" })] }), failed && _jsx(Flash, { variant: "warning", children: failed }), _jsx(Box, { "data-team-notebook-sheet": "", sx: {
83
- position: 'relative',
77
+ : 'Starting Python in your browser…' }), _jsx(Button, { size: "small", leadingVisual: DownloadIcon, onClick: save, "data-team-notebook-download": "", children: "Download .ipynb" })] }), failed && _jsx(Flash, { variant: "warning", children: failed }), _jsx(Box, { "data-team-notebook-sheet": "", position: "relative", border: "1px solid", borderColor: "border.default", borderRadius: 2, overflow: "hidden", sx: {
84
78
  height,
85
79
  minHeight: 0,
86
- border: '1px solid',
87
- borderColor: 'border.default',
88
- borderRadius: 2,
89
- overflow: 'hidden',
90
80
  // As the loop's notebook view pins them: Lumino sizes these
91
81
  // itself, and a resize it never hears of leaves them at zero.
92
82
  '& .jp-NotebookPanel': {
@@ -16,5 +16,6 @@ export * from './NotebookPreview';
16
16
  export * from './sceneTranscript';
17
17
  export * from './SceneTranscript';
18
18
  export * from './SceneView';
19
+ export * from './useBalloonRoom';
19
20
  export * from './sceneStage';
20
21
  export * from './AnswerSurfaces';
@@ -20,5 +20,6 @@ export * from './NotebookPreview';
20
20
  export * from './sceneTranscript';
21
21
  export * from './SceneTranscript';
22
22
  export * from './SceneView';
23
+ export * from './useBalloonRoom';
23
24
  export * from './sceneStage';
24
25
  export * from './AnswerSurfaces';
@@ -0,0 +1,39 @@
1
+ /**
2
+ * The room a scene's balloons take above their members, measured: a graph
3
+ * (`A2ATeamGraph`) or a member alone on its stage keeps above its members
4
+ * what their balloons take now — the greeting, the suggestions, *more*
5
+ * unfolded — and no more, so that the scene's box fits what it shows.
6
+ *
7
+ * @module components/teams/useBalloonRoom
8
+ */
9
+ import type { RefObject } from 'react';
10
+ /** A balloon, as measured on the page: its top and its anchor's, in pixels. */
11
+ export type BalloonRect = {
12
+ /** The top of what it speaks for: the member's node, or its figure. */
13
+ anchorTop: number;
14
+ /** The balloon's top. */
15
+ top: number;
16
+ /** Its height: a hidden balloon (`display: none`) has none and takes no room. */
17
+ height: number;
18
+ };
19
+ /** Between the tallest balloon and the edge above it, in pixels at full scale. */
20
+ export declare const BALLOON_MARGIN = 12;
21
+ /** The room is kept to steps of this many pixels: a line more or less does not move the members. */
22
+ export declare const BALLOON_ROOM_STEP = 8;
23
+ /**
24
+ * The room above the members their balloons take, in pixels at full scale:
25
+ * the tallest balloon above its anchor, with a margin, in steps — at least
26
+ * `floor`. `zoom` is the scale the balloons are drawn at (a graph's
27
+ * viewport): their measures are divided by it.
28
+ */
29
+ export declare function balloonRoomOf(balloons: readonly BalloonRect[], zoom?: number, floor?: number): number;
30
+ /**
31
+ * The room the balloons inside `box` take above their anchors (the closest
32
+ * ancestor of each matching `anchor`), kept current as they open, close
33
+ * and change: at least `floor`, in pixels at full scale.
34
+ */
35
+ export declare function useBalloonRoom(box: RefObject<HTMLElement | null>, { anchor, zoom, floor, }: {
36
+ anchor: string;
37
+ zoom?: number;
38
+ floor?: number;
39
+ }): number;
@@ -0,0 +1,89 @@
1
+ /*
2
+ * Copyright (c) 2025-2026 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ import { useEffect, useState } from 'react';
6
+ /** Between the tallest balloon and the edge above it, in pixels at full scale. */
7
+ export const BALLOON_MARGIN = 12;
8
+ /** The room is kept to steps of this many pixels: a line more or less does not move the members. */
9
+ export const BALLOON_ROOM_STEP = 8;
10
+ /**
11
+ * The room above the members their balloons take, in pixels at full scale:
12
+ * the tallest balloon above its anchor, with a margin, in steps — at least
13
+ * `floor`. `zoom` is the scale the balloons are drawn at (a graph's
14
+ * viewport): their measures are divided by it.
15
+ */
16
+ export function balloonRoomOf(balloons, zoom = 1, floor = 0) {
17
+ const scale = zoom > 0 ? zoom : 1;
18
+ const above = Math.max(0, ...balloons
19
+ .filter(balloon => balloon.height > 0)
20
+ .map(balloon => (balloon.anchorTop - balloon.top) / scale));
21
+ const room = above > 0
22
+ ? Math.ceil((above + BALLOON_MARGIN) / BALLOON_ROOM_STEP) *
23
+ BALLOON_ROOM_STEP
24
+ : 0;
25
+ return Math.max(floor, room);
26
+ }
27
+ /**
28
+ * The room the balloons inside `box` take above their anchors (the closest
29
+ * ancestor of each matching `anchor`), kept current as they open, close
30
+ * and change: at least `floor`, in pixels at full scale.
31
+ */
32
+ export function useBalloonRoom(box, { anchor, zoom = 1, floor = 0, }) {
33
+ const [room, setRoom] = useState(floor);
34
+ useEffect(() => {
35
+ const element = box.current;
36
+ if (!element ||
37
+ typeof ResizeObserver === 'undefined' ||
38
+ typeof MutationObserver === 'undefined') {
39
+ setRoom(floor);
40
+ return undefined;
41
+ }
42
+ let frame = 0;
43
+ const measure = () => {
44
+ frame = 0;
45
+ const balloons = [];
46
+ element
47
+ .querySelectorAll('[data-speech-balloon]')
48
+ .forEach(balloon => {
49
+ const owner = balloon.closest(anchor);
50
+ if (!owner || !element.contains(owner)) {
51
+ return;
52
+ }
53
+ const rect = balloon.getBoundingClientRect();
54
+ balloons.push({
55
+ anchorTop: owner.getBoundingClientRect().top,
56
+ top: rect.top,
57
+ height: rect.height,
58
+ });
59
+ });
60
+ const next = balloonRoomOf(balloons, zoom, floor);
61
+ setRoom(current => (current === next ? current : next));
62
+ };
63
+ const later = () => {
64
+ if (!frame) {
65
+ frame = requestAnimationFrame(measure);
66
+ }
67
+ };
68
+ const sizes = new ResizeObserver(later);
69
+ // A balloon that opens, closes or is made again is observed anew.
70
+ const observe = () => {
71
+ sizes.disconnect();
72
+ element
73
+ .querySelectorAll('[data-speech-balloon]')
74
+ .forEach(balloon => sizes.observe(balloon));
75
+ later();
76
+ };
77
+ const changes = new MutationObserver(observe);
78
+ changes.observe(element, { childList: true, subtree: true });
79
+ observe();
80
+ return () => {
81
+ if (frame) {
82
+ cancelAnimationFrame(frame);
83
+ }
84
+ sizes.disconnect();
85
+ changes.disconnect();
86
+ };
87
+ }, [box, anchor, zoom, floor]);
88
+ return room;
89
+ }