@datalayer/agent-runtimes 1.0.18 → 1.0.20

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 (146) hide show
  1. package/README.md +14 -6
  2. package/lib/AgentNode.js +567 -67
  3. package/lib/App.js +2 -2
  4. package/lib/agent-node/AgentNodeGallery.d.ts +80 -0
  5. package/lib/agent-node/AgentNodeGallery.js +627 -0
  6. package/lib/agent-notebook-main.js +0 -1
  7. package/lib/api/runtimes/runtimes.d.ts +57 -0
  8. package/lib/api/runtimes/runtimes.js +55 -1
  9. package/lib/chat/Chat.d.ts +14 -1
  10. package/lib/chat/Chat.js +22 -7
  11. package/lib/chat/base/ChatBase.js +86 -23
  12. package/lib/chat/document/EphemeralDocument.d.ts +49 -1
  13. package/lib/chat/document/EphemeralDocument.js +141 -15
  14. package/lib/chat/header/ChatHeaderBase.d.ts +3 -1
  15. package/lib/chat/header/ChatHeaderBase.js +5 -3
  16. package/lib/chat/messages/ChatMessageList.d.ts +19 -0
  17. package/lib/chat/messages/ChatMessageList.js +180 -9
  18. package/lib/chat/notebook/EphemeralNotebook.d.ts +40 -1
  19. package/lib/chat/notebook/EphemeralNotebook.js +49 -13
  20. package/lib/chat/prompt/InputPrompt.js +1 -1
  21. package/lib/chat/tools/SubagentActivity.d.ts +20 -0
  22. package/lib/chat/tools/SubagentActivity.js +154 -0
  23. package/lib/chat/tools/index.d.ts +1 -0
  24. package/lib/chat/tools/index.js +1 -0
  25. package/lib/chat/usage/TokenUsageBar.js +3 -3
  26. package/lib/client/AgentRuntimesClient.d.ts +5 -0
  27. package/lib/client/AgentsMixin.js +3 -1
  28. package/lib/client/mixins/RuntimesMixin.d.ts +12 -0
  29. package/lib/client/mixins/RuntimesMixin.js +24 -1
  30. package/lib/components/AgentSummary.d.ts +1 -0
  31. package/lib/components/AgentSummary.js +66 -10
  32. package/lib/components/runtimes/RuntimePickerBase.js +64 -29
  33. package/lib/components/runtimes/RuntimePickerCell.js +1 -1
  34. package/lib/components/runtimes/RuntimePickerNotebook.js +1 -1
  35. package/lib/components/runtimes/RuntimeSimplePicker.js +3 -2
  36. package/lib/components/runtimes/RuntimeUtils.js +2 -2
  37. package/lib/context/GraphFlowChart.js +1 -1
  38. package/lib/context/TokenUsageChart.js +1 -1
  39. package/lib/context/TurnGraphChart.js +2 -2
  40. package/lib/examples/A2UiAgentExample.js +4 -4
  41. package/lib/examples/A2UiComponentsGalleryExample.js +3 -3
  42. package/lib/examples/A2UiContactCardExample.js +3 -3
  43. package/lib/examples/A2UiRestaurantExample.js +2 -2
  44. package/lib/examples/A2UiViewerExample.js +3 -3
  45. package/lib/examples/AgUiAgenticExample.js +3 -3
  46. package/lib/examples/AgUiBackendToolRenderingExample.js +2 -2
  47. package/lib/examples/AgUiHaikuGenUiExample.js +3 -3
  48. package/lib/examples/AgUiHumanInTheLoopExample.js +5 -5
  49. package/lib/examples/AgUiSharedStateExample.js +3 -3
  50. package/lib/examples/AgUiToolsBasedGenUiExample.js +7 -5
  51. package/lib/examples/AgentCheckpointsExample.js +6 -5
  52. package/lib/examples/{AgentSandboxExample.d.ts → AgentCodeSandboxExample.d.ts} +4 -4
  53. package/lib/examples/{AgentSandboxExample.js → AgentCodeSandboxExample.js} +10 -9
  54. package/lib/examples/AgentCodeSandboxesExample.js +2 -2
  55. package/lib/examples/AgentCodemodeExample.js +3 -3
  56. package/lib/examples/AgentCompactionExample.d.ts +12 -0
  57. package/lib/examples/AgentCompactionExample.js +244 -0
  58. package/lib/examples/AgentEvalsExample.js +10 -20
  59. package/lib/examples/AgentGuardrailsExample.js +2 -2
  60. package/lib/examples/AgentHooksExample.js +1 -1
  61. package/lib/examples/AgentInferenceProviderExample.js +6 -8
  62. package/lib/examples/AgentLoopExample.js +3 -3
  63. package/lib/examples/AgentMCPExample.js +3 -3
  64. package/lib/examples/AgentMemoryExample.d.ts +4 -2
  65. package/lib/examples/AgentMemoryExample.js +93 -10
  66. package/lib/examples/AgentMonitoringExample.js +2 -2
  67. package/lib/examples/AgentNotificationsExample.js +1 -1
  68. package/lib/examples/AgentOtelExample.d.ts +2 -3
  69. package/lib/examples/AgentOtelExample.js +7 -12
  70. package/lib/examples/AgentOutputsExample.js +5 -5
  71. package/lib/examples/AgentParametersExample.js +3 -3
  72. package/lib/examples/AgentSkillsExample.js +4 -4
  73. package/lib/examples/AgentSubagentsExample.d.ts +2 -2
  74. package/lib/examples/AgentSubagentsExample.js +43 -34
  75. package/lib/examples/AgentToolApprovalsExample.js +1 -1
  76. package/lib/examples/AgentTriggersExample.js +9 -11
  77. package/lib/examples/AgentspecsExample.js +13 -5
  78. package/lib/examples/CellExample.d.ts +6 -0
  79. package/lib/examples/CellExample.js +84 -0
  80. package/lib/examples/ChatCustomExample.js +1 -1
  81. package/lib/examples/ChatExample.js +1 -1
  82. package/lib/examples/ChatStandaloneExample.js +2 -2
  83. package/lib/examples/HomeExample.js +29 -28
  84. package/lib/examples/Lexical2Example.js +2 -2
  85. package/lib/examples/LexicalAgentExample.js +1 -1
  86. package/lib/examples/LexicalAgentSidebarExample.js +2 -2
  87. package/lib/examples/NotebookAgentSidebarExample.d.ts +1 -1
  88. package/lib/examples/NotebookAgentSidebarExample.js +5 -4
  89. package/lib/examples/NotebookCollaborationExample.js +3 -3
  90. package/lib/examples/NotebookExample.js +2 -2
  91. package/lib/examples/components/ExampleWrapper.js +5 -0
  92. package/lib/examples/components/Header.js +2 -2
  93. package/lib/examples/components/HeaderControls.js +1 -1
  94. package/lib/examples/components/LexicalEditor.js +1 -1
  95. package/lib/examples/components/MainContent.js +1 -1
  96. package/lib/examples/components/MockFileBrowser.js +8 -8
  97. package/lib/examples/components/TimeTravel.js +1 -1
  98. package/lib/examples/components/haiku/HaikuDisplay.js +2 -2
  99. package/lib/examples/example-selector.js +4 -3
  100. package/lib/examples/hooks/useExampleAgentRuntime.js +11 -1
  101. package/lib/examples/hooks/useExampleAgentRuntimes.d.ts +7 -0
  102. package/lib/examples/hooks/useExampleAgentRuntimes.js +82 -0
  103. package/lib/examples/index.d.ts +2 -1
  104. package/lib/examples/index.js +2 -1
  105. package/lib/examples/main.js +359 -46
  106. package/lib/examples/utils/agentSummaryStore.d.ts +17 -0
  107. package/lib/examples/utils/themedProvider.js +32 -2
  108. package/lib/examples/utils/useExampleAgentRuntimesUrl.js +2 -1
  109. package/lib/examples2/NotebookMutationsKernel.js +6 -3
  110. package/lib/examples2/NotebookMutationsServiceManager.js +6 -3
  111. package/lib/examples2/ReactRouterExample.js +5 -5
  112. package/lib/examples2/main.js +38 -0
  113. package/lib/hooks/useAIAgentsWebSocket.js +35 -0
  114. package/lib/hooks/useAgentRuntimes.d.ts +22 -0
  115. package/lib/hooks/useAgentRuntimes.js +192 -5
  116. package/lib/hooks/useCheckpoints.js +2 -2
  117. package/lib/hooks/useToolApprovals.d.ts +10 -4
  118. package/lib/hooks/useToolApprovals.js +11 -5
  119. package/lib/identity/AgentIdentity.js +1 -2
  120. package/lib/models/Runtime.d.ts +10 -8
  121. package/lib/models/RuntimeDTO.d.ts +5 -3
  122. package/lib/models/RuntimeDTO.js +3 -3
  123. package/lib/runtimes/actions.js +3 -1
  124. package/lib/runtimes/apis.d.ts +7 -0
  125. package/lib/shims/primerAddonsBox.d.ts +1 -0
  126. package/lib/shims/primerAddonsBox.js +7 -0
  127. package/lib/specs/agents/agents.d.ts +51 -0
  128. package/lib/specs/agents/agents.js +3389 -94
  129. package/lib/specs/models.d.ts +2 -0
  130. package/lib/specs/models.js +37 -0
  131. package/lib/stores/agentRuntimeStore.d.ts +32 -1
  132. package/lib/stores/agentRuntimeStore.js +65 -1
  133. package/lib/stores/index.d.ts +1 -1
  134. package/lib/stores/index.js +1 -1
  135. package/lib/types/agents.d.ts +9 -3
  136. package/lib/types/agentspecs.d.ts +2 -0
  137. package/lib/types/chat.d.ts +83 -0
  138. package/lib/types/models.d.ts +5 -0
  139. package/lib/types/stream.d.ts +58 -1
  140. package/package.json +6 -5
  141. package/scripts/codegen/generate_agents.py +7 -0
  142. package/scripts/codegen/generate_models.py +22 -9
  143. package/scripts/gen_workers.py +340 -0
  144. package/lib/examples/CellSimpleExample.d.ts +0 -6
  145. package/lib/examples/CellSimpleExample.js +0 -20
  146. package/scripts/codegen/__pycache__/generate_sandbox_agents.cpython-313.pyc +0 -0
@@ -37,9 +37,11 @@ import { ListPlugin } from '@lexical/react/LexicalListPlugin';
37
37
  import { CheckListPlugin } from '@lexical/react/LexicalCheckListPlugin';
38
38
  import { LinkPlugin } from '@lexical/react/LexicalLinkPlugin';
39
39
  import { ServerConnection, ServiceManager } from '@jupyterlab/services';
40
- import { Box, DatalayerThemeProvider, getThemeConfig, useSystemColorMode, useThemeStore, } from '@datalayer/primer-addons';
40
+ import { DatalayerThemeProvider, getThemeConfig, useSystemColorMode, useThemeStore, } from '@datalayer/primer-addons';
41
+ import { Box, Spinner, Text } from '@primer/react';
41
42
  import { JupyterReactTheme, Kernel, disposeServiceManager, } from '@datalayer/jupyter-react';
42
43
  import { ComponentPickerMenuPlugin, JupyterCellPlugin, JupyterInputOutputPlugin, DraggableBlockPlugin, ImagesPlugin, ExcalidrawPlugin, TablePlugin, TableCellResizerPlugin, TableActionMenuPlugin, TableHoverActionsV2Plugin, CollapsiblePlugin, HorizontalRulePlugin, EquationsPlugin, YouTubePlugin, AutoLinkPlugin, AutoEmbedPlugin, LexicalConfigProvider, LexicalStatePlugin, FloatingTextFormatToolbarPlugin, CodeActionMenuPlugin, ListMaxIndentLevelPlugin, ToolbarPlugin, ToolbarContext, CommentsProvider, commentTheme, } from '@datalayer/jupyter-lexical';
44
+ import { createWebsocketProvider, LoroCollaborationPlugin, } from '@datalayer/lexical-loro';
43
45
  import { editorConfig } from '../../examples/lexical/editorConfig';
44
46
  import { useLexicalTools } from '../../tools/adapters/agent-runtimes/lexicalHooks';
45
47
  import { useAgentsRuntimes } from '../../hooks/useAgentRuntimes';
@@ -106,7 +108,32 @@ function DocumentToolbar({ setIsLinkEditMode, }) {
106
108
  /**
107
109
  * Renders an in-memory Lexical document backed by a sandbox kernel.
108
110
  */
109
- export function EphemeralDocument({ documentId, runtimePodName, content, onContentChange, onToolsReady, }) {
111
+ export function EphemeralDocument({ documentId, runtimePodName, runtimeOverride, themeVariant, colorMode, content, onContentChange, onToolsReady, onKernelChange, collaboration, }) {
112
+ // Real-time collaboration is active only when both a WebSocket endpoint and a
113
+ // room id are supplied. In that mode the shared Loro CRDT is the single source
114
+ // of truth: local content-seeding and undo history are disabled so the local
115
+ // editor never diverges from (or fights) the collaborative document.
116
+ const isCollaborative = Boolean(collaboration?.websocketUrl && collaboration?.roomId);
117
+ const collaborationName = collaboration?.identity?.displayName ||
118
+ collaboration?.identity?.handle ||
119
+ collaboration?.identity?.userId;
120
+ const collaborationColor = collaboration?.identity?.color;
121
+ const collaborationAwarenessData = useMemo(() => ({
122
+ user: {
123
+ id: collaboration?.identity?.userId,
124
+ username: collaboration?.identity?.userId ||
125
+ collaboration?.identity?.handle ||
126
+ collaboration?.identity?.displayName,
127
+ name: collaboration?.identity?.handle ||
128
+ collaboration?.identity?.displayName,
129
+ display_name: collaboration?.identity?.displayName ||
130
+ collaboration?.identity?.handle,
131
+ initials: collaboration?.identity?.initials,
132
+ color: collaboration?.identity?.color,
133
+ avatar_url: collaboration?.identity?.avatarUrl,
134
+ handle: collaboration?.identity?.handle,
135
+ },
136
+ }), [collaboration?.identity]);
110
137
  // Capture the restore seed ONCE per documentId so parent re-renders don't
111
138
  // remount the composer (which reads `initialConfig` a single time).
112
139
  const initialContentRef = useRef(content);
@@ -127,14 +154,38 @@ export function EphemeralDocument({ documentId, runtimePodName, content, onConte
127
154
  // Resolve the runtime sandbox strictly by its assigned pod name. There is
128
155
  // deliberately NO local fallback kernel: the ephemeral document executes on
129
156
  // exactly the runtime assigned to this agent, or shows a waiting state.
130
- const { runtimes } = useAgentsRuntimes();
157
+ const { runtimes, refetchRuntimes } = useAgentsRuntimes();
131
158
  const selectedRuntime = useMemo(() => {
159
+ const overrideBaseUrl = String(runtimeOverride?.baseUrl || '').trim();
160
+ if (overrideBaseUrl) {
161
+ return {
162
+ url: overrideBaseUrl,
163
+ wsUrl: String(runtimeOverride?.wsUrl || '').trim() || undefined,
164
+ token: String(runtimeOverride?.token || '').trim(),
165
+ pod_name: String(runtimeOverride?.podName || '').trim() || 'agent-node-proxy',
166
+ };
167
+ }
132
168
  const preferredPod = String(runtimePodName || '').trim();
133
169
  if (!preferredPod) {
134
170
  return undefined;
135
171
  }
136
172
  return runtimes.find(rt => String(rt?.pod_name || '') === preferredPod);
137
- }, [runtimePodName, runtimes]);
173
+ }, [runtimeOverride, runtimePodName, runtimes]);
174
+ const needsRuntimeLookup = Boolean(!runtimeOverride?.baseUrl &&
175
+ String(runtimePodName || '').trim() &&
176
+ !selectedRuntime);
177
+ useEffect(() => {
178
+ if (!needsRuntimeLookup) {
179
+ return;
180
+ }
181
+ void refetchRuntimes();
182
+ const intervalId = window.setInterval(() => {
183
+ void refetchRuntimes();
184
+ }, 1000);
185
+ return () => {
186
+ window.clearInterval(intervalId);
187
+ };
188
+ }, [needsRuntimeLookup, refetchRuntimes]);
138
189
  const [runtimeServiceManager, setRuntimeServiceManager] = useState(null);
139
190
  // Kernel started inside the agent runtime sandbox and threaded into the
140
191
  // Jupyter cell plugins, mirroring how the document editor wires its kernel.
@@ -154,9 +205,11 @@ export function EphemeralDocument({ documentId, runtimePodName, content, onConte
154
205
  }
155
206
  try {
156
207
  const token = String(selectedRuntime?.token || '').trim();
208
+ const wsUrl = String(selectedRuntime?.wsUrl || '').trim() ||
209
+ baseUrl.replace(/^http/, 'ws');
157
210
  const serverSettings = ServerConnection.makeSettings({
158
211
  baseUrl,
159
- wsUrl: baseUrl.replace(/^http/, 'ws'),
212
+ wsUrl,
160
213
  token,
161
214
  appendToken: true,
162
215
  });
@@ -195,8 +248,19 @@ export function EphemeralDocument({ documentId, runtimePodName, content, onConte
195
248
  }
196
249
  };
197
250
  }, [selectedRuntime?.pod_name, selectedRuntime?.url, selectedRuntime?.token]);
251
+ // Surface the document's live kernel connection to the parent so the chat
252
+ // header's kernel indicator reflects the real connected kernel instead of
253
+ // the "disconnected"/"no-kernel" placeholder while the document is active.
254
+ useEffect(() => {
255
+ onKernelChange?.(documentKernel?.connection ?? null);
256
+ return () => {
257
+ onKernelChange?.(null);
258
+ };
259
+ }, [documentKernel, onKernelChange]);
198
260
  const activeServiceManager = runtimeServiceManager;
199
- const isRuntimeStarting = Boolean(String(runtimePodName || '').trim() && !activeServiceManager);
261
+ const isRuntimeStarting = Boolean((String(runtimePodName || '').trim() ||
262
+ String(runtimeOverride?.baseUrl || '').trim()) &&
263
+ !activeServiceManager);
200
264
  useProgressTask(`ephemeral-document-start-${documentId}`, isRuntimeStarting);
201
265
  // Build the initial config once per documentId, without the demo content so
202
266
  // the document starts empty and is either restored or filled by the agent.
@@ -232,10 +296,12 @@ export function EphemeralDocument({ documentId, runtimePodName, content, onConte
232
296
  // Resolve the active theme/color-mode exactly like the notebook editor so
233
297
  // the document honours dark / branded themes instead of always rendering
234
298
  // light.
235
- const { colorMode, theme: themeVariant } = useThemeStore();
299
+ const { colorMode: storeColorMode, theme: storeThemeVariant } = useThemeStore();
300
+ const effectiveColorMode = colorMode ?? storeColorMode;
301
+ const effectiveThemeVariant = themeVariant ?? storeThemeVariant;
236
302
  const systemMode = useSystemColorMode();
237
- const themeConfig = getThemeConfig(themeVariant);
238
- const resolvedMode = colorMode === 'auto' ? systemMode : colorMode;
303
+ const themeConfig = getThemeConfig(effectiveThemeVariant);
304
+ const resolvedMode = effectiveColorMode === 'auto' ? systemMode : effectiveColorMode;
239
305
  const modeStyles = resolvedMode === 'dark'
240
306
  ? themeConfig.themeStyles.dark
241
307
  : themeConfig.themeStyles.light;
@@ -247,24 +313,84 @@ export function EphemeralDocument({ documentId, runtimePodName, content, onConte
247
313
  position: 'relative',
248
314
  overflow: 'hidden',
249
315
  bg: 'canvas.default',
250
- }, children: activeServiceManager ? (_jsx(DatalayerThemeProvider, { colorMode: colorMode, theme: themeConfig.primerTheme, themeStyles: themeConfig.themeStyles, children: _jsx(JupyterReactTheme, { colormode: resolvedMode, backgroundColor: themeBackground, children: _jsx(Box, { sx: {
316
+ }, children: activeServiceManager ? (_jsx(DatalayerThemeProvider, { colorMode: effectiveColorMode, theme: themeConfig.primerTheme, themeStyles: themeConfig.themeStyles, children: _jsx(JupyterReactTheme, { colormode: resolvedMode, backgroundColor: themeBackground, children: _jsx(Box, { sx: {
251
317
  position: 'absolute',
252
318
  inset: 0,
253
319
  display: 'flex',
254
320
  flexDirection: 'column',
255
- overflow: 'auto',
321
+ minHeight: 0,
322
+ overflow: 'hidden',
256
323
  overscrollBehaviorY: 'contain',
257
324
  padding: 2,
258
325
  '& .editor-shell': {
259
326
  backgroundColor: themeBackground,
260
327
  borderRadius: 2,
328
+ display: 'flex',
329
+ flexDirection: 'column',
330
+ minHeight: 0,
331
+ flex: 1,
332
+ // The shared lexical stylesheet caps `.editor-shell` at
333
+ // `max-width: 1100px; margin: 20px auto`, which leaves the
334
+ // ephemeral document narrow and centered. Take the full
335
+ // wrapping box width instead (matching the ui LiterateEditor,
336
+ // whose root is `.editor-container` with no such cap).
337
+ maxWidth: 'none',
338
+ width: '100%',
339
+ margin: 0,
340
+ },
341
+ '& .editor-container': {
342
+ backgroundColor: themeBackground,
343
+ display: 'flex',
344
+ flexDirection: 'column',
345
+ minHeight: 0,
346
+ flex: 1,
347
+ width: '100%',
348
+ maxWidth: 'none',
349
+ margin: 0,
350
+ },
351
+ '& .editor-inner': {
352
+ backgroundColor: themeBackground,
353
+ display: 'flex',
354
+ flexDirection: 'column',
355
+ minHeight: 0,
356
+ flex: 1,
357
+ width: '100%',
358
+ maxWidth: 'none',
359
+ },
360
+ '& .editor-scroller': {
361
+ minHeight: 0,
362
+ flex: 1,
363
+ overflow: 'auto',
364
+ width: '100%',
365
+ maxWidth: 'none',
366
+ },
367
+ '& .editor': {
368
+ minHeight: '100%',
369
+ width: '100%',
370
+ maxWidth: 'none',
371
+ margin: 0,
372
+ },
373
+ '& .editor-input': {
374
+ backgroundColor: themeBackground,
375
+ width: '100%',
376
+ maxWidth: 'none',
377
+ margin: 0,
378
+ },
379
+ '& .ContentEditable__root': {
380
+ width: '100%',
381
+ maxWidth: 'none',
382
+ margin: 0,
261
383
  },
262
- '& .editor-container': { backgroundColor: themeBackground },
263
- '& .editor-inner': { backgroundColor: themeBackground },
264
- '& .editor-input': { backgroundColor: themeBackground },
265
384
  '& [role="toolbar"][aria-label="Editor toolbar"]': {
266
385
  backgroundColor: themeBackground,
267
386
  },
268
- }, children: _jsx(LexicalConfigProvider, { lexicalId: documentId, serviceManager: activeServiceManager, children: _jsx(LexicalComposer, { initialConfig: initialConfig, children: _jsx(CommentsProvider, { children: _jsx(ToolbarContext, { children: _jsxs("div", { className: "editor-shell", children: [_jsx(DocumentToolbar, { setIsLinkEditMode: setIsLinkEditMode }), _jsx("div", { className: "editor-container", children: _jsxs("div", { className: "editor-inner", children: [_jsx(LexicalStatePlugin, {}), _jsx(RichTextPlugin, { contentEditable: _jsx("div", { className: "editor-scroller", children: _jsx("div", { className: "editor", ref: onAnchorRef, children: _jsx(ContentEditable, { className: "editor-input", "aria-label": "Ephemeral document editor" }) }) }), ErrorBoundary: LexicalErrorBoundary }), _jsx(OnChangePlugin, { onChange: handleChange }), _jsx(HistoryPlugin, {}), _jsx(AutoFocusPlugin, {}), _jsx(ListPlugin, {}), _jsx(CheckListPlugin, {}), _jsx(LinkPlugin, {}), _jsx(AutoLinkPlugin, {}), _jsx(ListMaxIndentLevelPlugin, { maxDepth: 7 }), _jsx(MarkdownShortcutPlugin, { transformers: TRANSFORMERS }), _jsx(LoadContentPlugin, { content: initialContent }), _jsx(CodeHighlightPlugin, {}), _jsx(ImagesPlugin, { captionsEnabled: false }), _jsx(ExcalidrawPlugin, {}), _jsx(TablePlugin, {}), _jsx(TableCellResizerPlugin, {}), _jsx(TableActionMenuPlugin, {}), _jsx(TableHoverActionsV2Plugin, {}), _jsx(CollapsiblePlugin, {}), _jsx(HorizontalRulePlugin, {}), _jsx(EquationsPlugin, {}), _jsx(YouTubePlugin, {}), _jsx(AutoEmbedPlugin, {}), _jsx(JupyterCellPlugin, {}), _jsx(ComponentPickerMenuPlugin, { kernel: documentKernel }), _jsx(JupyterInputOutputPlugin, { kernel: documentKernel }), floatingAnchorElem && (_jsxs(_Fragment, { children: [_jsx(DraggableBlockPlugin, { anchorElem: floatingAnchorElem }), _jsx(FloatingTextFormatToolbarPlugin, { anchorElem: floatingAnchorElem, setIsLinkEditMode: setIsLinkEditMode }), _jsx(CodeActionMenuPlugin, { anchorElem: floatingAnchorElem })] }))] }) })] }) }) }) }) }) }) }) })) : null }));
387
+ }, children: _jsx(LexicalConfigProvider, { lexicalId: documentId, serviceManager: activeServiceManager, children: _jsx(LexicalComposer, { initialConfig: initialConfig, children: _jsx(CommentsProvider, { children: _jsx(ToolbarContext, { children: _jsxs("div", { className: "editor-shell", children: [_jsx(DocumentToolbar, { setIsLinkEditMode: setIsLinkEditMode }), _jsx("div", { className: "editor-container", children: _jsxs("div", { className: "editor-inner", children: [isCollaborative && collaboration ? (_jsx(LoroCollaborationPlugin, { id: collaboration.roomId, providerFactory: createWebsocketProvider, websocketUrl: collaboration.websocketUrl, shouldBootstrap: true, showCollaborators: true, username: collaborationName, cursorColor: collaborationColor, awarenessData: collaborationAwarenessData })) : null, _jsx(LexicalStatePlugin, {}), _jsx(RichTextPlugin, { contentEditable: _jsx("div", { className: "editor-scroller", children: _jsx("div", { className: "editor", ref: onAnchorRef, children: _jsx(ContentEditable, { className: "editor-input", "aria-label": "Ephemeral document editor" }) }) }), ErrorBoundary: LexicalErrorBoundary }), !isCollaborative && (_jsx(OnChangePlugin, { onChange: handleChange })), !isCollaborative && _jsx(HistoryPlugin, {}), _jsx(AutoFocusPlugin, {}), _jsx(ListPlugin, {}), _jsx(CheckListPlugin, {}), _jsx(LinkPlugin, {}), _jsx(AutoLinkPlugin, {}), _jsx(ListMaxIndentLevelPlugin, { maxDepth: 7 }), _jsx(MarkdownShortcutPlugin, { transformers: TRANSFORMERS }), !isCollaborative && (_jsx(LoadContentPlugin, { content: initialContent })), _jsx(CodeHighlightPlugin, {}), _jsx(ImagesPlugin, { captionsEnabled: false }), _jsx(ExcalidrawPlugin, {}), _jsx(TablePlugin, {}), _jsx(TableCellResizerPlugin, {}), _jsx(TableActionMenuPlugin, {}), _jsx(TableHoverActionsV2Plugin, {}), _jsx(CollapsiblePlugin, {}), _jsx(HorizontalRulePlugin, {}), _jsx(EquationsPlugin, {}), _jsx(YouTubePlugin, {}), _jsx(AutoEmbedPlugin, {}), _jsx(JupyterCellPlugin, {}), _jsx(ComponentPickerMenuPlugin, { kernel: documentKernel }), _jsx(JupyterInputOutputPlugin, { kernel: documentKernel }), floatingAnchorElem && (_jsxs(_Fragment, { children: [_jsx(DraggableBlockPlugin, { anchorElem: floatingAnchorElem }), _jsx(FloatingTextFormatToolbarPlugin, { anchorElem: floatingAnchorElem, setIsLinkEditMode: setIsLinkEditMode }), _jsx(CodeActionMenuPlugin, { anchorElem: floatingAnchorElem })] }))] }) })] }) }) }) }) }) }) }) })) : isRuntimeStarting ? (_jsxs(Box, { sx: {
388
+ height: '100%',
389
+ display: 'flex',
390
+ alignItems: 'center',
391
+ justifyContent: 'center',
392
+ gap: 2,
393
+ color: 'fg.muted',
394
+ }, children: [_jsx(Spinner, { size: "small" }), _jsx(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: "Starting document..." })] })) : null }));
269
395
  }
270
396
  export default EphemeralDocument;
@@ -26,6 +26,8 @@ export interface ChatBaseHeaderProps {
26
26
  padding: number;
27
27
  /** Optional kernel indicator state override from notebook runtime. */
28
28
  kernelIndicatorState?: ExecutionState;
29
+ /** Horizontal placement for the kernel indicator in the title row. */
30
+ kernelIndicatorPlacement?: 'left' | 'center' | 'right';
29
31
  /**
30
32
  * Runtime status from agent-runtimes sandbox status stream.
31
33
  * Uses the same execution-state model as KernelIndicator.
@@ -69,5 +71,5 @@ export interface ChatBaseHeaderProps {
69
71
  /** Callback fired when the user changes the companion-surface mode. */
70
72
  onEphemeralSurfaceModeChange?: (mode: EphemeralSurfaceMode) => void;
71
73
  }
72
- export declare function ChatBaseHeader({ title, subtitle, brandIcon, headerContent, headerActions, showInformation, onInformationClick, padding, kernelIndicatorState, runtimeStatus, kernel, kernelEnvironmentName, kernelCpu, kernelMemory, kernelGpu, headerButtons, messageCount, onNewChat, onClear, chatViewMode, onChatViewModeChange, showEphemeralSurfaceControl, enableEphemeralNotebookOption, enableEphemeralDocumentOption, ephemeralSurfaceMode, onEphemeralSurfaceModeChange, }: ChatBaseHeaderProps): import("react/jsx-runtime").JSX.Element;
74
+ export declare function ChatBaseHeader({ title, subtitle, brandIcon, headerContent, headerActions, showInformation, onInformationClick, padding, kernelIndicatorState, kernelIndicatorPlacement, runtimeStatus, kernel, kernelEnvironmentName, kernelCpu, kernelMemory, kernelGpu, headerButtons, messageCount, onNewChat, onClear, chatViewMode, onChatViewModeChange, showEphemeralSurfaceControl, enableEphemeralNotebookOption, enableEphemeralDocumentOption, ephemeralSurfaceMode, onEphemeralSurfaceModeChange, }: ChatBaseHeaderProps): import("react/jsx-runtime").JSX.Element;
73
75
  export {};
@@ -29,11 +29,13 @@ export function toRuntimeExecutionState(runtimeStatus) {
29
29
  // ---------------------------------------------------------------------------
30
30
  // Component
31
31
  // ---------------------------------------------------------------------------
32
- export function ChatBaseHeader({ title, subtitle, brandIcon, headerContent, headerActions, showInformation, onInformationClick, padding, kernelIndicatorState, runtimeStatus, kernel, kernelEnvironmentName, kernelCpu, kernelMemory, kernelGpu, headerButtons, messageCount, onNewChat, onClear, chatViewMode, onChatViewModeChange, showEphemeralSurfaceControl = false, enableEphemeralNotebookOption = false, enableEphemeralDocumentOption = false, ephemeralSurfaceMode = 'none', onEphemeralSurfaceModeChange, }) {
32
+ export function ChatBaseHeader({ title, subtitle, brandIcon, headerContent, headerActions, showInformation, onInformationClick, padding, kernelIndicatorState, kernelIndicatorPlacement = 'left', runtimeStatus, kernel, kernelEnvironmentName, kernelCpu, kernelMemory, kernelGpu, headerButtons, messageCount, onNewChat, onClear, chatViewMode, onChatViewModeChange, showEphemeralSurfaceControl = false, enableEphemeralNotebookOption = false, enableEphemeralDocumentOption = false, ephemeralSurfaceMode = 'none', onEphemeralSurfaceModeChange, }) {
33
33
  const effectiveIndicatorState = kernelIndicatorState ?? toRuntimeExecutionState(runtimeStatus);
34
+ const kernelIndicatorElement = kernel ? (_jsx(KernelIndicator, { kernel: kernel, environmentName: kernelEnvironmentName, cpu: kernelCpu, memory: kernelMemory, gpu: kernelGpu, position: "s", bordered: false })) : (_jsx(KernelIndicator, { state: effectiveIndicatorState ?? 'undefined', environmentName: kernelEnvironmentName, cpu: kernelCpu, memory: kernelMemory, gpu: kernelGpu, position: "s", bordered: false }));
34
35
  return (_jsx(Box, { sx: {
35
36
  display: 'flex',
36
37
  flexDirection: 'column',
38
+ bg: 'canvas.default',
37
39
  borderBottom: '1px solid',
38
40
  borderColor: 'border.default',
39
41
  }, children: _jsxs(Box, { sx: {
@@ -47,7 +49,7 @@ export function ChatBaseHeader({ title, subtitle, brandIcon, headerContent, head
47
49
  gap: 2,
48
50
  minWidth: 0,
49
51
  flex: '1 1 auto',
50
- }, children: [brandIcon || _jsx(AiAgentIcon, { colored: true, size: 20 }), kernel ? (_jsx(KernelIndicator, { kernel: kernel, environmentName: kernelEnvironmentName, cpu: kernelCpu, memory: kernelMemory, gpu: kernelGpu, position: "s", bordered: false })) : (_jsx(KernelIndicator, { state: effectiveIndicatorState ?? 'undefined', environmentName: kernelEnvironmentName, cpu: kernelCpu, memory: kernelMemory, gpu: kernelGpu, position: "s", bordered: false })), (title || subtitle) && (_jsxs(Box, { sx: {
52
+ }, children: [kernelIndicatorPlacement === 'left' && kernelIndicatorElement, brandIcon || _jsx(AiAgentIcon, { colored: true, size: 20 }), (title || subtitle) && (_jsxs(Box, { sx: {
51
53
  display: 'flex',
52
54
  flexDirection: 'column',
53
55
  minWidth: 0,
@@ -62,7 +64,7 @@ export function ChatBaseHeader({ title, subtitle, brandIcon, headerContent, head
62
64
  color: 'fg.muted',
63
65
  minWidth: 0,
64
66
  maxWidth: '100%',
65
- }, children: _jsx(Truncate, { title: subtitle, maxWidth: "40ch", children: subtitle }) }))] })), headerContent, showInformation && (_jsx(IconButton, { icon: InfoIcon, "aria-label": "Information", variant: "invisible", size: "small", onClick: onInformationClick }))] }), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1, flexShrink: 0 }, children: [headerButtons?.showNewChat && (_jsx(IconButton, { icon: PlusIcon, "aria-label": "New chat", variant: "invisible", size: "small", onClick: onNewChat })), headerButtons?.showClear && messageCount > 0 && (_jsx(IconButton, { icon: TrashIcon, "aria-label": "Clear messages", variant: "invisible", size: "small", onClick: onClear })), headerButtons?.showSettings && (_jsx(IconButton, { icon: GearIcon, "aria-label": "Settings", variant: "invisible", size: "small", onClick: headerButtons.onSettings })), showEphemeralSurfaceControl && (_jsx(Box, { sx: {
67
+ }, children: _jsx(Truncate, { title: subtitle, maxWidth: "40ch", children: subtitle }) }))] })), headerContent, showInformation && (_jsx(IconButton, { icon: InfoIcon, "aria-label": "Information", variant: "invisible", size: "small", onClick: onInformationClick })), kernelIndicatorPlacement === 'center' && kernelIndicatorElement] }), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1, flexShrink: 0 }, children: [kernelIndicatorPlacement === 'right' && kernelIndicatorElement, headerButtons?.showNewChat && (_jsx(IconButton, { icon: PlusIcon, "aria-label": "New chat", variant: "invisible", size: "small", onClick: onNewChat })), headerButtons?.showClear && messageCount > 0 && (_jsx(IconButton, { icon: TrashIcon, "aria-label": "Clear messages", variant: "invisible", size: "small", onClick: onClear })), headerButtons?.showSettings && (_jsx(IconButton, { icon: GearIcon, "aria-label": "Settings", variant: "invisible", size: "small", onClick: headerButtons.onSettings })), showEphemeralSurfaceControl && (_jsx(Box, { sx: {
66
68
  display: 'inline-flex',
67
69
  alignItems: 'center',
68
70
  bg: 'neutral.muted',
@@ -46,4 +46,23 @@ export interface ChatMessageListProps {
46
46
  */
47
47
  approvalConfig?: ToolApprovalConfig;
48
48
  }
49
+ type SubagentAvatarConfig = Required<Pick<AvatarConfig, 'userAvatar' | 'assistantAvatar' | 'showAvatars' | 'avatarSize' | 'userAvatarBg' | 'assistantAvatarBg'>>;
50
+ export interface SubagentChatPanelProps {
51
+ /** Parent `delegate_task` tool call id used to look up streamed events. */
52
+ toolCallId: string;
53
+ /** Subagent name used as a fallback when the tool-call id does not match. */
54
+ subagentName?: string;
55
+ /** Fixed viewport height in pixels. */
56
+ height?: number;
57
+ /** Avatar configuration for the embedded message list. */
58
+ avatarConfig?: SubagentAvatarConfig;
59
+ }
60
+ /**
61
+ * Fixed-height, chat-style viewport for a single delegated subagent run.
62
+ * Reuses {@link ChatMessageList} so subagent output is formatted exactly like
63
+ * the primary agent, including tool-call cards and inline approvals. Tool
64
+ * approval decisions are sent over the shared monitoring socket.
65
+ */
66
+ export declare function SubagentChatPanel({ toolCallId, subagentName: subagentNameHint, height, avatarConfig, }: SubagentChatPanelProps): React.ReactElement | null;
49
67
  export declare function ChatMessageList({ displayItems, isLoading, isStreaming, showLoadingIndicator, hideMessagesAfterToolUI, avatarConfig, padding, renderToolResult, emptyContent, messagesEndRef, onRespond, approvalConfig, }: ChatMessageListProps): import("react/jsx-runtime").JSX.Element;
68
+ export {};
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  /*
3
3
  * Copyright (c) 2025-2026 Datalayer, Inc.
4
4
  * Distributed under the terms of the Modified BSD License.
@@ -9,14 +9,15 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
9
9
  *
10
10
  * @module chat/messages/MessageList
11
11
  */
12
- import { useState, useCallback, useMemo, } from 'react';
13
- import { Text } from '@primer/react';
12
+ import { useState, useCallback, useEffect, useMemo, useRef, } from 'react';
13
+ import { Text, Spinner } from '@primer/react';
14
+ import { DependabotIcon, PersonIcon } from '@primer/octicons-react';
14
15
  import { Box } from '@datalayer/primer-addons';
15
16
  import { Streamdown } from 'streamdown';
16
17
  import { streamdownMarkdownStyles, streamdownCodeBlockStyles, } from '../styles/streamdownStyles';
17
18
  import { ToolCallDisplay } from '../tools/ToolCallDisplay';
18
19
  import { isToolCallMessage, getMessageText } from '../../utils';
19
- import { useAgentRuntimeStore } from '../../stores/agentRuntimeStore';
20
+ import { useAgentRuntimeStore, useAgentRuntimeSubagentActivityByToolCall, agentRuntimeStore, } from '../../stores/agentRuntimeStore';
20
21
  // ---------------------------------------------------------------------------
21
22
  // Normalize helper
22
23
  // ---------------------------------------------------------------------------
@@ -70,6 +71,171 @@ function normalizeAssistantMarkdown(text) {
70
71
  });
71
72
  return out;
72
73
  }
74
+ const SUBAGENT_AVATAR_CONFIG = {
75
+ userAvatar: _jsx(PersonIcon, { size: 14 }),
76
+ assistantAvatar: _jsx(DependabotIcon, { size: 14 }),
77
+ showAvatars: true,
78
+ avatarSize: 24,
79
+ userAvatarBg: 'neutral.muted',
80
+ assistantAvatarBg: 'accent.emphasis',
81
+ };
82
+ /**
83
+ * Convert streamed subagent activity into the `DisplayItem[]` shape the main
84
+ * chat renders: text deltas merge into markdown messages, and tool events pair
85
+ * into tool-call cards (with approval controls when the runtime requests one).
86
+ * Reasoning (`thinking`) is omitted to mirror the primary agent view.
87
+ */
88
+ function buildSubagentDisplayItems(events, keyPrefix) {
89
+ const items = [];
90
+ const openByName = new Map();
91
+ let textBuffer = '';
92
+ let seq = 0;
93
+ const flushText = () => {
94
+ if (textBuffer.trim()) {
95
+ items.push({
96
+ id: `${keyPrefix}:msg:${seq++}`,
97
+ role: 'assistant',
98
+ content: textBuffer,
99
+ createdAt: new Date(0),
100
+ });
101
+ }
102
+ textBuffer = '';
103
+ };
104
+ for (const event of events) {
105
+ switch (event.phase) {
106
+ case 'text':
107
+ textBuffer += event.text ?? '';
108
+ break;
109
+ case 'tool_call': {
110
+ flushText();
111
+ const id = `${keyPrefix}:tool:${seq++}`;
112
+ const toolCall = {
113
+ id,
114
+ type: 'tool-call',
115
+ toolCallId: id,
116
+ toolName: event.toolName ?? 'tool',
117
+ args: event.toolArgs ?? {},
118
+ status: 'inProgress',
119
+ };
120
+ items.push(toolCall);
121
+ if (event.toolName) {
122
+ openByName.set(event.toolName, toolCall);
123
+ }
124
+ break;
125
+ }
126
+ case 'tool_result': {
127
+ flushText();
128
+ const open = event.toolName
129
+ ? openByName.get(event.toolName)
130
+ : undefined;
131
+ if (open) {
132
+ open.result = event.result;
133
+ open.status = 'complete';
134
+ if (event.toolName) {
135
+ openByName.delete(event.toolName);
136
+ }
137
+ }
138
+ else {
139
+ const id = `${keyPrefix}:tool:${seq++}`;
140
+ items.push({
141
+ id,
142
+ type: 'tool-call',
143
+ toolCallId: id,
144
+ toolName: event.toolName ?? 'tool',
145
+ args: {},
146
+ result: event.result,
147
+ status: 'complete',
148
+ });
149
+ }
150
+ break;
151
+ }
152
+ case 'error':
153
+ flushText();
154
+ items.push({
155
+ id: `${keyPrefix}:msg:${seq++}`,
156
+ role: 'assistant',
157
+ content: `**\u26a0\ufe0f ${event.error ?? 'Subagent failed'}**`,
158
+ createdAt: new Date(0),
159
+ });
160
+ break;
161
+ // `start`, `thinking`, and `end` do not produce display items.
162
+ default:
163
+ break;
164
+ }
165
+ }
166
+ flushText();
167
+ return items;
168
+ }
169
+ /**
170
+ * Fixed-height, chat-style viewport for a single delegated subagent run.
171
+ * Reuses {@link ChatMessageList} so subagent output is formatted exactly like
172
+ * the primary agent, including tool-call cards and inline approvals. Tool
173
+ * approval decisions are sent over the shared monitoring socket.
174
+ */
175
+ export function SubagentChatPanel({ toolCallId, subagentName: subagentNameHint, height = 280, avatarConfig = SUBAGENT_AVATAR_CONFIG, }) {
176
+ const events = useAgentRuntimeSubagentActivityByToolCall(toolCallId, subagentNameHint);
177
+ const displayItems = useMemo(() => buildSubagentDisplayItems(events, toolCallId), [events, toolCallId]);
178
+ const messagesEndRef = useRef(null);
179
+ const subagentName = useMemo(() => {
180
+ for (const event of events) {
181
+ if (event.subagentName)
182
+ return event.subagentName;
183
+ }
184
+ return subagentNameHint ?? 'subagent';
185
+ }, [events, subagentNameHint]);
186
+ const isDone = useMemo(() => events.some(e => e.phase === 'end' || e.phase === 'error'), [events]);
187
+ const hasError = useMemo(() => events.some(e => e.phase === 'error'), [events]);
188
+ // Forward inline tool-approval decisions to the shared monitoring socket.
189
+ const handleRespond = useCallback(async (_toolCallId, result) => {
190
+ if (result && typeof result === 'object') {
191
+ const record = result;
192
+ if (record.type === 'tool-approval-decision' &&
193
+ typeof record.approved === 'boolean' &&
194
+ typeof record.approvalId === 'string') {
195
+ agentRuntimeStore
196
+ .getState()
197
+ .sendDecision(record.approvalId, record.approved);
198
+ }
199
+ }
200
+ }, []);
201
+ useEffect(() => {
202
+ messagesEndRef.current?.scrollIntoView({ block: 'end' });
203
+ }, [displayItems]);
204
+ if (events.length === 0) {
205
+ return null;
206
+ }
207
+ return (_jsxs(Box, { sx: {
208
+ mt: 2,
209
+ display: 'flex',
210
+ flexDirection: 'column',
211
+ height,
212
+ width: '100%',
213
+ border: '1px solid',
214
+ borderColor: 'border.default',
215
+ borderRadius: 2,
216
+ overflow: 'hidden',
217
+ bg: 'canvas.default',
218
+ }, children: [_jsxs(Box, { sx: {
219
+ display: 'flex',
220
+ alignItems: 'center',
221
+ gap: 1,
222
+ px: 2,
223
+ py: 1,
224
+ borderBottom: '1px solid',
225
+ borderColor: 'border.muted',
226
+ bg: 'canvas.subtle',
227
+ flexShrink: 0,
228
+ }, children: [_jsx(Box, { sx: {
229
+ display: 'flex',
230
+ color: hasError ? 'danger.fg' : isDone ? 'success.fg' : 'accent.fg',
231
+ }, children: _jsx(DependabotIcon, { size: 14 }) }), _jsx(Text, { sx: { fontSize: 0, fontWeight: 'bold', color: 'fg.default' }, children: subagentName }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted', ml: 'auto' }, children: hasError ? 'failed' : isDone ? 'done' : 'working\u2026' })] }), _jsx(Box, { sx: { flex: 1, minHeight: 0, overflowY: 'auto' }, children: _jsx(ChatMessageList, { displayItems: displayItems, isLoading: !isDone, isStreaming: !isDone, showLoadingIndicator: !isDone, hideMessagesAfterToolUI: false, avatarConfig: avatarConfig, padding: 2, onRespond: handleRespond, messagesEndRef: messagesEndRef, emptyContent: _jsxs(Box, { sx: {
232
+ display: 'flex',
233
+ alignItems: 'center',
234
+ gap: 1,
235
+ color: 'fg.muted',
236
+ p: 2,
237
+ }, children: [_jsx(Spinner, { size: "small" }), _jsx(Text, { sx: { fontSize: 0 }, children: "Starting\u2026" })] }) }) })] }));
238
+ }
73
239
  // ---------------------------------------------------------------------------
74
240
  // DefaultToolCallRenderer — reads approvals from the Zustand store,
75
241
  // sends decisions over the shared WebSocket (no REST polling).
@@ -175,11 +341,16 @@ function DefaultToolCallRenderer({ item, onRespond, }) {
175
341
  : externalDecision
176
342
  ? 'external'
177
343
  : undefined;
178
- return (_jsx(ToolCallDisplay, { toolCallId: item.toolCallId, toolName: item.toolName, args: item.args, result: item.result, status: item.status, error: item.error, executionError: item.executionError, codeError: item.codeError, exitCode: item.exitCode, approvalRequired: hasApproval, approvalState: approvalState, approvalDecisionSource: approvalDecisionSource, onApprove: effectiveApprovalId && !decision && !externalDecision
179
- ? () => makeDecision('approve')
180
- : undefined, onDeny: effectiveApprovalId && !decision && !externalDecision
181
- ? () => makeDecision('reject')
182
- : undefined, approvalLoading: false }));
344
+ // `normalizeName` strips underscores, so compare against the normalized form.
345
+ const isSubagentDelegation = normalizedToolName === 'delegatetask';
346
+ const delegatedSubagentName = typeof item.args?.subagent_name === 'string'
347
+ ? item.args.subagent_name
348
+ : undefined;
349
+ return (_jsxs(_Fragment, { children: [_jsx(ToolCallDisplay, { toolCallId: item.toolCallId, toolName: item.toolName, args: item.args, result: item.result, status: item.status, error: item.error, executionError: item.executionError, codeError: item.codeError, exitCode: item.exitCode, approvalRequired: hasApproval, approvalState: approvalState, approvalDecisionSource: approvalDecisionSource, onApprove: effectiveApprovalId && !decision && !externalDecision
350
+ ? () => makeDecision('approve')
351
+ : undefined, onDeny: effectiveApprovalId && !decision && !externalDecision
352
+ ? () => makeDecision('reject')
353
+ : undefined, approvalLoading: false }), isSubagentDelegation && (_jsx(SubagentChatPanel, { toolCallId: item.toolCallId, subagentName: delegatedSubagentName }))] }));
183
354
  }
184
355
  // ---------------------------------------------------------------------------
185
356
  // Component
@@ -1,5 +1,24 @@
1
1
  import type { INotebookContent } from '@jupyterlab/nbformat';
2
+ import type { ICollaborationProvider } from '@datalayer/jupyter-react';
2
3
  import type { EphemeralNotebookToolbarComponent } from '../../types/chat';
4
+ /**
5
+ * Explicit runtime endpoint used to bind an ephemeral notebook kernel without
6
+ * resolving a pod from the user's runtimes list. Used to reach an agent node's
7
+ * Jupyter server through the runtimes tunnel HTTP/WebSocket proxy.
8
+ */
9
+ export interface EphemeralRuntimeOverride {
10
+ /** REST base URL, e.g. `https://.../agent-nodes/{nodeId}/jupyter`. */
11
+ baseUrl: string;
12
+ /**
13
+ * WebSocket base URL. Defaults to `baseUrl` with the http(s) scheme swapped
14
+ * for ws(s). For the tunnel proxy this is the `/ws` sibling of `baseUrl`.
15
+ */
16
+ wsUrl?: string;
17
+ /** Bearer/JWT token appended to requests (`appendToken`). */
18
+ token?: string;
19
+ /** Stable identifier used for the sandbox service-manager registry. */
20
+ podName?: string;
21
+ }
3
22
  export interface EphemeralNotebookProps {
4
23
  /**
5
24
  * Notebook identifier. Must match the id passed to `useNotebookTools` so the
@@ -8,6 +27,14 @@ export interface EphemeralNotebookProps {
8
27
  notebookId: string;
9
28
  /** Preferred runtime pod name to bind the notebook kernel to. */
10
29
  runtimePodName?: string;
30
+ /**
31
+ * Explicit runtime endpoint override. When supplied, the notebook binds its
32
+ * kernel to this endpoint directly instead of resolving a pod from the user's
33
+ * runtimes list. This is how a SaaS browser reaches an agent node's Jupyter
34
+ * server through the runtimes tunnel proxy: `baseUrl` points at
35
+ * `.../agent-nodes/{nodeId}/jupyter` and `wsUrl` at its `/ws` sibling.
36
+ */
37
+ runtimeOverride?: EphemeralRuntimeOverride;
11
38
  /** Left margin reserved for the cell sidebar (default 120). */
12
39
  cellSidebarMargin?: number;
13
40
  /** Optional persisted notebook model to restore when mounting. */
@@ -16,9 +43,21 @@ export interface EphemeralNotebookProps {
16
43
  onNbformatChange?: (content: INotebookContent) => void;
17
44
  /** Optional toolbar component override. */
18
45
  toolbarComponent?: EphemeralNotebookToolbarComponent;
46
+ /** Optional theme variant override from host chat context. */
47
+ themeVariant?: string;
48
+ /** Optional color mode override from host chat context. */
49
+ colorMode?: 'light' | 'dark' | 'auto';
50
+ /**
51
+ * Optional real-time collaboration provider. When supplied, the notebook
52
+ * joins a shared collaborative room (the ydoc becomes the source of truth)
53
+ * and the local in-memory persistence poll is disabled. This is how a node's
54
+ * notebook state transits to the SaaS UI (and back) over RTC instead of the
55
+ * tunnel.
56
+ */
57
+ collaborationProvider?: ICollaborationProvider;
19
58
  }
20
59
  /**
21
60
  * Renders an in-memory notebook backed by a sandbox kernel.
22
61
  */
23
- export declare function EphemeralNotebook({ notebookId, runtimePodName, cellSidebarMargin, nbformat, onNbformatChange, toolbarComponent, }: EphemeralNotebookProps): import("react/jsx-runtime").JSX.Element;
62
+ export declare function EphemeralNotebook({ notebookId, runtimePodName, runtimeOverride, cellSidebarMargin, nbformat, onNbformatChange, toolbarComponent, themeVariant, colorMode, collaborationProvider, }: EphemeralNotebookProps): import("react/jsx-runtime").JSX.Element;
24
63
  export default EphemeralNotebook;