@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.
- package/README.md +14 -6
- package/lib/AgentNode.js +567 -67
- package/lib/App.js +2 -2
- package/lib/agent-node/AgentNodeGallery.d.ts +80 -0
- package/lib/agent-node/AgentNodeGallery.js +627 -0
- package/lib/agent-notebook-main.js +0 -1
- package/lib/api/runtimes/runtimes.d.ts +57 -0
- package/lib/api/runtimes/runtimes.js +55 -1
- package/lib/chat/Chat.d.ts +14 -1
- package/lib/chat/Chat.js +22 -7
- package/lib/chat/base/ChatBase.js +86 -23
- package/lib/chat/document/EphemeralDocument.d.ts +49 -1
- package/lib/chat/document/EphemeralDocument.js +141 -15
- package/lib/chat/header/ChatHeaderBase.d.ts +3 -1
- package/lib/chat/header/ChatHeaderBase.js +5 -3
- package/lib/chat/messages/ChatMessageList.d.ts +19 -0
- package/lib/chat/messages/ChatMessageList.js +180 -9
- package/lib/chat/notebook/EphemeralNotebook.d.ts +40 -1
- package/lib/chat/notebook/EphemeralNotebook.js +49 -13
- package/lib/chat/prompt/InputPrompt.js +1 -1
- package/lib/chat/tools/SubagentActivity.d.ts +20 -0
- package/lib/chat/tools/SubagentActivity.js +154 -0
- package/lib/chat/tools/index.d.ts +1 -0
- package/lib/chat/tools/index.js +1 -0
- package/lib/chat/usage/TokenUsageBar.js +3 -3
- package/lib/client/AgentRuntimesClient.d.ts +5 -0
- package/lib/client/AgentsMixin.js +3 -1
- package/lib/client/mixins/RuntimesMixin.d.ts +12 -0
- package/lib/client/mixins/RuntimesMixin.js +24 -1
- package/lib/components/AgentSummary.d.ts +1 -0
- package/lib/components/AgentSummary.js +66 -10
- package/lib/components/runtimes/RuntimePickerBase.js +64 -29
- package/lib/components/runtimes/RuntimePickerCell.js +1 -1
- package/lib/components/runtimes/RuntimePickerNotebook.js +1 -1
- package/lib/components/runtimes/RuntimeSimplePicker.js +3 -2
- package/lib/components/runtimes/RuntimeUtils.js +2 -2
- package/lib/context/GraphFlowChart.js +1 -1
- package/lib/context/TokenUsageChart.js +1 -1
- package/lib/context/TurnGraphChart.js +2 -2
- package/lib/examples/A2UiAgentExample.js +4 -4
- package/lib/examples/A2UiComponentsGalleryExample.js +3 -3
- package/lib/examples/A2UiContactCardExample.js +3 -3
- package/lib/examples/A2UiRestaurantExample.js +2 -2
- package/lib/examples/A2UiViewerExample.js +3 -3
- package/lib/examples/AgUiAgenticExample.js +3 -3
- package/lib/examples/AgUiBackendToolRenderingExample.js +2 -2
- package/lib/examples/AgUiHaikuGenUiExample.js +3 -3
- package/lib/examples/AgUiHumanInTheLoopExample.js +5 -5
- package/lib/examples/AgUiSharedStateExample.js +3 -3
- package/lib/examples/AgUiToolsBasedGenUiExample.js +7 -5
- package/lib/examples/AgentCheckpointsExample.js +6 -5
- package/lib/examples/{AgentSandboxExample.d.ts → AgentCodeSandboxExample.d.ts} +4 -4
- package/lib/examples/{AgentSandboxExample.js → AgentCodeSandboxExample.js} +10 -9
- package/lib/examples/AgentCodeSandboxesExample.js +2 -2
- package/lib/examples/AgentCodemodeExample.js +3 -3
- package/lib/examples/AgentCompactionExample.d.ts +12 -0
- package/lib/examples/AgentCompactionExample.js +244 -0
- package/lib/examples/AgentEvalsExample.js +10 -20
- package/lib/examples/AgentGuardrailsExample.js +2 -2
- package/lib/examples/AgentHooksExample.js +1 -1
- package/lib/examples/AgentInferenceProviderExample.js +6 -8
- package/lib/examples/AgentLoopExample.js +3 -3
- package/lib/examples/AgentMCPExample.js +3 -3
- package/lib/examples/AgentMemoryExample.d.ts +4 -2
- package/lib/examples/AgentMemoryExample.js +93 -10
- package/lib/examples/AgentMonitoringExample.js +2 -2
- package/lib/examples/AgentNotificationsExample.js +1 -1
- package/lib/examples/AgentOtelExample.d.ts +2 -3
- package/lib/examples/AgentOtelExample.js +7 -12
- package/lib/examples/AgentOutputsExample.js +5 -5
- package/lib/examples/AgentParametersExample.js +3 -3
- package/lib/examples/AgentSkillsExample.js +4 -4
- package/lib/examples/AgentSubagentsExample.d.ts +2 -2
- package/lib/examples/AgentSubagentsExample.js +43 -34
- package/lib/examples/AgentToolApprovalsExample.js +1 -1
- package/lib/examples/AgentTriggersExample.js +9 -11
- package/lib/examples/AgentspecsExample.js +13 -5
- package/lib/examples/CellExample.d.ts +6 -0
- package/lib/examples/CellExample.js +84 -0
- package/lib/examples/ChatCustomExample.js +1 -1
- package/lib/examples/ChatExample.js +1 -1
- package/lib/examples/ChatStandaloneExample.js +2 -2
- package/lib/examples/HomeExample.js +29 -28
- package/lib/examples/Lexical2Example.js +2 -2
- package/lib/examples/LexicalAgentExample.js +1 -1
- package/lib/examples/LexicalAgentSidebarExample.js +2 -2
- package/lib/examples/NotebookAgentSidebarExample.d.ts +1 -1
- package/lib/examples/NotebookAgentSidebarExample.js +5 -4
- package/lib/examples/NotebookCollaborationExample.js +3 -3
- package/lib/examples/NotebookExample.js +2 -2
- package/lib/examples/components/ExampleWrapper.js +5 -0
- package/lib/examples/components/Header.js +2 -2
- package/lib/examples/components/HeaderControls.js +1 -1
- package/lib/examples/components/LexicalEditor.js +1 -1
- package/lib/examples/components/MainContent.js +1 -1
- package/lib/examples/components/MockFileBrowser.js +8 -8
- package/lib/examples/components/TimeTravel.js +1 -1
- package/lib/examples/components/haiku/HaikuDisplay.js +2 -2
- package/lib/examples/example-selector.js +4 -3
- package/lib/examples/hooks/useExampleAgentRuntime.js +11 -1
- package/lib/examples/hooks/useExampleAgentRuntimes.d.ts +7 -0
- package/lib/examples/hooks/useExampleAgentRuntimes.js +82 -0
- package/lib/examples/index.d.ts +2 -1
- package/lib/examples/index.js +2 -1
- package/lib/examples/main.js +359 -46
- package/lib/examples/utils/agentSummaryStore.d.ts +17 -0
- package/lib/examples/utils/themedProvider.js +32 -2
- package/lib/examples/utils/useExampleAgentRuntimesUrl.js +2 -1
- package/lib/examples2/NotebookMutationsKernel.js +6 -3
- package/lib/examples2/NotebookMutationsServiceManager.js +6 -3
- package/lib/examples2/ReactRouterExample.js +5 -5
- package/lib/examples2/main.js +38 -0
- package/lib/hooks/useAIAgentsWebSocket.js +35 -0
- package/lib/hooks/useAgentRuntimes.d.ts +22 -0
- package/lib/hooks/useAgentRuntimes.js +192 -5
- package/lib/hooks/useCheckpoints.js +2 -2
- package/lib/hooks/useToolApprovals.d.ts +10 -4
- package/lib/hooks/useToolApprovals.js +11 -5
- package/lib/identity/AgentIdentity.js +1 -2
- package/lib/models/Runtime.d.ts +10 -8
- package/lib/models/RuntimeDTO.d.ts +5 -3
- package/lib/models/RuntimeDTO.js +3 -3
- package/lib/runtimes/actions.js +3 -1
- package/lib/runtimes/apis.d.ts +7 -0
- package/lib/shims/primerAddonsBox.d.ts +1 -0
- package/lib/shims/primerAddonsBox.js +7 -0
- package/lib/specs/agents/agents.d.ts +51 -0
- package/lib/specs/agents/agents.js +3389 -94
- package/lib/specs/models.d.ts +2 -0
- package/lib/specs/models.js +37 -0
- package/lib/stores/agentRuntimeStore.d.ts +32 -1
- package/lib/stores/agentRuntimeStore.js +65 -1
- package/lib/stores/index.d.ts +1 -1
- package/lib/stores/index.js +1 -1
- package/lib/types/agents.d.ts +9 -3
- package/lib/types/agentspecs.d.ts +2 -0
- package/lib/types/chat.d.ts +83 -0
- package/lib/types/models.d.ts +5 -0
- package/lib/types/stream.d.ts +58 -1
- package/package.json +6 -5
- package/scripts/codegen/generate_agents.py +7 -0
- package/scripts/codegen/generate_models.py +22 -9
- package/scripts/gen_workers.py +340 -0
- package/lib/examples/CellSimpleExample.d.ts +0 -6
- package/lib/examples/CellSimpleExample.js +0 -20
- 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.
|
|
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
|
*
|
package/lib/chat/Chat.d.ts
CHANGED
|
@@ -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:
|
|
235
|
-
?
|
|
236
|
-
:
|
|
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
|
-
}, [
|
|
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 {
|
|
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
|
|
117
|
-
const
|
|
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(
|
|
120
|
-
const resolvedMode =
|
|
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
|
-
|
|
514
|
-
|
|
515
|
-
|
|
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
|
-
|
|
525
|
-
|
|
526
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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;
|