@datalayer/agent-runtimes 1.0.21 → 1.0.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/README.md +2 -2
  2. package/lib/AgentNode.js +26 -26
  3. package/lib/chat/Chat.d.ts +1 -1
  4. package/lib/chat/Chat.js +2 -2
  5. package/lib/chat/base/ChatBase.js +44 -9
  6. package/lib/chat/document/EphemeralDocument.d.ts +12 -1
  7. package/lib/chat/document/EphemeralDocument.js +4 -4
  8. package/lib/chat/notebook/EphemeralNotebook.d.ts +11 -1
  9. package/lib/chat/notebook/EphemeralNotebook.js +13 -2
  10. package/lib/collaboration/DatalayerCollaborationProvider.d.ts +1 -1
  11. package/lib/collaboration/DatalayerCollaborationProvider.js +5 -5
  12. package/lib/components/agents/index.d.ts +6 -0
  13. package/lib/components/{students → agents}/index.js +6 -1
  14. package/lib/components/{NotificationEventCard.js → cards/NotificationEventCard.js} +1 -1
  15. package/lib/components/{OutputCard.js → cards/OutputCard.js} +1 -1
  16. package/lib/components/cards/index.d.ts +9 -0
  17. package/lib/components/cards/index.js +13 -0
  18. package/lib/components/{runtimes/RuntimeCellVariables.d.ts → code-sandboxes/CodeSandboxCellVariables.d.ts} +3 -3
  19. package/lib/components/{runtimes/RuntimeCellVariables.js → code-sandboxes/CodeSandboxCellVariables.js} +2 -2
  20. package/lib/components/{runtimes/RuntimeCellVariablesDialog.d.ts → code-sandboxes/CodeSandboxCellVariablesDialog.d.ts} +4 -4
  21. package/lib/components/{runtimes/RuntimeCellVariablesDialog.js → code-sandboxes/CodeSandboxCellVariablesDialog.js} +4 -4
  22. package/lib/components/{runtimes/RuntimeLauncherDialog.d.ts → code-sandboxes/CodeSandboxLauncher.d.ts} +4 -4
  23. package/lib/components/{runtimes/RuntimeLauncherDialog.js → code-sandboxes/CodeSandboxLauncher.js} +33 -38
  24. package/lib/components/code-sandboxes/CodeSandboxPicker.d.ts +96 -0
  25. package/lib/components/code-sandboxes/CodeSandboxPicker.js +296 -0
  26. package/lib/components/{runtimes/RuntimePickerCell.d.ts → code-sandboxes/CodeSandboxPickerCell.d.ts} +5 -5
  27. package/lib/components/{runtimes/RuntimePickerCell.js → code-sandboxes/CodeSandboxPickerCell.js} +7 -7
  28. package/lib/components/{runtimes/RuntimeReservationControl.d.ts → code-sandboxes/CodeSandboxReservationControl.d.ts} +3 -3
  29. package/lib/components/{runtimes/RuntimeReservationControl.js → code-sandboxes/CodeSandboxReservationControl.js} +11 -4
  30. package/lib/components/{runtimes/RuntimeTransfer.d.ts → code-sandboxes/CodeSandboxTransfer.d.ts} +1 -1
  31. package/lib/components/{runtimes/RuntimeUtils.d.ts → code-sandboxes/CodeSandboxUtils.d.ts} +3 -3
  32. package/lib/components/{runtimes/RuntimeUtils.js → code-sandboxes/CodeSandboxUtils.js} +35 -19
  33. package/lib/components/code-sandboxes/CodeSandboxVariables.d.ts +71 -0
  34. package/lib/components/{runtimes/RuntimeVariables.js → code-sandboxes/CodeSandboxVariables.js} +77 -2
  35. package/lib/components/code-sandboxes/NewCodeSandboxControls.d.ts +42 -0
  36. package/lib/components/code-sandboxes/NewCodeSandboxControls.js +76 -0
  37. package/lib/components/code-sandboxes/index.d.ts +21 -0
  38. package/lib/components/code-sandboxes/index.js +25 -0
  39. package/lib/components/index.d.ts +4 -6
  40. package/lib/components/index.js +4 -6
  41. package/lib/components/progress/CreditsIndicator.d.ts +7 -0
  42. package/lib/components/progress/CreditsIndicator.js +3 -3
  43. package/lib/context/CostUsageChart.d.ts +2 -2
  44. package/lib/context/CostUsageChart.js +7 -7
  45. package/lib/context/TokenUsageChart.d.ts +2 -2
  46. package/lib/context/TokenUsageChart.js +6 -6
  47. package/lib/context/TurnGraphChart.d.ts +1 -1
  48. package/lib/context/TurnGraphChart.js +6 -6
  49. package/lib/examples/AgentEvalsExample.js +1 -1
  50. package/lib/examples/AgentGuardrailsExample.js +3 -3
  51. package/lib/examples/AgentInferenceProviderExample.js +1 -1
  52. package/lib/examples/AgentMonitoringExample.js +6 -6
  53. package/lib/examples/AgentOtelExample.d.ts +2 -2
  54. package/lib/examples/AgentOtelExample.js +5 -5
  55. package/lib/examples/AgentspecsExample.js +1 -1
  56. package/lib/examples/NotebookCollaborationExample.js +8 -8
  57. package/lib/examples/main.js +5 -5
  58. package/lib/examples2/DatalayerNotebookExample.js +8 -8
  59. package/lib/examples2/main.js +5 -5
  60. package/lib/hooks/useAgentRuntimes.js +3 -3
  61. package/lib/hooks/useMonitoring.d.ts +5 -5
  62. package/lib/hooks/useMonitoring.js +10 -10
  63. package/lib/protocols/AGUIAdapter.js +4 -0
  64. package/lib/protocols/VercelAIAdapter.js +3 -0
  65. package/lib/types/chat.d.ts +23 -0
  66. package/lib/types/tools.d.ts +11 -0
  67. package/package.json +4 -4
  68. package/lib/components/runtimes/RuntimePickerBase.d.ts +0 -69
  69. package/lib/components/runtimes/RuntimePickerBase.js +0 -157
  70. package/lib/components/runtimes/RuntimePickerNotebook.d.ts +0 -42
  71. package/lib/components/runtimes/RuntimePickerNotebook.js +0 -232
  72. package/lib/components/runtimes/RuntimeSimplePicker.d.ts +0 -38
  73. package/lib/components/runtimes/RuntimeSimplePicker.js +0 -156
  74. package/lib/components/runtimes/RuntimeVariables.d.ts +0 -38
  75. package/lib/components/runtimes/index.d.ts +0 -11
  76. package/lib/components/runtimes/index.js +0 -15
  77. package/lib/components/students/StudentItemStatus.d.ts +0 -7
  78. package/lib/components/students/StudentItemStatus.js +0 -68
  79. package/lib/components/students/index.d.ts +0 -1
  80. package/lib/components/toolbars/AssignmentEditorToolbar.d.ts +0 -4
  81. package/lib/components/toolbars/AssignmentEditorToolbar.js +0 -18
  82. package/lib/components/toolbars/DocumentEditorToolbar.d.ts +0 -2
  83. package/lib/components/toolbars/DocumentEditorToolbar.js +0 -12
  84. package/lib/components/toolbars/NotebookEditorToolbar.d.ts +0 -29
  85. package/lib/components/toolbars/NotebookEditorToolbar.js +0 -30
  86. package/scripts/codegen/__pycache__/versioning.cpython-313.pyc +0 -0
  87. /package/lib/components/{AgentSummary.d.ts → agents/AgentSummary.d.ts} +0 -0
  88. /package/lib/components/{AgentSummary.js → agents/AgentSummary.js} +0 -0
  89. /package/lib/components/{NotificationEventCard.d.ts → cards/NotificationEventCard.d.ts} +0 -0
  90. /package/lib/components/{OutputCard.d.ts → cards/OutputCard.d.ts} +0 -0
  91. /package/lib/components/{ToolApprovalCard.d.ts → cards/ToolApprovalCard.d.ts} +0 -0
  92. /package/lib/components/{ToolApprovalCard.js → cards/ToolApprovalCard.js} +0 -0
  93. /package/lib/components/{runtimes/RuntimeTransfer.js → code-sandboxes/CodeSandboxTransfer.js} +0 -0
package/README.md CHANGED
@@ -261,7 +261,7 @@ and propagates those values to the Vite HTML placeholders.
261
261
  Override any URL on the command line:
262
262
 
263
263
  ```bash
264
- make examples:prod DATALAYER_URL=https://prod2.datalayer.run
264
+ make examples:prod DATALAYER_DEFAULT_URL=https://prod2.datalayer.run
265
265
  ```
266
266
 
267
267
  ### Running against a local `plane local` stack
@@ -285,7 +285,7 @@ both http and ws traffic stay local) at the matching localhost port exposed by
285
285
  | `PLANE_LOCAL_MANAGER_URL` | `http://localhost:2100` |
286
286
  | `PLANE_LOCAL_AI_AGENTS_URL` | `http://localhost:4400` |
287
287
  | `PLANE_LOCAL_AI_INFERENCE_URL` | `http://localhost:4450` |
288
- | `PLANE_LOCAL_MCP_SERVERS_URL` | `http://localhost:4111` |
288
+ | `PLANE_LOCAL_JUPYTER_MCP_SERVER_URL` | `http://localhost:4404/mcp` |
289
289
  | `PLANE_LOCAL_GROWTH_URL` | `http://localhost:6660` |
290
290
  | `PLANE_LOCAL_SUCCESS_URL` | `http://localhost:3300` |
291
291
  | `PLANE_LOCAL_STATUS_URL` | `http://localhost:4785` |
package/lib/AgentNode.js CHANGED
@@ -49,7 +49,7 @@ const LOCAL_JUPYTER_SANDBOX = (() => {
49
49
  return { baseUrl: raw.replace(/\/$/, ''), token: undefined };
50
50
  }
51
51
  })();
52
- const DEFAULT_DATALAYER_URL = 'https://prod1.datalayer.run';
52
+ const DEFAULT_DATALAYER_SERVICE_URL = 'https://prod1.datalayer.run';
53
53
  /**
54
54
  * localStorage key recording that the user explicitly signed out. When set, the
55
55
  * UI must not silently re-authenticate from the env-supplied DATALAYER_API_KEY
@@ -76,7 +76,7 @@ function setAutoBootstrapDisabled(disabled) {
76
76
  * `DATALAYER_*_URL` environment variables, e.g. from `plane local`) when it
77
77
  * serves the built agent pages. Reading it at runtime lets the node target the
78
78
  * configured services (IAM, runtimes, ...) instead of the build-time-baked
79
- * `VITE_DATALAYER_URL`, which defaults to production because `make build` runs
79
+ * `VITE_DATALAYER_*_URL`, which default to production because `make build` runs
80
80
  * without the local environment.
81
81
  */
82
82
  const getConfigUrlFromDocument = (...keys) => {
@@ -101,18 +101,18 @@ const getConfigUrlFromDocument = (...keys) => {
101
101
  }
102
102
  return undefined;
103
103
  };
104
- /** Resolve the base Datalayer URL: injected config → VITE env → production. */
105
- const resolveDatalayerUrl = () => getConfigUrlFromDocument('datalayerUrl', 'iamUrl') ||
106
- import.meta.env?.VITE_DATALAYER_URL ||
107
- DEFAULT_DATALAYER_URL;
108
- /** Resolve the runtimes URL: injected config → VITE env → base Datalayer URL. */
104
+ /** Resolve the IAM URL: injected config → VITE env → production. */
105
+ const resolveIamUrl = () => getConfigUrlFromDocument('iamUrl') ||
106
+ import.meta.env?.VITE_DATALAYER_IAM_URL ||
107
+ DEFAULT_DATALAYER_SERVICE_URL;
108
+ /** Resolve the runtimes URL: injected config → VITE env → production. */
109
109
  const resolveRuntimesUrl = () => getConfigUrlFromDocument('runtimesUrl') ||
110
110
  import.meta.env?.VITE_DATALAYER_RUNTIMES_URL ||
111
- resolveDatalayerUrl();
112
- /** Resolve the spacer URL: injected config → VITE env → base Datalayer URL. */
111
+ DEFAULT_DATALAYER_SERVICE_URL;
112
+ /** Resolve the spacer URL: injected config → VITE env → production. */
113
113
  const resolveSpacerUrl = () => getConfigUrlFromDocument('spacerUrl') ||
114
114
  import.meta.env?.VITE_DATALAYER_SPACER_URL ||
115
- resolveDatalayerUrl();
115
+ DEFAULT_DATALAYER_SERVICE_URL;
116
116
  const MODE_CARDS = [
117
117
  {
118
118
  mode: 'private',
@@ -236,7 +236,7 @@ function AgentNodeProfileView({ token, onTokenExpired, avatarFallbackBackground,
236
236
  export function AgentNode() {
237
237
  const { token, setAuth, clearAuth } = useSimpleAuthStore();
238
238
  const tokenForCore = token ?? undefined;
239
- const signInLoginUrl = `${resolveDatalayerUrl()}/api/iam/v1/login`;
239
+ const signInLoginUrl = `${resolveIamUrl()}/api/iam/v1/login`;
240
240
  const queryClient = useQueryClient();
241
241
  const iamUser = useIAMStore(state => state.user);
242
242
  const { colorMode, theme: themeVariant } = useAgentNodeThemeStore();
@@ -287,7 +287,7 @@ export function AgentNode() {
287
287
  }
288
288
  const spacerUrl = resolveSpacerUrl();
289
289
  return new DatalayerCollaborationProvider({
290
- datalayerUrl: spacerUrl,
290
+ spacerUrl,
291
291
  token,
292
292
  });
293
293
  }, [ephemeralCollaborationDocumentId, token]);
@@ -702,26 +702,26 @@ export function AgentNode() {
702
702
  }, [token, pushCredentials]);
703
703
  useEffect(() => {
704
704
  import('@datalayer/core/lib/state').then(({ iamStore, coreStore }) => {
705
- const datalayerUrl = resolveDatalayerUrl();
705
+ const iamUrl = resolveIamUrl();
706
706
  const runtimesUrl = resolveRuntimesUrl();
707
707
  const aiInferenceUrl = getConfigUrlFromDocument('aiInferenceUrl') ||
708
708
  import.meta.env?.VITE_DATALAYER_AI_INFERENCE_URL ||
709
- datalayerUrl;
709
+ DEFAULT_DATALAYER_SERVICE_URL;
710
710
  // Seed all per-service URLs to match the main UI login behavior.
711
711
  const coreApi = coreStore.getState();
712
712
  const prevCfg = coreApi.configuration ?? {};
713
713
  const urls = {
714
- iamUrl: datalayerUrl,
714
+ iamUrl: iamUrl,
715
715
  runtimesUrl,
716
- spacerUrl: datalayerUrl,
717
- libraryUrl: datalayerUrl,
718
- aiAgentsUrl: datalayerUrl,
716
+ spacerUrl: iamUrl,
717
+ libraryUrl: iamUrl,
718
+ aiAgentsUrl: iamUrl,
719
719
  aiInferenceUrl: aiInferenceUrl,
720
- mcpServersUrl: datalayerUrl,
721
- otelUrl: datalayerUrl,
722
- growthUrl: datalayerUrl,
723
- successUrl: datalayerUrl,
724
- supportUrl: datalayerUrl,
720
+ jupyterMcpServerUrl: 'https://mcp.datalayer.run/mcp',
721
+ otelUrl: iamUrl,
722
+ growthUrl: iamUrl,
723
+ successUrl: iamUrl,
724
+ supportUrl: iamUrl,
725
725
  };
726
726
  if (typeof coreApi.setConfiguration === 'function') {
727
727
  coreApi.setConfiguration({ ...prevCfg, ...urls });
@@ -732,7 +732,7 @@ export function AgentNode() {
732
732
  }));
733
733
  }
734
734
  const api = iamStore.getState();
735
- iamStore.setState({ token: tokenForCore, iamUrl: datalayerUrl });
735
+ iamStore.setState({ token: tokenForCore, iamUrl });
736
736
  if (tokenForCore && typeof api.refreshUserByToken === 'function') {
737
737
  void Promise.resolve(api.refreshUserByToken(tokenForCore)).then(() => {
738
738
  queryClient.invalidateQueries({ queryKey: ['organizations'] });
@@ -841,9 +841,9 @@ export function AgentNode() {
841
841
  // API keys are exchanged for a session token before login so billing and
842
842
  // plans endpoints (/api/iam/v1/plans/*) resolve the correct paid plan.
843
843
  const handleApiKeySignIn = async (apiKey) => {
844
- const datalayerUrl = resolveDatalayerUrl();
844
+ const iamUrl = resolveIamUrl();
845
845
  try {
846
- const resp = await fetch(`${datalayerUrl}/api/iam/v1/login`, {
846
+ const resp = await fetch(`${iamUrl}/api/iam/v1/login`, {
847
847
  method: 'POST',
848
848
  headers: { 'Content-Type': 'application/json' },
849
849
  body: JSON.stringify({ token: apiKey }),
@@ -107,5 +107,5 @@ export interface ChatProps extends ChatCommonProps {
107
107
  * />
108
108
  * ```
109
109
  */
110
- export declare function Chat({ protocol: transport, extensions: _extensions, baseUrl, endpoint: endpointProp, configEndpoint: configEndpointProp, enableConfigQuery: enableConfigQueryProp, wsUrl, agentId, authToken: authTokenProp, placeholder, title, subtitle, brandIcon, autoConnect, streaming: _streaming, onMessageSent: _onMessageSent, onMessageReceived: _onMessageReceived, onDisconnect, onLogout: _onLogout, onCollapsePanel: _onCollapsePanel, className, height, showHeader, showNewChatButton, showClearButton, showModelSelector, showToolsMenu, showInput, disableInputPrompt, overlay, launching, launchingMessage, showSkillsMenu, codemodeEnabled, onToggleCodemode, showTokenUsage, initialModel, availableModels, mcpServers, initialSkills, clearOnMount: _clearOnMount, suggestions, submitOnSuggestionClick, description, headerContent, headerActions, autoFocus, identityProviders, onIdentityConnect, onIdentityDisconnect, runtimeId, historyEndpoint, pendingPrompt, errorBanner, showInformation, chatViewMode, onChatViewModeChange, frontendTools, enableEphemeralNotebook, initialEphemeralNotebookOpen, onEphemeralNotebookOpenChange, enableEphemeralDocument, initialEphemeralSurfaceMode, onEphemeralSurfaceModeChange, collapsed, onExpandFromCollapsed, ephemeralNotebookToolbar, ephemeralNotebookCollaborationProvider, ephemeralNotebookCollaborationDocumentId, ephemeralDocumentCollaboration, ephemeralRuntimeOverride, onToolCallStart, onToolCallComplete, renderToolResult, hideMessagesAfterToolUI, contextSnapshot, mcpStatusData, codemodeStatusData, sandboxStatusData, kernel, kernelIndicatorPlacement, kernelEnvironmentName, kernelCpu, kernelMemory, kernelGpu, themeVariant, colorMode, showToolApprovalBanner, pendingApprovals, onApproveApproval, onRejectApproval, disableInternalJupyterTheme, }: ChatProps): import("react/jsx-runtime").JSX.Element;
110
+ export declare function Chat({ protocol: transport, extensions: _extensions, baseUrl, endpoint: endpointProp, configEndpoint: configEndpointProp, enableConfigQuery: enableConfigQueryProp, wsUrl, agentId, authToken: authTokenProp, placeholder, title, subtitle, brandIcon, autoConnect, streaming: _streaming, onMessageSent: _onMessageSent, onMessageReceived: _onMessageReceived, onDisconnect, onLogout: _onLogout, onCollapsePanel: _onCollapsePanel, className, height, showHeader, showNewChatButton, showClearButton, showModelSelector, showToolsMenu, showInput, disableInputPrompt, overlay, launching, launchingMessage, showSkillsMenu, codemodeEnabled, onToggleCodemode, showTokenUsage, initialModel, availableModels, mcpServers, initialSkills, clearOnMount: _clearOnMount, suggestions, submitOnSuggestionClick, description, headerContent, headerActions, autoFocus, identityProviders, onIdentityConnect, onIdentityDisconnect, runtimeId, historyEndpoint, pendingPrompt, errorBanner, showInformation, chatViewMode, onChatViewModeChange, frontendTools, enableEphemeralNotebook, initialEphemeralNotebookOpen, onEphemeralNotebookOpenChange, enableEphemeralDocument, initialEphemeralSurfaceMode, onEphemeralSurfaceModeChange, collapsed, onExpandFromCollapsed, ephemeralNotebookToolbar, ephemeralNotebookToolbarExtraItems, ephemeralDocumentToolbarExtraItems, ephemeralNotebookCollaborationProvider, ephemeralNotebookCollaborationDocumentId, ephemeralDocumentCollaboration, ephemeralRuntimeOverride, onToolCallStart, onToolCallComplete, renderToolResult, hideMessagesAfterToolUI, contextSnapshot, mcpStatusData, codemodeStatusData, sandboxStatusData, kernel, kernelIndicatorPlacement, kernelEnvironmentName, kernelCpu, kernelMemory, kernelGpu, themeVariant, colorMode, showToolApprovalBanner, pendingApprovals, onApproveApproval, onRejectApproval, disableInternalJupyterTheme, }: ChatProps): import("react/jsx-runtime").JSX.Element;
111
111
  export default Chat;
package/lib/chat/Chat.js CHANGED
@@ -136,7 +136,7 @@ function getProtocolType(protocol) {
136
136
  * />
137
137
  * ```
138
138
  */
139
- export function Chat({ protocol: transport, extensions: _extensions, baseUrl = 'http://localhost:8765', endpoint: endpointProp, configEndpoint: configEndpointProp, enableConfigQuery: enableConfigQueryProp, wsUrl, agentId, authToken: authTokenProp, placeholder = 'Type your message...', title, subtitle, brandIcon, autoConnect = true, streaming: _streaming = true, onMessageSent: _onMessageSent, onMessageReceived: _onMessageReceived, onDisconnect, onLogout: _onLogout, onCollapsePanel: _onCollapsePanel, className, height = '600px', showHeader = true, showNewChatButton = true, showClearButton = true, showModelSelector = true, showToolsMenu = true, showInput = true, disableInputPrompt = false, overlay, launching = false, launchingMessage, showSkillsMenu = true, codemodeEnabled = false, onToggleCodemode, showTokenUsage = true, initialModel, availableModels, mcpServers, initialSkills, clearOnMount: _clearOnMount = true, suggestions, submitOnSuggestionClick = true, description, headerContent, headerActions, autoFocus = false, identityProviders, onIdentityConnect, onIdentityDisconnect, runtimeId, historyEndpoint, pendingPrompt, errorBanner, showInformation = true, chatViewMode, onChatViewModeChange, frontendTools, enableEphemeralNotebook, initialEphemeralNotebookOpen, onEphemeralNotebookOpenChange, enableEphemeralDocument, initialEphemeralSurfaceMode, onEphemeralSurfaceModeChange, collapsed = false, onExpandFromCollapsed, ephemeralNotebookToolbar, ephemeralNotebookCollaborationProvider, ephemeralNotebookCollaborationDocumentId, ephemeralDocumentCollaboration, ephemeralRuntimeOverride, onToolCallStart, onToolCallComplete, renderToolResult, hideMessagesAfterToolUI = false, contextSnapshot, mcpStatusData, codemodeStatusData, sandboxStatusData, kernel, kernelIndicatorPlacement, kernelEnvironmentName, kernelCpu, kernelMemory, kernelGpu, themeVariant, colorMode, showToolApprovalBanner, pendingApprovals, onApproveApproval, onRejectApproval, disableInternalJupyterTheme = false, }) {
139
+ export function Chat({ protocol: transport, extensions: _extensions, baseUrl = 'http://localhost:8765', endpoint: endpointProp, configEndpoint: configEndpointProp, enableConfigQuery: enableConfigQueryProp, wsUrl, agentId, authToken: authTokenProp, placeholder = 'Type your message...', title, subtitle, brandIcon, autoConnect = true, streaming: _streaming = true, onMessageSent: _onMessageSent, onMessageReceived: _onMessageReceived, onDisconnect, onLogout: _onLogout, onCollapsePanel: _onCollapsePanel, className, height = '600px', showHeader = true, showNewChatButton = true, showClearButton = true, showModelSelector = true, showToolsMenu = true, showInput = true, disableInputPrompt = false, overlay, launching = false, launchingMessage, showSkillsMenu = true, codemodeEnabled = false, onToggleCodemode, showTokenUsage = true, initialModel, availableModels, mcpServers, initialSkills, clearOnMount: _clearOnMount = true, suggestions, submitOnSuggestionClick = true, description, headerContent, headerActions, autoFocus = false, identityProviders, onIdentityConnect, onIdentityDisconnect, runtimeId, historyEndpoint, pendingPrompt, errorBanner, showInformation = true, chatViewMode, onChatViewModeChange, frontendTools, enableEphemeralNotebook, initialEphemeralNotebookOpen, onEphemeralNotebookOpenChange, enableEphemeralDocument, initialEphemeralSurfaceMode, onEphemeralSurfaceModeChange, collapsed = false, onExpandFromCollapsed, ephemeralNotebookToolbar, ephemeralNotebookToolbarExtraItems, ephemeralDocumentToolbarExtraItems, ephemeralNotebookCollaborationProvider, ephemeralNotebookCollaborationDocumentId, ephemeralDocumentCollaboration, ephemeralRuntimeOverride, onToolCallStart, onToolCallComplete, renderToolResult, hideMessagesAfterToolUI = false, contextSnapshot, mcpStatusData, codemodeStatusData, sandboxStatusData, kernel, kernelIndicatorPlacement, kernelEnvironmentName, kernelCpu, kernelMemory, kernelGpu, themeVariant, colorMode, showToolApprovalBanner, pendingApprovals, onApproveApproval, onRejectApproval, disableInternalJupyterTheme = false, }) {
140
140
  const resolvedAgentId = typeof agentId === 'string' && agentId.trim().length > 0
141
141
  ? agentId.trim()
142
142
  : 'default';
@@ -364,6 +364,6 @@ export function Chat({ protocol: transport, extensions: _extensions, baseUrl = '
364
364
  ? 'attention.fg'
365
365
  : 'danger.fg',
366
366
  flex: 1,
367
- }, children: errorBanner.message })] })), _jsx(ChatBase, { title: title, subtitle: subtitle, brandIcon: brandIcon, showHeader: showHeader, protocol: protocolConfig, placeholder: placeholder, description: description, suggestions: suggestions, submitOnSuggestionClick: submitOnSuggestionClick, autoFocus: autoFocus, runtimeId: runtimeId, historyEndpoint: historyEndpoint, pendingPrompt: pendingPrompt, showInformation: showInformation, onInformationClick: handleInformationClick, headerContent: headerContent, headerActions: headerActions, showModelSelector: showModelSelector, showToolsMenu: showToolsMenu, showInput: showInput, disableInputPrompt: disableInputPrompt, overlay: overlay, launching: launching, launchingMessage: launchingMessage, autoConnect: autoConnect, showSkillsMenu: showSkillsMenu, showTokenUsage: showTokenUsage, codemodeEnabled: codemodeEnabled, onToggleCodemode: onToggleCodemode, initialModel: initialModel, availableModels: availableModels, mcpServers: mcpServers, initialSkills: initialSkills, connectedIdentities: identitiesForChat, onNewChat: handleNewChat, onMessagesChange: handleMessagesChange, headerButtons: headerButtons, avatarConfig: avatarConfig, backgroundColor: "canvas.default", focusTrigger: focusTrigger, chatViewMode: chatViewMode, onChatViewModeChange: onChatViewModeChange, frontendTools: frontendTools, enableEphemeralNotebook: enableEphemeralNotebook, initialEphemeralNotebookOpen: initialEphemeralNotebookOpen, onEphemeralNotebookOpenChange: onEphemeralNotebookOpenChange, enableEphemeralDocument: enableEphemeralDocument, initialEphemeralSurfaceMode: initialEphemeralSurfaceMode, onEphemeralSurfaceModeChange: onEphemeralSurfaceModeChange, collapsed: collapsed, onExpandFromCollapsed: onExpandFromCollapsed, ephemeralNotebookToolbar: ephemeralNotebookToolbar, ephemeralNotebookCollaborationProvider: ephemeralNotebookCollaborationProvider, ephemeralNotebookCollaborationDocumentId: ephemeralNotebookCollaborationDocumentId, ephemeralDocumentCollaboration: ephemeralDocumentCollaboration, ephemeralRuntimeOverride: ephemeralRuntimeOverride, onToolCallStart: onToolCallStart, onToolCallComplete: onToolCallComplete, renderToolResult: renderToolResult, hideMessagesAfterToolUI: hideMessagesAfterToolUI, contextSnapshot: contextSnapshot, mcpStatusData: mcpStatusData, sandboxStatusData: sandboxStatusData, kernel: kernel, kernelIndicatorPlacement: kernelIndicatorPlacement, kernelEnvironmentName: kernelEnvironmentName, kernelCpu: kernelCpu, kernelMemory: kernelMemory, kernelGpu: kernelGpu, themeVariant: themeVariant, colorMode: colorMode, showToolApprovalBanner: showToolApprovalBanner, pendingApprovals: pendingApprovals, onApproveApproval: onApproveApproval, onRejectApproval: onRejectApproval, disableInternalJupyterTheme: disableInternalJupyterTheme })] })] }) }) }));
367
+ }, children: errorBanner.message })] })), _jsx(ChatBase, { title: title, subtitle: subtitle, brandIcon: brandIcon, showHeader: showHeader, protocol: protocolConfig, placeholder: placeholder, description: description, suggestions: suggestions, submitOnSuggestionClick: submitOnSuggestionClick, autoFocus: autoFocus, runtimeId: runtimeId, historyEndpoint: historyEndpoint, pendingPrompt: pendingPrompt, showInformation: showInformation, onInformationClick: handleInformationClick, headerContent: headerContent, headerActions: headerActions, showModelSelector: showModelSelector, showToolsMenu: showToolsMenu, showInput: showInput, disableInputPrompt: disableInputPrompt, overlay: overlay, launching: launching, launchingMessage: launchingMessage, autoConnect: autoConnect, showSkillsMenu: showSkillsMenu, showTokenUsage: showTokenUsage, codemodeEnabled: codemodeEnabled, onToggleCodemode: onToggleCodemode, initialModel: initialModel, availableModels: availableModels, mcpServers: mcpServers, initialSkills: initialSkills, connectedIdentities: identitiesForChat, onNewChat: handleNewChat, onMessagesChange: handleMessagesChange, headerButtons: headerButtons, avatarConfig: avatarConfig, backgroundColor: "canvas.default", focusTrigger: focusTrigger, chatViewMode: chatViewMode, onChatViewModeChange: onChatViewModeChange, frontendTools: frontendTools, enableEphemeralNotebook: enableEphemeralNotebook, initialEphemeralNotebookOpen: initialEphemeralNotebookOpen, onEphemeralNotebookOpenChange: onEphemeralNotebookOpenChange, enableEphemeralDocument: enableEphemeralDocument, initialEphemeralSurfaceMode: initialEphemeralSurfaceMode, onEphemeralSurfaceModeChange: onEphemeralSurfaceModeChange, collapsed: collapsed, onExpandFromCollapsed: onExpandFromCollapsed, ephemeralNotebookToolbar: ephemeralNotebookToolbar, ephemeralNotebookToolbarExtraItems: ephemeralNotebookToolbarExtraItems, ephemeralDocumentToolbarExtraItems: ephemeralDocumentToolbarExtraItems, ephemeralNotebookCollaborationProvider: ephemeralNotebookCollaborationProvider, ephemeralNotebookCollaborationDocumentId: ephemeralNotebookCollaborationDocumentId, ephemeralDocumentCollaboration: ephemeralDocumentCollaboration, ephemeralRuntimeOverride: ephemeralRuntimeOverride, onToolCallStart: onToolCallStart, onToolCallComplete: onToolCallComplete, renderToolResult: renderToolResult, hideMessagesAfterToolUI: hideMessagesAfterToolUI, contextSnapshot: contextSnapshot, mcpStatusData: mcpStatusData, sandboxStatusData: sandboxStatusData, kernel: kernel, kernelIndicatorPlacement: kernelIndicatorPlacement, kernelEnvironmentName: kernelEnvironmentName, kernelCpu: kernelCpu, kernelMemory: kernelMemory, kernelGpu: kernelGpu, themeVariant: themeVariant, colorMode: colorMode, showToolApprovalBanner: showToolApprovalBanner, pendingApprovals: pendingApprovals, onApproveApproval: onApproveApproval, onRejectApproval: onRejectApproval, disableInternalJupyterTheme: disableInternalJupyterTheme })] })] }) }) }));
368
368
  }
369
369
  export default Chat;
@@ -58,6 +58,28 @@ const sentPendingPromptKeys = new Set();
58
58
  * ephemeral notebook/document is not yet ready. Shown in place of the surface
59
59
  * content (never as an overlay) so structure appears as early as possible.
60
60
  */
61
+ /**
62
+ * Whether a frontend tool declares any parameter.
63
+ *
64
+ * The empty-args guard around execution exists for AG-UI, which emits a
65
+ * first tool-call with `{}` and the real arguments in a later update. A
66
+ * tool that declares no parameters never gets that update — `{}` IS its
67
+ * full argument set — so waiting on it left the call executing forever.
68
+ */
69
+ function frontendToolExpectsArgs(tool) {
70
+ const parameters = tool?.parameters;
71
+ if (!parameters) {
72
+ return false;
73
+ }
74
+ if (Array.isArray(parameters)) {
75
+ return parameters.length > 0;
76
+ }
77
+ const properties = parameters.properties;
78
+ if (properties && typeof properties === 'object') {
79
+ return Object.keys(properties).length > 0;
80
+ }
81
+ return Object.keys(parameters).length > 0;
82
+ }
61
83
  function CompanionSurfaceSkeleton({ mode }) {
62
84
  return (_jsx(Box, { "aria-label": mode === 'notebook' ? 'Preparing notebook…' : 'Preparing document…', sx: {
63
85
  flex: 1,
@@ -474,7 +496,7 @@ function ChatBaseInner({ title, subtitle, showHeader = false, showTokenUsage = t
474
496
  // Mode selection
475
497
  useStore: useStoreMode = true, protocol: protocolRaw, onSendMessage, enableStreaming = false,
476
498
  // Extended props
477
- brandIcon, avatarConfig, headerButtons, showPoweredBy = false, poweredByProps, emptyState, renderToolResult, footerContent, showInformation = false, onInformationClick, headerContent, children, borderRadius, backgroundColor, border, boxShadow, compact = false, placeholder, description = 'Start a conversation with the AI agent.', onStateUpdate, onNewChat, onClear, onMessagesChange, autoFocus = false, suggestions, submitOnSuggestionClick = true, hideMessagesAfterToolUI = false, focusTrigger, frontendTools: frontendToolsProp, enableEphemeralNotebook = false, initialEphemeralNotebookOpen = true, onEphemeralNotebookOpenChange, enableEphemeralDocument = false, initialEphemeralSurfaceMode, onEphemeralSurfaceModeChange, collapsed = false, onExpandFromCollapsed, ephemeralNotebookToolbar, ephemeralNotebookCollaborationProvider, ephemeralNotebookCollaborationDocumentId, ephemeralDocumentCollaboration, ephemeralRuntimeOverride,
499
+ brandIcon, avatarConfig, headerButtons, showPoweredBy = false, poweredByProps, emptyState, renderToolResult, footerContent, showInformation = false, onInformationClick, headerContent, children, borderRadius, backgroundColor, border, boxShadow, compact = false, placeholder, description = 'Start a conversation with the AI agent.', onStateUpdate, onNewChat, onClear, onMessagesChange, autoFocus = false, suggestions, submitOnSuggestionClick = true, hideMessagesAfterToolUI = false, focusTrigger, frontendTools: frontendToolsProp, enableEphemeralNotebook = false, initialEphemeralNotebookOpen = true, onEphemeralNotebookOpenChange, enableEphemeralDocument = false, initialEphemeralSurfaceMode, onEphemeralSurfaceModeChange, collapsed = false, onExpandFromCollapsed, ephemeralNotebookToolbar, ephemeralNotebookToolbarExtraItems, ephemeralDocumentToolbarExtraItems, ephemeralNotebookCollaborationProvider, ephemeralNotebookCollaborationDocumentId, ephemeralDocumentCollaboration, ephemeralRuntimeOverride,
478
500
  // Tool invocation hooks
479
501
  onToolCallStart, onToolCallComplete,
480
502
  // Identity/Authorization props
@@ -2011,6 +2033,14 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
2011
2033
  const toolCallId = event.toolCall.toolCallId || generateMessageId();
2012
2034
  const toolName = event.toolCall.toolName;
2013
2035
  const args = event.toolCall.args || {};
2036
+ /*
2037
+ * Whether these args are the full set, as the protocol tells it.
2038
+ * Vercel's tool event is terminal — `{}` is an answer there,
2039
+ * legal for a tool whose parameters are all optional. AG-UI
2040
+ * streams the args after a first empty event and says so with
2041
+ * `false`. Without the flag, the old heuristics decide.
2042
+ */
2043
+ const argsComplete = event.toolCall.argsComplete;
2014
2044
  if (toolCallsRef.current.has(toolCallId)) {
2015
2045
  const existingToolCall = toolCallsRef.current.get(toolCallId);
2016
2046
  if (existingToolCall) {
@@ -2026,7 +2056,7 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
2026
2056
  const toolHandler = frontendTool?.handler;
2027
2057
  if (toolHandler &&
2028
2058
  existingToolCall.status === 'executing' &&
2029
- Object.keys(args).length > 0) {
2059
+ (argsComplete ?? Object.keys(args).length > 0)) {
2030
2060
  pendingToolExecutionsRef.current++;
2031
2061
  executeFrontendTool(toolHandler, updatedToolCall, toolCallId);
2032
2062
  }
@@ -2051,12 +2081,17 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
2051
2081
  });
2052
2082
  const frontendTool = frontendToolsRef.current?.find(t => t.name === toolName);
2053
2083
  const toolHandler = frontendTool?.handler;
2054
- // Only execute when we have actual args. AG-UI emits an
2055
- // initial tool-call with empty args on TOOL_CALL_START;
2056
- // the real args arrive on TOOL_CALL_END. Skip execution
2057
- // here and let the update branch (above) handle it once
2058
- // the full args are available.
2059
- if (toolHandler && Object.keys(args).length > 0) {
2084
+ // Execute when the args are complete. The protocol says so
2085
+ // when it can (`argsComplete`); without the flag, fall back
2086
+ // to the old heuristics — actual args present, or a tool
2087
+ // that declares no parameters, for which `{}` is the full
2088
+ // set and no update is ever coming. A protocol that streams
2089
+ // its args (AG-UI start) says `false` and the update branch
2090
+ // above executes once the full set has arrived.
2091
+ if (toolHandler &&
2092
+ (argsComplete ??
2093
+ (Object.keys(args).length > 0 ||
2094
+ !frontendToolExpectsArgs(frontendTool)))) {
2060
2095
  pendingToolExecutionsRef.current++;
2061
2096
  executeFrontendTool(toolHandler, toolCallMsg, toolCallId);
2062
2097
  }
@@ -2937,7 +2972,7 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
2937
2972
  borderRight: '1px solid',
2938
2973
  borderColor: 'border.default',
2939
2974
  }),
2940
- }, children: launching || overlay ? (_jsx(CompanionSurfaceSkeleton, { mode: notebookVisible ? 'notebook' : 'document' })) : notebookVisible ? (_jsx(EphemeralNotebook, { notebookId: ephemeralNotebookId, runtimePodName: runtimeId || activeAgentId, runtimeOverride: ephemeralRuntimeOverride, themeVariant: themeVariant, colorMode: colorMode, nbformat: persistedEphemeralNbformat ?? undefined, onNbformatChange: handleEphemeralNotebookChange, toolbarComponent: ephemeralNotebookToolbar, collaborationProvider: ephemeralNotebookCollaborationProvider })) : (_jsx(React.Suspense, { fallback: null, children: _jsx(EphemeralDocument, { documentId: ephemeralDocumentId, runtimePodName: runtimeId || activeAgentId, runtimeOverride: ephemeralRuntimeOverride, themeVariant: themeVariant, colorMode: colorMode, content: persistedEphemeralDocument ?? undefined, onContentChange: handleEphemeralDocumentChange, onToolsReady: handleDocumentToolsReady, onKernelChange: handleDocumentKernelChange, collaboration: ephemeralDocumentCollaboration }) })) }), !surfaceCollapsed && (_jsxs(Box, { sx: surfaceChatFloating
2975
+ }, children: launching || overlay ? (_jsx(CompanionSurfaceSkeleton, { mode: notebookVisible ? 'notebook' : 'document' })) : notebookVisible ? (_jsx(EphemeralNotebook, { notebookId: ephemeralNotebookId, runtimePodName: runtimeId || activeAgentId, runtimeOverride: ephemeralRuntimeOverride, themeVariant: themeVariant, colorMode: colorMode, nbformat: persistedEphemeralNbformat ?? undefined, onNbformatChange: handleEphemeralNotebookChange, toolbarComponent: ephemeralNotebookToolbar, toolbarExtraItems: ephemeralNotebookToolbarExtraItems, collaborationProvider: ephemeralNotebookCollaborationProvider })) : (_jsx(React.Suspense, { fallback: null, children: _jsx(EphemeralDocument, { documentId: ephemeralDocumentId, runtimePodName: runtimeId || activeAgentId, runtimeOverride: ephemeralRuntimeOverride, themeVariant: themeVariant, colorMode: colorMode, content: persistedEphemeralDocument ?? undefined, onContentChange: handleEphemeralDocumentChange, onToolsReady: handleDocumentToolsReady, onKernelChange: handleDocumentKernelChange, collaboration: ephemeralDocumentCollaboration, toolbarExtraItems: ephemeralDocumentToolbarExtraItems }) })) }), !surfaceCollapsed && (_jsxs(Box, { sx: surfaceChatFloating
2941
2976
  ? {
2942
2977
  position: 'absolute',
2943
2978
  right: 16,
@@ -1,4 +1,5 @@
1
1
  import type { IKernelConnection } from '@jupyterlab/services/lib/kernel/kernel';
2
+ import { type ToolbarItem } from '@datalayer/primer-addons';
2
3
  import type { FrontendToolDefinition } from '../../types/tools';
3
4
  import type { EphemeralRuntimeOverride } from '../notebook/EphemeralNotebook';
4
5
  import '@datalayer/jupyter-react/lib/css/PrismCss';
@@ -63,9 +64,19 @@ export interface EphemeralDocumentProps {
63
64
  * local memory.
64
65
  */
65
66
  collaboration?: EphemeralDocumentCollaboration;
67
+ /**
68
+ * Items added to the toolbar of the document.
69
+ *
70
+ * The Lexical toolbar merges them with its own and orders the whole by the
71
+ * `order` of each item, so a host adds what the document itself knows
72
+ * nothing about — the status of the sandbox it runs on, a selector to
73
+ * change it — the same way the notebook surface does through the
74
+ * `extraItems` of its toolbar.
75
+ */
76
+ toolbarExtraItems?: ToolbarItem[];
66
77
  }
67
78
  /**
68
79
  * Renders an in-memory Lexical document backed by a sandbox kernel.
69
80
  */
70
- export declare function EphemeralDocument({ documentId, runtimePodName, runtimeOverride, themeVariant, colorMode, content, onContentChange, onToolsReady, onKernelChange, collaboration, }: EphemeralDocumentProps): import("react/jsx-runtime").JSX.Element;
81
+ export declare function EphemeralDocument({ documentId, runtimePodName, runtimeOverride, themeVariant, colorMode, content, onContentChange, onToolsReady, onKernelChange, collaboration, toolbarExtraItems, }: EphemeralDocumentProps): import("react/jsx-runtime").JSX.Element;
71
82
  export default EphemeralDocument;
@@ -100,15 +100,15 @@ function CodeHighlightPlugin() {
100
100
  * the active editor from the Lexical composer context and drives the shared
101
101
  * {@link ToolbarPlugin} (block type, formatting, insert menu, …).
102
102
  */
103
- function DocumentToolbar({ setIsLinkEditMode, }) {
103
+ function DocumentToolbar({ setIsLinkEditMode, extraItems, }) {
104
104
  const [editor] = useLexicalComposerContext();
105
105
  const [activeEditor, setActiveEditor] = useState(editor);
106
- return (_jsx(ToolbarPlugin, { editor: editor, activeEditor: activeEditor, setActiveEditor: setActiveEditor, setIsLinkEditMode: setIsLinkEditMode }));
106
+ return (_jsx(ToolbarPlugin, { editor: editor, activeEditor: activeEditor, setActiveEditor: setActiveEditor, setIsLinkEditMode: setIsLinkEditMode, extraItems: extraItems }));
107
107
  }
108
108
  /**
109
109
  * Renders an in-memory Lexical document backed by a sandbox kernel.
110
110
  */
111
- export function EphemeralDocument({ documentId, runtimePodName, runtimeOverride, themeVariant, colorMode, content, onContentChange, onToolsReady, onKernelChange, collaboration, }) {
111
+ export function EphemeralDocument({ documentId, runtimePodName, runtimeOverride, themeVariant, colorMode, content, onContentChange, onToolsReady, onKernelChange, collaboration, toolbarExtraItems, }) {
112
112
  // Real-time collaboration is active only when both a WebSocket endpoint and a
113
113
  // room id are supplied. In that mode the shared Loro CRDT is the single source
114
114
  // of truth: local content-seeding and undo history are disabled so the local
@@ -384,7 +384,7 @@ export function EphemeralDocument({ documentId, runtimePodName, runtimeOverride,
384
384
  '& [role="toolbar"][aria-label="Editor toolbar"]': {
385
385
  backgroundColor: themeBackground,
386
386
  },
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: {
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, extraItems: toolbarExtraItems }), _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
388
  height: '100%',
389
389
  display: 'flex',
390
390
  alignItems: 'center',
@@ -1,4 +1,5 @@
1
1
  import type { INotebookContent } from '@jupyterlab/nbformat';
2
+ import { type ToolbarItem } from '@datalayer/primer-addons';
2
3
  import type { ICollaborationProvider } from '@datalayer/jupyter-react';
3
4
  import type { EphemeralNotebookToolbarComponent } from '../../types/chat';
4
5
  /**
@@ -43,6 +44,15 @@ export interface EphemeralNotebookProps {
43
44
  onNbformatChange?: (content: INotebookContent) => void;
44
45
  /** Optional toolbar component override. */
45
46
  toolbarComponent?: EphemeralNotebookToolbarComponent;
47
+ /**
48
+ * Items added to the toolbar of the notebook.
49
+ *
50
+ * The notebook toolbar merges them with its own and orders the whole by the
51
+ * `order` of each item, so a host adds what the notebook itself knows
52
+ * nothing about — the status of the sandbox it runs on, a selector to
53
+ * change it — without replacing the toolbar through `toolbarComponent`.
54
+ */
55
+ toolbarExtraItems?: ToolbarItem[];
46
56
  /** Optional theme variant override from host chat context. */
47
57
  themeVariant?: string;
48
58
  /** Optional color mode override from host chat context. */
@@ -59,5 +69,5 @@ export interface EphemeralNotebookProps {
59
69
  /**
60
70
  * Renders an in-memory notebook backed by a sandbox kernel.
61
71
  */
62
- export declare function EphemeralNotebook({ notebookId, runtimePodName, runtimeOverride, cellSidebarMargin, nbformat, onNbformatChange, toolbarComponent, themeVariant, colorMode, collaborationProvider, }: EphemeralNotebookProps): import("react/jsx-runtime").JSX.Element;
72
+ export declare function EphemeralNotebook({ notebookId, runtimePodName, runtimeOverride, cellSidebarMargin, nbformat, onNbformatChange, toolbarComponent, toolbarExtraItems, themeVariant, colorMode, collaborationProvider, }: EphemeralNotebookProps): import("react/jsx-runtime").JSX.Element;
63
73
  export default EphemeralNotebook;
@@ -55,7 +55,7 @@ const EPHEMERAL_NOTEBOOK_CONTENT = {
55
55
  /**
56
56
  * Renders an in-memory notebook backed by a sandbox kernel.
57
57
  */
58
- export function EphemeralNotebook({ notebookId, runtimePodName, runtimeOverride, cellSidebarMargin = 120, nbformat, onNbformatChange, toolbarComponent, themeVariant, colorMode, collaborationProvider, }) {
58
+ export function EphemeralNotebook({ notebookId, runtimePodName, runtimeOverride, cellSidebarMargin = 120, nbformat, onNbformatChange, toolbarComponent, toolbarExtraItems, themeVariant, colorMode, collaborationProvider, }) {
59
59
  // The `nbformat` passed to the `Notebook` component MUST stay a stable
60
60
  // reference for the lifetime of a given `notebookId`: the underlying
61
61
  // `useNotebookModel` hook rebuilds the notebook model (and its context /
@@ -188,7 +188,18 @@ export function EphemeralNotebook({ notebookId, runtimePodName, runtimeOverride,
188
188
  const activeServiceManager = runtimeServiceManager;
189
189
  const activeKernelId = runtimeKernelId;
190
190
  const activeStartDefaultKernel = runtimeStartDefaultKernel;
191
- const ToolbarComponent = toolbarComponent || NotebookToolbar;
191
+ // The toolbar of the notebook, with the items of the host merged in. A host
192
+ // replacing the toolbar altogether receives them as well, as every toolbar
193
+ // built on the notebook one takes `extraItems`.
194
+ const ToolbarComponent = useMemo(() => {
195
+ const Base = toolbarComponent || NotebookToolbar;
196
+ if (!toolbarExtraItems?.length) {
197
+ return Base;
198
+ }
199
+ return function EphemeralNotebookToolbar(props) {
200
+ return _jsx(Base, { ...props, extraItems: toolbarExtraItems });
201
+ };
202
+ }, [toolbarComponent, toolbarExtraItems]);
192
203
  const isRuntimeStarting = Boolean((String(runtimePodName || '').trim() ||
193
204
  String(runtimeOverride?.baseUrl || '').trim()) &&
194
205
  !activeServiceManager);
@@ -15,7 +15,7 @@ export interface IDatalayerCollaborationConfig {
15
15
  /**
16
16
  * Base URL for the Datalayer server (optional, uses config from store if not provided).
17
17
  */
18
- datalayerUrl?: string;
18
+ spacerUrl?: string;
19
19
  /**
20
20
  * Authentication token (optional, uses config from store if not provided).
21
21
  */
@@ -60,17 +60,17 @@ export class DatalayerCollaborationProvider {
60
60
  }
61
61
  this.setStatus(CollaborationStatus.Connecting);
62
62
  try {
63
- const datalayerUrl = this._config.datalayerUrl;
63
+ const spacerUrl = this._config.spacerUrl;
64
64
  const token = this._config.token;
65
- if (!datalayerUrl) {
66
- throw new Error('Datalayer datalayerUrl is not configured - must be explicitly provided in DatalayerCollaborationProvider config');
65
+ if (!spacerUrl) {
66
+ throw new Error('The Datalayer spacerUrl is not configured - it must be explicitly provided in the DatalayerCollaborationProvider config');
67
67
  }
68
68
  if (!token) {
69
69
  throw new Error('Datalayer token is not configured - must be explicitly provided in DatalayerCollaborationProvider config');
70
70
  }
71
71
  const { ydoc, awareness } = sharedModel;
72
- const documentURL = URLExt.join(datalayerUrl, '/api/spacer/v1/documents');
73
- const wsUrl = URLExt.join(datalayerUrl, '/api/spacer/v1/documents/ws').replace(/^http/, 'ws');
72
+ const documentURL = URLExt.join(spacerUrl, '/api/spacer/v1/documents');
73
+ const wsUrl = URLExt.join(spacerUrl, '/api/spacer/v1/documents/ws').replace(/^http/, 'ws');
74
74
  const sessionId = await requestDatalayerCollaborationSessionId({
75
75
  url: URLExt.join(documentURL, documentId),
76
76
  token,
@@ -0,0 +1,6 @@
1
+ /**
2
+ * What an agent shows of itself.
3
+ *
4
+ * @module components/agents
5
+ */
6
+ export * from './AgentSummary';
@@ -2,4 +2,9 @@
2
2
  * Copyright (c) 2025-2026 Datalayer, Inc.
3
3
  * Distributed under the terms of the Modified BSD License.
4
4
  */
5
- export * from './StudentItemStatus';
5
+ /**
6
+ * What an agent shows of itself.
7
+ *
8
+ * @module components/agents
9
+ */
10
+ export * from './AgentSummary';
@@ -9,7 +9,7 @@ import { Box } from '@datalayer/primer-addons';
9
9
  import { ChevronDownIcon, DownloadIcon, EyeClosedIcon, EyeIcon, TrashIcon, } from '@primer/octicons-react';
10
10
  import { createMarkdownDownloadPayload, downloadTextPayload, formatDurationMs, formatRelativeTime, } from '@datalayer/core/lib/utils';
11
11
  import { Streamdown } from 'streamdown';
12
- import { streamdownMarkdownStyles } from '../chat/styles/streamdownStyles';
12
+ import { streamdownMarkdownStyles } from '../../chat/styles/streamdownStyles';
13
13
  const EVENT_KIND_VARIANT = {
14
14
  'agent-start-requested': 'attention',
15
15
  'agent-assigned': 'accent',
@@ -9,7 +9,7 @@ import { Box } from '@datalayer/primer-addons';
9
9
  import { ChevronDownIcon, DownloadIcon, EyeClosedIcon, EyeIcon, TrashIcon, } from '@primer/octicons-react';
10
10
  import { createMarkdownDownloadPayload, downloadTextPayload, formatDurationMs, formatRelativeTime, } from '@datalayer/core/lib/utils';
11
11
  import { Streamdown } from 'streamdown';
12
- import { streamdownMarkdownStyles } from '../chat/styles/streamdownStyles';
12
+ import { streamdownMarkdownStyles } from '../../chat/styles/streamdownStyles';
13
13
  export function OutputCard({ event, onToggleRead, onDelete, onOpenAgent, }) {
14
14
  const [isOutputExpanded, setIsOutputExpanded] = useState(false);
15
15
  const outputText = event.kind === 'agent-output' && event.payload?.outputs
@@ -0,0 +1,9 @@
1
+ /**
2
+ * The cards an agent run is read through: the notifications it emitted, the
3
+ * outputs it produced, and the tool calls waiting for an approval.
4
+ *
5
+ * @module components/cards
6
+ */
7
+ export * from './NotificationEventCard';
8
+ export * from './OutputCard';
9
+ export * from './ToolApprovalCard';
@@ -0,0 +1,13 @@
1
+ /*
2
+ * Copyright (c) 2025-2026 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ /**
6
+ * The cards an agent run is read through: the notifications it emitted, the
7
+ * outputs it produced, and the tool calls waiting for an approval.
8
+ *
9
+ * @module components/cards
10
+ */
11
+ export * from './NotificationEventCard';
12
+ export * from './OutputCard';
13
+ export * from './ToolApprovalCard';
@@ -1,6 +1,6 @@
1
1
  import { ITranslator } from '@jupyterlab/translation';
2
2
  /**
3
- * {@link RuntimeCellVariables} properties
3
+ * {@link CodeSandboxCellVariables} properties
4
4
  */
5
5
  interface IRuntimeCellVariablesProps {
6
6
  /**
@@ -35,5 +35,5 @@ interface IRuntimeCellVariablesProps {
35
35
  /**
36
36
  * Runtime Cell Variables Picker.
37
37
  */
38
- export declare function RuntimeCellVariables(props: IRuntimeCellVariablesProps): JSX.Element;
39
- export default RuntimeCellVariables;
38
+ export declare function CodeSandboxCellVariables(props: IRuntimeCellVariablesProps): JSX.Element;
39
+ export default CodeSandboxCellVariables;
@@ -11,7 +11,7 @@ import { Box } from '@datalayer/primer-addons';
11
11
  /**
12
12
  * Runtime Cell Variables Picker.
13
13
  */
14
- export function RuntimeCellVariables(props) {
14
+ export function CodeSandboxCellVariables(props) {
15
15
  const { getInputOptions, getOutputOptions, inputs, output, setInputs, setOutput, translator, } = props;
16
16
  const trans = useMemo(() => (translator ?? nullTranslator).load('jupyterlab'), [translator]);
17
17
  const inputForOutputRef = useRef(null);
@@ -169,4 +169,4 @@ export function RuntimeCellVariables(props) {
169
169
  .filter(item => item.selected)
170
170
  .map(item => item.id), onSelectedChange: onSelectedInputsChange, "aria-labelledby": "cell-input-variables", selectionVariant: "multiple", emptyStateText: trans.__('No available variables.'), loading: inputLoading }) })] })] }), _jsxs(FormControl, { children: [_jsx(FormControl.Label, { id: "cell-output-variables", children: trans.__('Output') }), _jsxs(Autocomplete, { children: [_jsx(Autocomplete.Input, { ref: inputForOutputRef, value: output, onChange: onOutputChange }), _jsx(Autocomplete.Overlay, { children: _jsx(Autocomplete.Menu, { items: outputsState ?? [], selectedItemIds: output ? [output] : [], "aria-labelledby": "cell-output-variables", loading: getOutputOptions && !outputsState, emptyStateText: trans.__('Not among the available variables.'), onOpenChange: handleOutputMenuOpenChange }) })] })] })] }));
171
171
  }
172
- export default RuntimeCellVariables;
172
+ export default CodeSandboxCellVariables;
@@ -2,9 +2,9 @@ import { ISessionContext } from '@jupyterlab/apputils';
2
2
  import { CodeCellModel } from '@jupyterlab/cells';
3
3
  import { ITranslator } from '@jupyterlab/translation';
4
4
  /**
5
- * {@link RuntimeCellVariablesDialog} properties
5
+ * {@link CodeSandboxCellVariablesDialog} properties
6
6
  */
7
- export interface IRuntimeCellVariablesDialogProps {
7
+ export interface ICodeSandboxCellVariablesDialogProps {
8
8
  /**
9
9
  * Code cell model
10
10
  */
@@ -33,5 +33,5 @@ export interface IRuntimeCellVariablesDialogProps {
33
33
  /**
34
34
  * Dialog to define the runtime cell variables to transfer
35
35
  */
36
- export declare function RuntimeCellVariablesDialog(props: IRuntimeCellVariablesDialogProps): JSX.Element;
37
- export default RuntimeCellVariablesDialog;
36
+ export declare function CodeSandboxCellVariablesDialog(props: ICodeSandboxCellVariablesDialogProps): JSX.Element;
37
+ export default CodeSandboxCellVariablesDialog;
@@ -9,11 +9,11 @@ import { nullTranslator } from '@jupyterlab/translation';
9
9
  import { JSONExt } from '@lumino/coreutils';
10
10
  import { KernelExecutor } from '@datalayer/jupyter-react';
11
11
  import { RuntimeSnippetsFacade } from '../../jupyter';
12
- import { RuntimeCellVariables } from './RuntimeCellVariables';
12
+ import { CodeSandboxCellVariables } from './CodeSandboxCellVariables';
13
13
  /**
14
14
  * Dialog to define the runtime cell variables to transfer
15
15
  */
16
- export function RuntimeCellVariablesDialog(props) {
16
+ export function CodeSandboxCellVariablesDialog(props) {
17
17
  const { onClose, model, preference, sessionContext, translator } = props;
18
18
  const [inputs, setInputs] = useState([]);
19
19
  const [output, setOutput] = useState();
@@ -96,6 +96,6 @@ export function RuntimeCellVariablesDialog(props) {
96
96
  onClick: setVariables,
97
97
  autoFocus: true,
98
98
  },
99
- ], children: _jsx(RuntimeCellVariables, { inputs: inputs, getInputOptions: sessionContext ? getInputCandidates : undefined, setInputs: setInputs, output: output ?? undefined, getOutputOptions: getOutputCandidates, setOutput: setOutput, translator: translator }) }));
99
+ ], children: _jsx(CodeSandboxCellVariables, { inputs: inputs, getInputOptions: sessionContext ? getInputCandidates : undefined, setInputs: setInputs, output: output ?? undefined, getOutputOptions: getOutputCandidates, setOutput: setOutput, translator: translator }) }));
100
100
  }
101
- export default RuntimeCellVariablesDialog;
101
+ export default CodeSandboxCellVariablesDialog;
@@ -2,9 +2,9 @@ import type { IMarkdownParser, IRenderMime } from '@jupyterlab/rendermime';
2
2
  import type { IRemoteServicesManager } from '../../runtimes';
3
3
  import type { ICodeSandboxSnapshot, IRuntimeDesc } from '../../models';
4
4
  /**
5
- * {@link RuntimeLauncherDialog} properties.
5
+ * {@link CodeSandboxLauncher} properties.
6
6
  */
7
- export interface IRuntimeLauncherDialogProps {
7
+ export interface ICodeSandboxLauncherProps {
8
8
  /**
9
9
  * Dialog title
10
10
  */
@@ -52,6 +52,6 @@ export interface IRuntimeLauncherDialogProps {
52
52
  submitLabel?: string;
53
53
  }
54
54
  /**
55
- * Start Runtime Launcher Dialog.
55
+ * The launcher of a new code sandbox.
56
56
  */
57
- export declare function RuntimeLauncherDialog(props: IRuntimeLauncherDialogProps): JSX.Element;
57
+ export declare function CodeSandboxLauncher(props: ICodeSandboxLauncherProps): JSX.Element;