@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
@@ -120,6 +120,63 @@ export interface ResumeRuntimeBody {
120
120
  /** Additional metadata */
121
121
  metadata?: Record<string, any>;
122
122
  }
123
+ /**
124
+ * Persisted memory record returned by ``/api/runtimes/v1/memories``.
125
+ */
126
+ export interface RuntimeMemory {
127
+ id: string;
128
+ memory?: string | null;
129
+ hash?: string | null;
130
+ user_id?: string | null;
131
+ agent_id?: string | null;
132
+ run_id?: string | null;
133
+ actor_id?: string | null;
134
+ role?: string | null;
135
+ scope?: string | null;
136
+ created_at?: string | null;
137
+ updated_at?: string | null;
138
+ metadata?: Record<string, any>;
139
+ }
140
+ /**
141
+ * Response payload for listing persisted runtime memories.
142
+ */
143
+ export interface ListRuntimeMemoriesResponse {
144
+ success: boolean;
145
+ message?: string;
146
+ count: number;
147
+ limit: number;
148
+ offset: number;
149
+ user_id?: string;
150
+ memories: RuntimeMemory[];
151
+ }
152
+ /**
153
+ * Response payload for fetching one persisted memory.
154
+ */
155
+ export interface GetRuntimeMemoryResponse {
156
+ success: boolean;
157
+ message?: string;
158
+ memory: RuntimeMemory;
159
+ }
160
+ /**
161
+ * Query options for listing persisted runtime memories.
162
+ */
163
+ export interface ListRuntimeMemoriesOptions {
164
+ userId?: string;
165
+ agentId?: string;
166
+ limit?: number;
167
+ offset?: number;
168
+ }
169
+ /**
170
+ * List persisted memories from the runtimes API.
171
+ *
172
+ * Non-admin callers are automatically scoped to their own personal account by
173
+ * the backend, even when ``userId`` is omitted.
174
+ */
175
+ export declare const listRuntimeMemories: (token: string, options?: ListRuntimeMemoriesOptions, baseUrl?: string) => Promise<ListRuntimeMemoriesResponse>;
176
+ /**
177
+ * Fetch one persisted memory by id from the runtimes API.
178
+ */
179
+ export declare const getRuntimeMemory: (token: string, memoryId: string, baseUrl?: string) => Promise<GetRuntimeMemoryResponse>;
123
180
  /**
124
181
  * Resume a paused runtime by restoring from a checkpoint (async).
125
182
  *
@@ -39,7 +39,7 @@ export const createRuntime = async (token, data, baseUrl = DEFAULT_SERVICE_URLS.
39
39
  const responseData = error.response.data || {};
40
40
  if (status === 404) {
41
41
  // Environment not found
42
- throw new Error(`Environment '${data.environment_name}' not found. ${responseData.message || 'Please check the environment name and try again.'}`);
42
+ throw new Error(`Environment '${data.environment?.name || ''}' not found. ${responseData.message || 'Please check the environment name and try again.'}`);
43
43
  }
44
44
  else if (status === 503) {
45
45
  // No runtime available
@@ -203,6 +203,60 @@ export const pauseRuntime = async (token, podName, baseUrl = DEFAULT_SERVICE_URL
203
203
  ...(body ? { body } : {}),
204
204
  });
205
205
  };
206
+ /**
207
+ * List persisted memories from the runtimes API.
208
+ *
209
+ * Non-admin callers are automatically scoped to their own personal account by
210
+ * the backend, even when ``userId`` is omitted.
211
+ */
212
+ export const listRuntimeMemories = async (token, options = {}, baseUrl = DEFAULT_SERVICE_URLS.RUNTIMES) => {
213
+ validateToken(token);
214
+ const query = new URLSearchParams();
215
+ if (options.userId?.trim()) {
216
+ query.set('user_id', options.userId.trim());
217
+ }
218
+ if (options.agentId?.trim()) {
219
+ query.set('agent_id', options.agentId.trim());
220
+ }
221
+ if (typeof options.limit === 'number' && Number.isFinite(options.limit)) {
222
+ query.set('limit', String(Math.max(1, Math.min(1000, Math.floor(options.limit)))));
223
+ }
224
+ if (typeof options.offset === 'number' && Number.isFinite(options.offset)) {
225
+ query.set('offset', String(Math.max(0, Math.floor(options.offset))));
226
+ }
227
+ const qs = query.toString();
228
+ const response = await requestDatalayerAPI({
229
+ url: `${baseUrl}${API_BASE_PATHS.RUNTIMES}/memories${qs ? `?${qs}` : ''}`,
230
+ method: 'GET',
231
+ token,
232
+ });
233
+ return {
234
+ success: Boolean(response?.success),
235
+ message: response?.message,
236
+ count: Number(response?.count ?? 0),
237
+ limit: Number(response?.limit ?? options.limit ?? 100),
238
+ offset: Number(response?.offset ?? options.offset ?? 0),
239
+ user_id: response?.user_id,
240
+ memories: Array.isArray(response?.memories) ? response.memories : [],
241
+ };
242
+ };
243
+ /**
244
+ * Fetch one persisted memory by id from the runtimes API.
245
+ */
246
+ export const getRuntimeMemory = async (token, memoryId, baseUrl = DEFAULT_SERVICE_URLS.RUNTIMES) => {
247
+ validateToken(token);
248
+ validateRequiredString(memoryId, 'Memory id');
249
+ const response = await requestDatalayerAPI({
250
+ url: `${baseUrl}${API_BASE_PATHS.RUNTIMES}/memories/${encodeURIComponent(memoryId)}`,
251
+ method: 'GET',
252
+ token,
253
+ });
254
+ return {
255
+ success: Boolean(response?.success),
256
+ message: response?.message,
257
+ memory: response?.memory,
258
+ };
259
+ };
206
260
  /**
207
261
  * Resume a paused runtime by restoring from a checkpoint (async).
208
262
  *
@@ -10,6 +10,19 @@ export interface ChatProps extends ChatCommonProps {
10
10
  extensions?: Extension[];
11
11
  /** Base URL of the server (for HTTP-based protocols) */
12
12
  baseUrl?: string;
13
+ /**
14
+ * Explicit endpoint URL override. When set, it is used verbatim instead of
15
+ * deriving `${baseUrl}${getEndpointPath(protocol, agentId)}`. Useful for
16
+ * proxied endpoints such as the Agent Node tunnel proxy.
17
+ */
18
+ endpoint?: string;
19
+ /**
20
+ * Explicit config endpoint override. When provided (including `null`/empty
21
+ * to disable), it replaces the default `${baseUrl}/api/v1/configure`.
22
+ */
23
+ configEndpoint?: string;
24
+ /** Override whether the protocol queries the backend for models/tools. */
25
+ enableConfigQuery?: boolean;
13
26
  /** WebSocket URL (for WebSocket-based protocols like ACP) */
14
27
  wsUrl?: string;
15
28
  /** Agent ID */
@@ -94,5 +107,5 @@ export interface ChatProps extends ChatCommonProps {
94
107
  * />
95
108
  * ```
96
109
  */
97
- export declare function Chat({ protocol: transport, extensions: _extensions, baseUrl, 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, onToolCallStart, onToolCallComplete, renderToolResult, hideMessagesAfterToolUI, contextSnapshot, mcpStatusData, codemodeStatusData, sandboxStatusData, kernel, 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, 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;
98
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', 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, onToolCallStart, onToolCallComplete, renderToolResult, hideMessagesAfterToolUI = false, contextSnapshot, mcpStatusData, codemodeStatusData, sandboxStatusData, kernel, 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, 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';
@@ -220,6 +220,10 @@ export function Chat({ protocol: transport, extensions: _extensions, baseUrl = '
220
220
  break;
221
221
  }
222
222
  }
223
+ // Explicit endpoint override (e.g. Agent Node tunnel proxy).
224
+ if (endpointProp) {
225
+ endpoint = endpointProp;
226
+ }
223
227
  return {
224
228
  config: {
225
229
  type: getProtocolType(transport),
@@ -228,12 +232,14 @@ export function Chat({ protocol: transport, extensions: _extensions, baseUrl = '
228
232
  authToken,
229
233
  options,
230
234
  // Enable config query for all protocols to fetch models and tools
231
- enableConfigQuery: true,
235
+ enableConfigQuery: enableConfigQueryProp ?? true,
232
236
  // For Jupyter-based transports, use Jupyter requestAPI (configEndpoint undefined)
233
237
  // For FastAPI-based transports, use direct fetch to the configure endpoint
234
- configEndpoint: transport === 'vercel-ai-jupyter'
235
- ? undefined // Use Jupyter requestAPI
236
- : `${baseUrl}/api/v1/configure`,
238
+ configEndpoint: configEndpointProp !== undefined
239
+ ? configEndpointProp
240
+ : transport === 'vercel-ai-jupyter'
241
+ ? undefined // Use Jupyter requestAPI
242
+ : `${baseUrl}/api/v1/configure`,
237
243
  },
238
244
  error: null,
239
245
  };
@@ -245,7 +251,16 @@ export function Chat({ protocol: transport, extensions: _extensions, baseUrl = '
245
251
  error: err instanceof Error ? err.message : 'Failed to configure',
246
252
  };
247
253
  }
248
- }, [transport, baseUrl, wsUrl, resolvedAgentId, authTokenProp]);
254
+ }, [
255
+ transport,
256
+ baseUrl,
257
+ wsUrl,
258
+ resolvedAgentId,
259
+ authTokenProp,
260
+ endpointProp,
261
+ configEndpointProp,
262
+ enableConfigQueryProp,
263
+ ]);
249
264
  const protocolConfig = protocolConfigResult.config;
250
265
  // Set initialized once protocol config is built
251
266
  useEffect(() => {
@@ -349,6 +364,6 @@ export function Chat({ protocol: transport, extensions: _extensions, baseUrl = '
349
364
  ? 'attention.fg'
350
365
  : 'danger.fg',
351
366
  flex: 1,
352
- }, 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, onToolCallStart: onToolCallStart, onToolCallComplete: onToolCallComplete, renderToolResult: renderToolResult, hideMessagesAfterToolUI: hideMessagesAfterToolUI, contextSnapshot: contextSnapshot, mcpStatusData: mcpStatusData, sandboxStatusData: sandboxStatusData, kernel: kernel, 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, 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 })] })] }) }) }));
353
368
  }
354
369
  export default Chat;
@@ -17,11 +17,11 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
17
17
  */
18
18
  import { useContext } from 'react';
19
19
  import React, { useCallback, useEffect, useMemo, useRef, useState, } from 'react';
20
- import { Text, Spinner, IconButton } from '@primer/react';
20
+ import { Box, Text, Spinner, IconButton } from '@primer/react';
21
21
  import { SkeletonText } from '@primer/react/experimental';
22
22
  import { SidebarExpandIcon } from '@primer/octicons-react';
23
23
  import { notebookStore, JupyterReactTheme } from '@datalayer/jupyter-react';
24
- import { Box, setupPrimerPortals, useThemeStore, getColorPalette, getThemeConfig, useSystemColorMode, } from '@datalayer/primer-addons';
24
+ import { setupPrimerPortals, useThemeStore, getColorPalette, getThemeConfig, useSystemColorMode, } from '@datalayer/primer-addons';
25
25
  import { AlertIcon, PersonIcon } from '@primer/octicons-react';
26
26
  import { AiAgentIcon } from '@datalayer/icons-react';
27
27
  import { QueryClientProvider, QueryClientContext } from '@tanstack/react-query';
@@ -112,12 +112,14 @@ const ThemedJupyterReactTheme = JupyterReactTheme;
112
112
  * chat height/flex chain is preserved); CSS custom properties and inherited
113
113
  * properties (color, font) still cascade through it.
114
114
  */
115
- function ThemedChatBoundary({ children }) {
116
- const colorMode = useThemeStore(s => s.colorMode);
117
- const themeVariant = useThemeStore(s => s.theme);
115
+ function ThemedChatBoundary({ children, themeVariant, colorMode, }) {
116
+ const storeColorMode = useThemeStore(s => s.colorMode);
117
+ const storeThemeVariant = useThemeStore(s => s.theme);
118
+ const resolvedColorMode = colorMode ?? storeColorMode;
119
+ const resolvedThemeVariant = themeVariant ?? storeThemeVariant;
118
120
  const systemMode = useSystemColorMode();
119
- const themeConfig = getThemeConfig(themeVariant);
120
- const resolvedMode = colorMode === 'auto' ? systemMode : colorMode;
121
+ const themeConfig = getThemeConfig(resolvedThemeVariant);
122
+ const resolvedMode = resolvedColorMode === 'auto' ? systemMode : resolvedColorMode;
121
123
  const modeStyles = resolvedMode === 'dark'
122
124
  ? themeConfig.themeStyles.dark
123
125
  : themeConfig.themeStyles.light;
@@ -432,7 +434,7 @@ function parseApprovedMcpToolsByServer(mcpStatusData) {
432
434
  * ChatBase component — Universal chat panel supporting store, protocol, and custom modes.
433
435
  */
434
436
  export function ChatBase(props) {
435
- const { agentRuntimeConfig, protocol: protocolProp, useStore: useStoreMode = true, disableInternalJupyterTheme = false, } = props;
437
+ const { agentRuntimeConfig, protocol: protocolProp, useStore: useStoreMode = true, disableInternalJupyterTheme = false, themeVariant, colorMode, } = props;
436
438
  // Resolve protocol: string Protocol overrides type in agentRuntimeConfig or
437
439
  // is combined with a full ProtocolConfig object.
438
440
  const protocolType = typeof protocolProp === 'string' ? protocolProp : undefined;
@@ -459,7 +461,7 @@ export function ChatBase(props) {
459
461
  useStore: effectiveUseStoreMode,
460
462
  };
461
463
  const content = _jsx(ChatBaseInner, { ...innerProps });
462
- const wrappedContent = disableInternalJupyterTheme ? (content) : (_jsx(ThemedChatBoundary, { children: content }));
464
+ const wrappedContent = disableInternalJupyterTheme ? (content) : (_jsx(ThemedChatBoundary, { themeVariant: themeVariant, colorMode: colorMode, children: content }));
463
465
  if (!existingQueryClient) {
464
466
  return (_jsx(QueryClientProvider, { client: internalQueryClient, children: wrappedContent }));
465
467
  }
@@ -468,11 +470,11 @@ export function ChatBase(props) {
468
470
  // ---------------------------------------------------------------------------
469
471
  // ChatBaseInner — contains all actual logic
470
472
  // ---------------------------------------------------------------------------
471
- function ChatBaseInner({ title, subtitle, showHeader = false, showTokenUsage = true, showLoadingIndicator = true, showErrors = true, showInput = true, showModelSelector = true, showToolsMenu = true, showSkillsMenu = true, disableInputPrompt = false, overlay, launching = false, launchingMessage, autoConnect = true, codemodeEnabled = false, onToggleCodemode, initialModel, availableModels, mcpServers, initialSkills: _initialSkills, className, loadingState, headerActions, kernelIndicatorState, kernel, kernelEnvironmentName, kernelCpu, kernelMemory, kernelGpu, chatViewMode, onChatViewModeChange,
473
+ function ChatBaseInner({ title, subtitle, showHeader = false, showTokenUsage = true, showLoadingIndicator = true, showErrors = true, showInput = true, showModelSelector = true, showToolsMenu = true, showSkillsMenu = true, disableInputPrompt = false, overlay, launching = false, launchingMessage, autoConnect = true, codemodeEnabled = false, onToggleCodemode, initialModel, availableModels, mcpServers, initialSkills: _initialSkills, className, loadingState, headerActions, kernelIndicatorState, kernelIndicatorPlacement = 'left', kernel, kernelEnvironmentName, kernelCpu, kernelMemory, kernelGpu, themeVariant, colorMode, chatViewMode, onChatViewModeChange,
472
474
  // Mode selection
473
475
  useStore: useStoreMode = true, protocol: protocolRaw, onSendMessage, enableStreaming = false,
474
476
  // Extended props
475
- 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,
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,
476
478
  // Tool invocation hooks
477
479
  onToolCallStart, onToolCallComplete,
478
480
  // Identity/Authorization props
@@ -510,9 +512,15 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
510
512
  // agent id. This keeps the persisted notebook model addressable by the same
511
513
  // key when navigating away from and back to the same runtime page.
512
514
  const notebookScopeId = runtimeId || protocolConfig?.agentId || activeAgentId;
513
- const ephemeralNotebookId = notebookScopeId
514
- ? `ephemeral-notebook-${notebookScopeId}`
515
- : generatedNotebookIdRef.current;
515
+ // When an explicit collaboration document id is supplied (e.g. an Agent Node
516
+ // sharing a room with the SaaS UI), it becomes the notebook id directly so
517
+ // BOTH peers join the same collaborative room AND the agent's notebook tools
518
+ // (scoped by this same id) drive the shared notebook. Otherwise fall back to
519
+ // the derived, per-runtime in-memory id.
520
+ const ephemeralNotebookId = ephemeralNotebookCollaborationDocumentId ||
521
+ (notebookScopeId
522
+ ? `ephemeral-notebook-${notebookScopeId}`
523
+ : generatedNotebookIdRef.current);
516
524
  const persistedEphemeralNbformat = useAgentRuntimeStore(s => s.getEphemeralNotebookModel(ephemeralNotebookId));
517
525
  const setEphemeralNotebookModel = useAgentRuntimeStore(s => s.setEphemeralNotebookModel);
518
526
  const handleEphemeralNotebookChange = useCallback((model) => {
@@ -520,10 +528,14 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
520
528
  }, [ephemeralNotebookId, setEphemeralNotebookModel]);
521
529
  // ── Ephemeral document (in-memory Lexical) ──────────────────────────────
522
530
  // Scoped to the same stable runtime identity as the notebook so the persisted
523
- // document survives navigation away from and back to the runtime page.
524
- const ephemeralDocumentId = notebookScopeId
525
- ? `ephemeral-document-${notebookScopeId}`
526
- : `ephemeral-document-${generatedNotebookIdRef.current}`;
531
+ // document survives navigation away from and back to the runtime page. When a
532
+ // collaboration room is supplied it becomes the document id directly so BOTH
533
+ // peers join the same Loro room AND the agent's lexical tools (scoped by this
534
+ // same id) drive the shared document.
535
+ const ephemeralDocumentId = ephemeralDocumentCollaboration?.roomId ||
536
+ (notebookScopeId
537
+ ? `ephemeral-document-${notebookScopeId}`
538
+ : `ephemeral-document-${generatedNotebookIdRef.current}`);
527
539
  const persistedEphemeralDocument = useAgentRuntimeStore(s => s.getEphemeralDocumentModel(ephemeralDocumentId));
528
540
  const setEphemeralDocumentModel = useAgentRuntimeStore(s => s.setEphemeralDocumentModel);
529
541
  const handleEphemeralDocumentChange = useCallback((model) => {
@@ -576,6 +588,18 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
576
588
  unsubscribe();
577
589
  };
578
590
  }, [notebookVisible, ephemeralNotebookId]);
591
+ // Track the ephemeral document's live kernel connection the same way, so the
592
+ // header's kernel indicator reflects the real connected kernel while the
593
+ // document surface is active (instead of the "disconnected" placeholder).
594
+ const [documentKernel, setDocumentKernel] = useState(null);
595
+ const handleDocumentKernelChange = useCallback((next) => {
596
+ setDocumentKernel(prev => (prev?.id === next?.id ? prev : next));
597
+ }, []);
598
+ useEffect(() => {
599
+ if (!documentVisible) {
600
+ setDocumentKernel(null);
601
+ }
602
+ }, [documentVisible]);
579
603
  // When a companion surface is shown, the chat can be docked as a sidebar
580
604
  // (default) or floated over it, driven by the header view-mode toggle.
581
605
  const surfaceChatFloating = surfaceVisible &&
@@ -861,6 +885,10 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
861
885
  requestAiAgentsApprovalHistory,
862
886
  sendAiAgentsApprovalDecision,
863
887
  ]);
888
+ // Assigned once `applyServerApprovalDecision` is defined below. A ref lets the
889
+ // ai-agents approval WS effect (declared earlier) drive the deferred-run
890
+ // continuation without re-subscribing when the callback identity changes.
891
+ const applyServerApprovalDecisionRef = useRef(null);
864
892
  const reconcileResolvedApprovalInStore = useCallback((approval) => {
865
893
  const state = agentRuntimeStore.getState();
866
894
  const removalIds = new Set([approval.id]);
@@ -966,7 +994,24 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
966
994
  }
967
995
  const state = agentRuntimeStore.getState();
968
996
  for (const record of records) {
969
- const approval = normalizeApprovalPayload(record);
997
+ let approval = normalizeApprovalPayload(record);
998
+ // SaaS-resolved events (tool_approval_approved/rejected) can arrive
999
+ // with only {approvalId, status} and no tool_name/tool_args. Recover
1000
+ // the full envelope from the store (populated by the earlier pending
1001
+ // event) so the card clears AND the deferred run can resume.
1002
+ if (!approval) {
1003
+ const rawId = (typeof record.id === 'string' && record.id) ||
1004
+ (typeof record.approval_id === 'string' && record.approval_id) ||
1005
+ (typeof record.approvalId === 'string' && record.approvalId) ||
1006
+ '';
1007
+ const rawStatus = (typeof record.status === 'string' && record.status) || '';
1008
+ if (rawId && rawStatus && rawStatus !== 'pending') {
1009
+ const stored = state.approvals.find(a => a.id === rawId);
1010
+ if (stored) {
1011
+ approval = { ...stored, status: rawStatus };
1012
+ }
1013
+ }
1014
+ }
970
1015
  if (!approval) {
971
1016
  continue;
972
1017
  }
@@ -996,6 +1041,11 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
996
1041
  }
997
1042
  else {
998
1043
  reconcileResolvedApprovalInStore(scopedApproval);
1044
+ // Resume the deferred tool call when the decision was made on
1045
+ // another surface (e.g. the SaaS Tool Approvals UI). Without this
1046
+ // the pending card clears but pydantic-ai never receives the
1047
+ // client continuation and the run stays parked.
1048
+ applyServerApprovalDecisionRef.current?.(scopedApproval, scopedApproval.status === 'approved', scopedApproval.note ?? undefined);
999
1049
  }
1000
1050
  }
1001
1051
  }
@@ -1237,13 +1287,16 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
1237
1287
  });
1238
1288
  return true;
1239
1289
  }, [activeAgentId]);
1290
+ applyServerApprovalDecisionRef.current = applyServerApprovalDecision;
1240
1291
  // ---- Agent-runtime WebSocket (monitoring stream) ----
1241
1292
  // Derive the bare base URL from configEndpoint or protocol.endpoint.
1293
+ const isAgentNodeTunnelAgUi = Boolean(protocol?.endpoint &&
1294
+ /\/api\/runtimes\/v1\/agent-nodes\/[^/]+\/ag-ui\/?$/.test(protocol.endpoint));
1242
1295
  const wsBaseUrl = protocol?.configEndpoint
1243
1296
  ? protocol.configEndpoint.replace(/\/api\/v1\/(config|configure)\/?$/, '')
1244
1297
  : (protocol?.endpoint?.replace(/\/api\/v1\/.*$/, '') ?? '');
1245
1298
  useAgentRuntimeWebSocket({
1246
- enabled: !!protocol && !!wsBaseUrl,
1299
+ enabled: !!protocol && !!wsBaseUrl && !isAgentNodeTunnelAgUi,
1247
1300
  baseUrl: wsBaseUrl,
1248
1301
  authToken: protocol?.authToken,
1249
1302
  agentId: protocol?.agentId,
@@ -2418,7 +2471,11 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
2418
2471
  pendingPromptSentRef.current = pendingPromptKey;
2419
2472
  return;
2420
2473
  }
2421
- if (!historyLoaded)
2474
+ // Do not block prompt replay forever when runtime history cannot be fetched
2475
+ // (e.g. websocket not connected yet/anymore). In that case we fall back to
2476
+ // submitting once the adapter is ready.
2477
+ const canProceedWithoutHistory = !historyScopeId || wsState !== 'connected';
2478
+ if (!historyLoaded && !canProceedWithoutHistory)
2422
2479
  return;
2423
2480
  if (!adapterReady && !onSendMessage)
2424
2481
  return;
@@ -2431,6 +2488,8 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
2431
2488
  pendingPrompt,
2432
2489
  pendingPromptKey,
2433
2490
  historyLoaded,
2491
+ historyScopeId,
2492
+ wsState,
2434
2493
  adapterReady,
2435
2494
  handleSend,
2436
2495
  onSendMessage,
@@ -2827,7 +2886,11 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
2827
2886
  // no ephemeral notebook is shown) or INSIDE the chat body column (when the
2828
2887
  // notebook is visible) so the header always follows the chat body across all
2829
2888
  // view modes (docked sidebar, floating popup, floating-small).
2830
- const chatHeaderElement = showHeader ? (_jsx(ChatBaseHeader, { title: title, subtitle: subtitle, brandIcon: brandIcon, headerContent: headerContent, headerActions: headerActions, showInformation: showInformation, onInformationClick: onInformationClick, padding: padding, kernelIndicatorState: kernelIndicatorState, runtimeStatus: sandboxStatusData ?? sandboxStatusQuery.data, kernel: notebookVisible ? (notebookKernel ?? kernel) : kernel, kernelEnvironmentName: kernelEnvironmentName, kernelCpu: kernelCpu, kernelMemory: kernelMemory, kernelGpu: kernelGpu, headerButtons: headerButtons, messageCount: messages.length, onNewChat: handleNewChat, onClear: handleClear, chatViewMode: chatViewMode, onChatViewModeChange: onChatViewModeChange, showEphemeralSurfaceControl: enableEphemeralNotebook || enableEphemeralDocument, enableEphemeralNotebookOption: enableEphemeralNotebook, enableEphemeralDocumentOption: enableEphemeralDocument, ephemeralSurfaceMode: ephemeralSurfaceMode, onEphemeralSurfaceModeChange: handleEphemeralSurfaceModeChange })) : null;
2889
+ const chatHeaderElement = showHeader ? (_jsx(ChatBaseHeader, { title: title, subtitle: subtitle, brandIcon: brandIcon, headerContent: headerContent, headerActions: headerActions, showInformation: showInformation, onInformationClick: onInformationClick, padding: padding, kernelIndicatorState: kernelIndicatorState, kernelIndicatorPlacement: kernelIndicatorPlacement, runtimeStatus: sandboxStatusData ?? sandboxStatusQuery.data, kernel: notebookVisible
2890
+ ? (notebookKernel ?? kernel)
2891
+ : documentVisible
2892
+ ? (documentKernel ?? kernel)
2893
+ : kernel, kernelEnvironmentName: kernelEnvironmentName, kernelCpu: kernelCpu, kernelMemory: kernelMemory, kernelGpu: kernelGpu, headerButtons: headerButtons, messageCount: messages.length, onNewChat: handleNewChat, onClear: handleClear, chatViewMode: chatViewMode, onChatViewModeChange: onChatViewModeChange, showEphemeralSurfaceControl: enableEphemeralNotebook || enableEphemeralDocument, enableEphemeralNotebookOption: enableEphemeralNotebook, enableEphemeralDocumentOption: enableEphemeralDocument, ephemeralSurfaceMode: ephemeralSurfaceMode, onEphemeralSurfaceModeChange: handleEphemeralSurfaceModeChange })) : null;
2831
2894
  // ========================================================================
2832
2895
  // Render
2833
2896
  // ========================================================================
@@ -2874,7 +2937,7 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
2874
2937
  borderRight: '1px solid',
2875
2938
  borderColor: 'border.default',
2876
2939
  }),
2877
- }, children: launching || overlay ? (_jsx(CompanionSurfaceSkeleton, { mode: notebookVisible ? 'notebook' : 'document' })) : notebookVisible ? (_jsx(EphemeralNotebook, { notebookId: ephemeralNotebookId, runtimePodName: runtimeId || activeAgentId, nbformat: persistedEphemeralNbformat ?? undefined, onNbformatChange: handleEphemeralNotebookChange, toolbarComponent: ephemeralNotebookToolbar })) : (_jsx(React.Suspense, { fallback: null, children: _jsx(EphemeralDocument, { documentId: ephemeralDocumentId, runtimePodName: runtimeId || activeAgentId, content: persistedEphemeralDocument ?? undefined, onContentChange: handleEphemeralDocumentChange, onToolsReady: handleDocumentToolsReady }) })) }), !surfaceCollapsed && (_jsxs(Box, { sx: surfaceChatFloating
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
2878
2941
  ? {
2879
2942
  position: 'absolute',
2880
2943
  right: 16,
@@ -1,6 +1,35 @@
1
+ import type { IKernelConnection } from '@jupyterlab/services/lib/kernel/kernel';
1
2
  import type { FrontendToolDefinition } from '../../types/tools';
3
+ import type { EphemeralRuntimeOverride } from '../notebook/EphemeralNotebook';
2
4
  import '@datalayer/jupyter-react/lib/css/PrismCss';
3
5
  import '@datalayer/jupyter-lexical/style/index.css';
6
+ /**
7
+ * Real-time collaboration configuration for the ephemeral document.
8
+ *
9
+ * When supplied, the Lexical editor state is backed by a shared Loro CRDT
10
+ * document synchronised over a WebSocket (the spacer lexical endpoint) instead
11
+ * of the in-memory / persisted local state. Every peer that joins the same
12
+ * `roomId` edits the same document — this is how an Agent Node and the SaaS UI
13
+ * share a live document. The caller owns the room/identity lifecycle.
14
+ */
15
+ export interface EphemeralDocumentCollaboration {
16
+ /**
17
+ * WebSocket URL of the Loro collaboration server, e.g.
18
+ * `wss://…/api/spacer/v1/lexical/ws`.
19
+ */
20
+ websocketUrl: string;
21
+ /** Shared collaboration room / document id joined by all peers. */
22
+ roomId: string;
23
+ /** Optional identity used for collaborative presence (cursors / awareness). */
24
+ identity?: {
25
+ userId?: string;
26
+ handle?: string;
27
+ displayName?: string;
28
+ initials?: string;
29
+ avatarUrl?: string;
30
+ color?: string;
31
+ };
32
+ }
4
33
  export interface EphemeralDocumentProps {
5
34
  /**
6
35
  * Document identifier. Must match the id passed to `useLexicalTools` so the
@@ -9,15 +38,34 @@ export interface EphemeralDocumentProps {
9
38
  documentId: string;
10
39
  /** Preferred runtime pod name to bind the document kernel to. */
11
40
  runtimePodName?: string;
41
+ /** Optional explicit runtime endpoint (agent-node tunnel proxy path). */
42
+ runtimeOverride?: EphemeralRuntimeOverride;
43
+ /** Optional theme variant override from host chat context. */
44
+ themeVariant?: string;
45
+ /** Optional color mode override from host chat context. */
46
+ colorMode?: 'light' | 'dark' | 'auto';
12
47
  /** Optional persisted Lexical editor state (JSON string) to restore. */
13
48
  content?: string;
14
49
  /** Callback fired when the document's editor state changes. */
15
50
  onContentChange?: (content: string) => void;
16
51
  /** Reports the lexical frontend tools so the parent can pass them to the agent. */
17
52
  onToolsReady?: (tools: FrontendToolDefinition[]) => void;
53
+ /**
54
+ * Reports the document's live sandbox kernel connection upward so the chat
55
+ * header can render the same rich kernel indicator (kernel id, client id,
56
+ * status) as the notebook surface. Emits `null` while the kernel is absent.
57
+ */
58
+ onKernelChange?: (kernel: IKernelConnection | null) => void;
59
+ /**
60
+ * Optional real-time collaboration configuration. When supplied the document
61
+ * joins a shared Loro room over WebSocket so its state transits over RTC
62
+ * (e.g. between an Agent Node and the SaaS UI) rather than living purely in
63
+ * local memory.
64
+ */
65
+ collaboration?: EphemeralDocumentCollaboration;
18
66
  }
19
67
  /**
20
68
  * Renders an in-memory Lexical document backed by a sandbox kernel.
21
69
  */
22
- export declare function EphemeralDocument({ documentId, runtimePodName, content, onContentChange, onToolsReady, }: EphemeralDocumentProps): import("react/jsx-runtime").JSX.Element;
70
+ export declare function EphemeralDocument({ documentId, runtimePodName, runtimeOverride, themeVariant, colorMode, content, onContentChange, onToolsReady, onKernelChange, collaboration, }: EphemeralDocumentProps): import("react/jsx-runtime").JSX.Element;
23
71
  export default EphemeralDocument;