@datalayer/agent-runtimes 1.0.21 → 1.0.25
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 +2 -2
- package/lib/AgentNode.js +26 -26
- package/lib/chat/Chat.d.ts +1 -1
- package/lib/chat/Chat.js +2 -2
- package/lib/chat/base/ChatBase.js +44 -9
- package/lib/chat/document/EphemeralDocument.d.ts +12 -1
- package/lib/chat/document/EphemeralDocument.js +4 -4
- package/lib/chat/notebook/EphemeralNotebook.d.ts +11 -1
- package/lib/chat/notebook/EphemeralNotebook.js +13 -2
- package/lib/collaboration/DatalayerCollaborationProvider.d.ts +1 -1
- package/lib/collaboration/DatalayerCollaborationProvider.js +5 -5
- package/lib/components/code-sandboxes/CodeSandboxLauncher.d.ts +59 -0
- package/lib/components/code-sandboxes/CodeSandboxLauncher.js +272 -0
- package/lib/components/code-sandboxes/CodeSandboxPicker.d.ts +71 -0
- package/lib/components/code-sandboxes/CodeSandboxPicker.js +163 -0
- package/lib/components/code-sandboxes/NewCodeSandboxControls.d.ts +42 -0
- package/lib/components/code-sandboxes/NewCodeSandboxControls.js +76 -0
- package/lib/components/code-sandboxes/index.d.ts +3 -0
- package/lib/components/code-sandboxes/index.js +7 -0
- package/lib/components/progress/CreditsIndicator.d.ts +7 -0
- package/lib/components/progress/CreditsIndicator.js +2 -2
- package/lib/components/runtimes/RuntimeLauncherDialog.d.ts +5 -55
- package/lib/components/runtimes/RuntimeLauncherDialog.js +5 -269
- package/lib/components/runtimes/RuntimePickerBase.d.ts +6 -67
- package/lib/components/runtimes/RuntimePickerBase.js +6 -151
- package/lib/components/runtimes/RuntimePickerCell.d.ts +2 -2
- package/lib/components/runtimes/RuntimePickerCell.js +4 -4
- package/lib/components/runtimes/RuntimePickerNotebook.js +35 -70
- package/lib/components/runtimes/RuntimeReservationControl.js +8 -1
- package/lib/components/runtimes/RuntimeSimplePicker.js +1 -1
- package/lib/components/runtimes/RuntimeUtils.js +34 -18
- package/lib/components/runtimes/index.d.ts +1 -0
- package/lib/components/runtimes/index.js +2 -0
- package/lib/context/CostUsageChart.d.ts +2 -2
- package/lib/context/CostUsageChart.js +7 -7
- package/lib/context/TokenUsageChart.d.ts +2 -2
- package/lib/context/TokenUsageChart.js +6 -6
- package/lib/context/TurnGraphChart.d.ts +1 -1
- package/lib/context/TurnGraphChart.js +6 -6
- package/lib/examples/AgentEvalsExample.js +1 -1
- package/lib/examples/AgentGuardrailsExample.js +3 -3
- package/lib/examples/AgentInferenceProviderExample.js +1 -1
- package/lib/examples/AgentMonitoringExample.js +6 -6
- package/lib/examples/AgentOtelExample.d.ts +2 -2
- package/lib/examples/AgentOtelExample.js +5 -5
- package/lib/examples/AgentspecsExample.js +1 -1
- package/lib/examples/NotebookCollaborationExample.js +8 -8
- package/lib/examples/main.js +5 -5
- package/lib/examples2/DatalayerNotebookExample.js +8 -8
- package/lib/examples2/main.js +5 -5
- package/lib/hooks/useAgentRuntimes.js +3 -3
- package/lib/hooks/useMonitoring.d.ts +5 -5
- package/lib/hooks/useMonitoring.js +10 -10
- package/lib/protocols/AGUIAdapter.js +4 -0
- package/lib/protocols/VercelAIAdapter.js +3 -0
- package/lib/types/chat.d.ts +23 -0
- package/lib/types/tools.d.ts +11 -0
- package/package.json +3 -3
- package/scripts/codegen/__pycache__/versioning.cpython-313.pyc +0 -0
- package/lib/components/toolbars/AssignmentEditorToolbar.d.ts +0 -4
- package/lib/components/toolbars/AssignmentEditorToolbar.js +0 -18
- package/lib/components/toolbars/DocumentEditorToolbar.d.ts +0 -2
- package/lib/components/toolbars/DocumentEditorToolbar.js +0 -12
- package/lib/components/toolbars/NotebookEditorToolbar.d.ts +0 -29
- package/lib/components/toolbars/NotebookEditorToolbar.js +0 -30
package/README.md
CHANGED
|
@@ -261,7 +261,7 @@ and propagates those values to the Vite HTML placeholders.
|
|
|
261
261
|
Override any URL on the command line:
|
|
262
262
|
|
|
263
263
|
```bash
|
|
264
|
-
make examples:prod
|
|
264
|
+
make examples:prod DATALAYER_DEFAULT_URL=https://prod2.datalayer.run
|
|
265
265
|
```
|
|
266
266
|
|
|
267
267
|
### Running against a local `plane local` stack
|
|
@@ -285,7 +285,7 @@ both http and ws traffic stay local) at the matching localhost port exposed by
|
|
|
285
285
|
| `PLANE_LOCAL_MANAGER_URL` | `http://localhost:2100` |
|
|
286
286
|
| `PLANE_LOCAL_AI_AGENTS_URL` | `http://localhost:4400` |
|
|
287
287
|
| `PLANE_LOCAL_AI_INFERENCE_URL` | `http://localhost:4450` |
|
|
288
|
-
| `
|
|
288
|
+
| `PLANE_LOCAL_JUPYTER_MCP_SERVER_URL` | `http://localhost:4404/mcp` |
|
|
289
289
|
| `PLANE_LOCAL_GROWTH_URL` | `http://localhost:6660` |
|
|
290
290
|
| `PLANE_LOCAL_SUCCESS_URL` | `http://localhost:3300` |
|
|
291
291
|
| `PLANE_LOCAL_STATUS_URL` | `http://localhost:4785` |
|
package/lib/AgentNode.js
CHANGED
|
@@ -49,7 +49,7 @@ const LOCAL_JUPYTER_SANDBOX = (() => {
|
|
|
49
49
|
return { baseUrl: raw.replace(/\/$/, ''), token: undefined };
|
|
50
50
|
}
|
|
51
51
|
})();
|
|
52
|
-
const
|
|
52
|
+
const DEFAULT_DATALAYER_SERVICE_URL = 'https://prod1.datalayer.run';
|
|
53
53
|
/**
|
|
54
54
|
* localStorage key recording that the user explicitly signed out. When set, the
|
|
55
55
|
* UI must not silently re-authenticate from the env-supplied DATALAYER_API_KEY
|
|
@@ -76,7 +76,7 @@ function setAutoBootstrapDisabled(disabled) {
|
|
|
76
76
|
* `DATALAYER_*_URL` environment variables, e.g. from `plane local`) when it
|
|
77
77
|
* serves the built agent pages. Reading it at runtime lets the node target the
|
|
78
78
|
* configured services (IAM, runtimes, ...) instead of the build-time-baked
|
|
79
|
-
* `
|
|
79
|
+
* `VITE_DATALAYER_*_URL`, which default to production because `make build` runs
|
|
80
80
|
* without the local environment.
|
|
81
81
|
*/
|
|
82
82
|
const getConfigUrlFromDocument = (...keys) => {
|
|
@@ -101,18 +101,18 @@ const getConfigUrlFromDocument = (...keys) => {
|
|
|
101
101
|
}
|
|
102
102
|
return undefined;
|
|
103
103
|
};
|
|
104
|
-
/** Resolve the
|
|
105
|
-
const
|
|
106
|
-
import.meta.env?.
|
|
107
|
-
|
|
108
|
-
/** Resolve the runtimes URL: injected config → VITE env →
|
|
104
|
+
/** Resolve the IAM URL: injected config → VITE env → production. */
|
|
105
|
+
const resolveIamUrl = () => getConfigUrlFromDocument('iamUrl') ||
|
|
106
|
+
import.meta.env?.VITE_DATALAYER_IAM_URL ||
|
|
107
|
+
DEFAULT_DATALAYER_SERVICE_URL;
|
|
108
|
+
/** Resolve the runtimes URL: injected config → VITE env → production. */
|
|
109
109
|
const resolveRuntimesUrl = () => getConfigUrlFromDocument('runtimesUrl') ||
|
|
110
110
|
import.meta.env?.VITE_DATALAYER_RUNTIMES_URL ||
|
|
111
|
-
|
|
112
|
-
/** Resolve the spacer URL: injected config → VITE env →
|
|
111
|
+
DEFAULT_DATALAYER_SERVICE_URL;
|
|
112
|
+
/** Resolve the spacer URL: injected config → VITE env → production. */
|
|
113
113
|
const resolveSpacerUrl = () => getConfigUrlFromDocument('spacerUrl') ||
|
|
114
114
|
import.meta.env?.VITE_DATALAYER_SPACER_URL ||
|
|
115
|
-
|
|
115
|
+
DEFAULT_DATALAYER_SERVICE_URL;
|
|
116
116
|
const MODE_CARDS = [
|
|
117
117
|
{
|
|
118
118
|
mode: 'private',
|
|
@@ -236,7 +236,7 @@ function AgentNodeProfileView({ token, onTokenExpired, avatarFallbackBackground,
|
|
|
236
236
|
export function AgentNode() {
|
|
237
237
|
const { token, setAuth, clearAuth } = useSimpleAuthStore();
|
|
238
238
|
const tokenForCore = token ?? undefined;
|
|
239
|
-
const signInLoginUrl = `${
|
|
239
|
+
const signInLoginUrl = `${resolveIamUrl()}/api/iam/v1/login`;
|
|
240
240
|
const queryClient = useQueryClient();
|
|
241
241
|
const iamUser = useIAMStore(state => state.user);
|
|
242
242
|
const { colorMode, theme: themeVariant } = useAgentNodeThemeStore();
|
|
@@ -287,7 +287,7 @@ export function AgentNode() {
|
|
|
287
287
|
}
|
|
288
288
|
const spacerUrl = resolveSpacerUrl();
|
|
289
289
|
return new DatalayerCollaborationProvider({
|
|
290
|
-
|
|
290
|
+
spacerUrl,
|
|
291
291
|
token,
|
|
292
292
|
});
|
|
293
293
|
}, [ephemeralCollaborationDocumentId, token]);
|
|
@@ -702,26 +702,26 @@ export function AgentNode() {
|
|
|
702
702
|
}, [token, pushCredentials]);
|
|
703
703
|
useEffect(() => {
|
|
704
704
|
import('@datalayer/core/lib/state').then(({ iamStore, coreStore }) => {
|
|
705
|
-
const
|
|
705
|
+
const iamUrl = resolveIamUrl();
|
|
706
706
|
const runtimesUrl = resolveRuntimesUrl();
|
|
707
707
|
const aiInferenceUrl = getConfigUrlFromDocument('aiInferenceUrl') ||
|
|
708
708
|
import.meta.env?.VITE_DATALAYER_AI_INFERENCE_URL ||
|
|
709
|
-
|
|
709
|
+
DEFAULT_DATALAYER_SERVICE_URL;
|
|
710
710
|
// Seed all per-service URLs to match the main UI login behavior.
|
|
711
711
|
const coreApi = coreStore.getState();
|
|
712
712
|
const prevCfg = coreApi.configuration ?? {};
|
|
713
713
|
const urls = {
|
|
714
|
-
iamUrl:
|
|
714
|
+
iamUrl: iamUrl,
|
|
715
715
|
runtimesUrl,
|
|
716
|
-
spacerUrl:
|
|
717
|
-
libraryUrl:
|
|
718
|
-
aiAgentsUrl:
|
|
716
|
+
spacerUrl: iamUrl,
|
|
717
|
+
libraryUrl: iamUrl,
|
|
718
|
+
aiAgentsUrl: iamUrl,
|
|
719
719
|
aiInferenceUrl: aiInferenceUrl,
|
|
720
|
-
|
|
721
|
-
otelUrl:
|
|
722
|
-
growthUrl:
|
|
723
|
-
successUrl:
|
|
724
|
-
supportUrl:
|
|
720
|
+
jupyterMcpServerUrl: 'https://mcp.datalayer.run/mcp',
|
|
721
|
+
otelUrl: iamUrl,
|
|
722
|
+
growthUrl: iamUrl,
|
|
723
|
+
successUrl: iamUrl,
|
|
724
|
+
supportUrl: iamUrl,
|
|
725
725
|
};
|
|
726
726
|
if (typeof coreApi.setConfiguration === 'function') {
|
|
727
727
|
coreApi.setConfiguration({ ...prevCfg, ...urls });
|
|
@@ -732,7 +732,7 @@ export function AgentNode() {
|
|
|
732
732
|
}));
|
|
733
733
|
}
|
|
734
734
|
const api = iamStore.getState();
|
|
735
|
-
iamStore.setState({ token: tokenForCore, iamUrl
|
|
735
|
+
iamStore.setState({ token: tokenForCore, iamUrl });
|
|
736
736
|
if (tokenForCore && typeof api.refreshUserByToken === 'function') {
|
|
737
737
|
void Promise.resolve(api.refreshUserByToken(tokenForCore)).then(() => {
|
|
738
738
|
queryClient.invalidateQueries({ queryKey: ['organizations'] });
|
|
@@ -841,9 +841,9 @@ export function AgentNode() {
|
|
|
841
841
|
// API keys are exchanged for a session token before login so billing and
|
|
842
842
|
// plans endpoints (/api/iam/v1/plans/*) resolve the correct paid plan.
|
|
843
843
|
const handleApiKeySignIn = async (apiKey) => {
|
|
844
|
-
const
|
|
844
|
+
const iamUrl = resolveIamUrl();
|
|
845
845
|
try {
|
|
846
|
-
const resp = await fetch(`${
|
|
846
|
+
const resp = await fetch(`${iamUrl}/api/iam/v1/login`, {
|
|
847
847
|
method: 'POST',
|
|
848
848
|
headers: { 'Content-Type': 'application/json' },
|
|
849
849
|
body: JSON.stringify({ token: apiKey }),
|
package/lib/chat/Chat.d.ts
CHANGED
|
@@ -107,5 +107,5 @@ export interface ChatProps extends ChatCommonProps {
|
|
|
107
107
|
* />
|
|
108
108
|
* ```
|
|
109
109
|
*/
|
|
110
|
-
export declare function Chat({ protocol: transport, extensions: _extensions, baseUrl, endpoint: endpointProp, configEndpoint: configEndpointProp, enableConfigQuery: enableConfigQueryProp, wsUrl, agentId, authToken: authTokenProp, placeholder, title, subtitle, brandIcon, autoConnect, streaming: _streaming, onMessageSent: _onMessageSent, onMessageReceived: _onMessageReceived, onDisconnect, onLogout: _onLogout, onCollapsePanel: _onCollapsePanel, className, height, showHeader, showNewChatButton, showClearButton, showModelSelector, showToolsMenu, showInput, disableInputPrompt, overlay, launching, launchingMessage, showSkillsMenu, codemodeEnabled, onToggleCodemode, showTokenUsage, initialModel, availableModels, mcpServers, initialSkills, clearOnMount: _clearOnMount, suggestions, submitOnSuggestionClick, description, headerContent, headerActions, autoFocus, identityProviders, onIdentityConnect, onIdentityDisconnect, runtimeId, historyEndpoint, pendingPrompt, errorBanner, showInformation, chatViewMode, onChatViewModeChange, frontendTools, enableEphemeralNotebook, initialEphemeralNotebookOpen, onEphemeralNotebookOpenChange, enableEphemeralDocument, initialEphemeralSurfaceMode, onEphemeralSurfaceModeChange, collapsed, onExpandFromCollapsed, ephemeralNotebookToolbar, ephemeralNotebookCollaborationProvider, ephemeralNotebookCollaborationDocumentId, ephemeralDocumentCollaboration, ephemeralRuntimeOverride, onToolCallStart, onToolCallComplete, renderToolResult, hideMessagesAfterToolUI, contextSnapshot, mcpStatusData, codemodeStatusData, sandboxStatusData, kernel, kernelIndicatorPlacement, kernelEnvironmentName, kernelCpu, kernelMemory, kernelGpu, themeVariant, colorMode, showToolApprovalBanner, pendingApprovals, onApproveApproval, onRejectApproval, disableInternalJupyterTheme, }: ChatProps): import("react/jsx-runtime").JSX.Element;
|
|
110
|
+
export declare function Chat({ protocol: transport, extensions: _extensions, baseUrl, endpoint: endpointProp, configEndpoint: configEndpointProp, enableConfigQuery: enableConfigQueryProp, wsUrl, agentId, authToken: authTokenProp, placeholder, title, subtitle, brandIcon, autoConnect, streaming: _streaming, onMessageSent: _onMessageSent, onMessageReceived: _onMessageReceived, onDisconnect, onLogout: _onLogout, onCollapsePanel: _onCollapsePanel, className, height, showHeader, showNewChatButton, showClearButton, showModelSelector, showToolsMenu, showInput, disableInputPrompt, overlay, launching, launchingMessage, showSkillsMenu, codemodeEnabled, onToggleCodemode, showTokenUsage, initialModel, availableModels, mcpServers, initialSkills, clearOnMount: _clearOnMount, suggestions, submitOnSuggestionClick, description, headerContent, headerActions, autoFocus, identityProviders, onIdentityConnect, onIdentityDisconnect, runtimeId, historyEndpoint, pendingPrompt, errorBanner, showInformation, chatViewMode, onChatViewModeChange, frontendTools, enableEphemeralNotebook, initialEphemeralNotebookOpen, onEphemeralNotebookOpenChange, enableEphemeralDocument, initialEphemeralSurfaceMode, onEphemeralSurfaceModeChange, collapsed, onExpandFromCollapsed, ephemeralNotebookToolbar, ephemeralNotebookToolbarExtraItems, ephemeralDocumentToolbarExtraItems, ephemeralNotebookCollaborationProvider, ephemeralNotebookCollaborationDocumentId, ephemeralDocumentCollaboration, ephemeralRuntimeOverride, onToolCallStart, onToolCallComplete, renderToolResult, hideMessagesAfterToolUI, contextSnapshot, mcpStatusData, codemodeStatusData, sandboxStatusData, kernel, kernelIndicatorPlacement, kernelEnvironmentName, kernelCpu, kernelMemory, kernelGpu, themeVariant, colorMode, showToolApprovalBanner, pendingApprovals, onApproveApproval, onRejectApproval, disableInternalJupyterTheme, }: ChatProps): import("react/jsx-runtime").JSX.Element;
|
|
111
111
|
export default Chat;
|
package/lib/chat/Chat.js
CHANGED
|
@@ -136,7 +136,7 @@ function getProtocolType(protocol) {
|
|
|
136
136
|
* />
|
|
137
137
|
* ```
|
|
138
138
|
*/
|
|
139
|
-
export function Chat({ protocol: transport, extensions: _extensions, baseUrl = 'http://localhost:8765', endpoint: endpointProp, configEndpoint: configEndpointProp, enableConfigQuery: enableConfigQueryProp, wsUrl, agentId, authToken: authTokenProp, placeholder = 'Type your message...', title, subtitle, brandIcon, autoConnect = true, streaming: _streaming = true, onMessageSent: _onMessageSent, onMessageReceived: _onMessageReceived, onDisconnect, onLogout: _onLogout, onCollapsePanel: _onCollapsePanel, className, height = '600px', showHeader = true, showNewChatButton = true, showClearButton = true, showModelSelector = true, showToolsMenu = true, showInput = true, disableInputPrompt = false, overlay, launching = false, launchingMessage, showSkillsMenu = true, codemodeEnabled = false, onToggleCodemode, showTokenUsage = true, initialModel, availableModels, mcpServers, initialSkills, clearOnMount: _clearOnMount = true, suggestions, submitOnSuggestionClick = true, description, headerContent, headerActions, autoFocus = false, identityProviders, onIdentityConnect, onIdentityDisconnect, runtimeId, historyEndpoint, pendingPrompt, errorBanner, showInformation = true, chatViewMode, onChatViewModeChange, frontendTools, enableEphemeralNotebook, initialEphemeralNotebookOpen, onEphemeralNotebookOpenChange, enableEphemeralDocument, initialEphemeralSurfaceMode, onEphemeralSurfaceModeChange, collapsed = false, onExpandFromCollapsed, ephemeralNotebookToolbar, ephemeralNotebookCollaborationProvider, ephemeralNotebookCollaborationDocumentId, ephemeralDocumentCollaboration, ephemeralRuntimeOverride, onToolCallStart, onToolCallComplete, renderToolResult, hideMessagesAfterToolUI = false, contextSnapshot, mcpStatusData, codemodeStatusData, sandboxStatusData, kernel, kernelIndicatorPlacement, kernelEnvironmentName, kernelCpu, kernelMemory, kernelGpu, themeVariant, colorMode, showToolApprovalBanner, pendingApprovals, onApproveApproval, onRejectApproval, disableInternalJupyterTheme = false, }) {
|
|
139
|
+
export function Chat({ protocol: transport, extensions: _extensions, baseUrl = 'http://localhost:8765', endpoint: endpointProp, configEndpoint: configEndpointProp, enableConfigQuery: enableConfigQueryProp, wsUrl, agentId, authToken: authTokenProp, placeholder = 'Type your message...', title, subtitle, brandIcon, autoConnect = true, streaming: _streaming = true, onMessageSent: _onMessageSent, onMessageReceived: _onMessageReceived, onDisconnect, onLogout: _onLogout, onCollapsePanel: _onCollapsePanel, className, height = '600px', showHeader = true, showNewChatButton = true, showClearButton = true, showModelSelector = true, showToolsMenu = true, showInput = true, disableInputPrompt = false, overlay, launching = false, launchingMessage, showSkillsMenu = true, codemodeEnabled = false, onToggleCodemode, showTokenUsage = true, initialModel, availableModels, mcpServers, initialSkills, clearOnMount: _clearOnMount = true, suggestions, submitOnSuggestionClick = true, description, headerContent, headerActions, autoFocus = false, identityProviders, onIdentityConnect, onIdentityDisconnect, runtimeId, historyEndpoint, pendingPrompt, errorBanner, showInformation = true, chatViewMode, onChatViewModeChange, frontendTools, enableEphemeralNotebook, initialEphemeralNotebookOpen, onEphemeralNotebookOpenChange, enableEphemeralDocument, initialEphemeralSurfaceMode, onEphemeralSurfaceModeChange, collapsed = false, onExpandFromCollapsed, ephemeralNotebookToolbar, ephemeralNotebookToolbarExtraItems, ephemeralDocumentToolbarExtraItems, ephemeralNotebookCollaborationProvider, ephemeralNotebookCollaborationDocumentId, ephemeralDocumentCollaboration, ephemeralRuntimeOverride, onToolCallStart, onToolCallComplete, renderToolResult, hideMessagesAfterToolUI = false, contextSnapshot, mcpStatusData, codemodeStatusData, sandboxStatusData, kernel, kernelIndicatorPlacement, kernelEnvironmentName, kernelCpu, kernelMemory, kernelGpu, themeVariant, colorMode, showToolApprovalBanner, pendingApprovals, onApproveApproval, onRejectApproval, disableInternalJupyterTheme = false, }) {
|
|
140
140
|
const resolvedAgentId = typeof agentId === 'string' && agentId.trim().length > 0
|
|
141
141
|
? agentId.trim()
|
|
142
142
|
: 'default';
|
|
@@ -364,6 +364,6 @@ export function Chat({ protocol: transport, extensions: _extensions, baseUrl = '
|
|
|
364
364
|
? 'attention.fg'
|
|
365
365
|
: 'danger.fg',
|
|
366
366
|
flex: 1,
|
|
367
|
-
}, children: errorBanner.message })] })), _jsx(ChatBase, { title: title, subtitle: subtitle, brandIcon: brandIcon, showHeader: showHeader, protocol: protocolConfig, placeholder: placeholder, description: description, suggestions: suggestions, submitOnSuggestionClick: submitOnSuggestionClick, autoFocus: autoFocus, runtimeId: runtimeId, historyEndpoint: historyEndpoint, pendingPrompt: pendingPrompt, showInformation: showInformation, onInformationClick: handleInformationClick, headerContent: headerContent, headerActions: headerActions, showModelSelector: showModelSelector, showToolsMenu: showToolsMenu, showInput: showInput, disableInputPrompt: disableInputPrompt, overlay: overlay, launching: launching, launchingMessage: launchingMessage, autoConnect: autoConnect, showSkillsMenu: showSkillsMenu, showTokenUsage: showTokenUsage, codemodeEnabled: codemodeEnabled, onToggleCodemode: onToggleCodemode, initialModel: initialModel, availableModels: availableModels, mcpServers: mcpServers, initialSkills: initialSkills, connectedIdentities: identitiesForChat, onNewChat: handleNewChat, onMessagesChange: handleMessagesChange, headerButtons: headerButtons, avatarConfig: avatarConfig, backgroundColor: "canvas.default", focusTrigger: focusTrigger, chatViewMode: chatViewMode, onChatViewModeChange: onChatViewModeChange, frontendTools: frontendTools, enableEphemeralNotebook: enableEphemeralNotebook, initialEphemeralNotebookOpen: initialEphemeralNotebookOpen, onEphemeralNotebookOpenChange: onEphemeralNotebookOpenChange, enableEphemeralDocument: enableEphemeralDocument, initialEphemeralSurfaceMode: initialEphemeralSurfaceMode, onEphemeralSurfaceModeChange: onEphemeralSurfaceModeChange, collapsed: collapsed, onExpandFromCollapsed: onExpandFromCollapsed, ephemeralNotebookToolbar: ephemeralNotebookToolbar, ephemeralNotebookCollaborationProvider: ephemeralNotebookCollaborationProvider, ephemeralNotebookCollaborationDocumentId: ephemeralNotebookCollaborationDocumentId, ephemeralDocumentCollaboration: ephemeralDocumentCollaboration, ephemeralRuntimeOverride: ephemeralRuntimeOverride, onToolCallStart: onToolCallStart, onToolCallComplete: onToolCallComplete, renderToolResult: renderToolResult, hideMessagesAfterToolUI: hideMessagesAfterToolUI, contextSnapshot: contextSnapshot, mcpStatusData: mcpStatusData, sandboxStatusData: sandboxStatusData, kernel: kernel, kernelIndicatorPlacement: kernelIndicatorPlacement, kernelEnvironmentName: kernelEnvironmentName, kernelCpu: kernelCpu, kernelMemory: kernelMemory, kernelGpu: kernelGpu, themeVariant: themeVariant, colorMode: colorMode, showToolApprovalBanner: showToolApprovalBanner, pendingApprovals: pendingApprovals, onApproveApproval: onApproveApproval, onRejectApproval: onRejectApproval, disableInternalJupyterTheme: disableInternalJupyterTheme })] })] }) }) }));
|
|
367
|
+
}, children: errorBanner.message })] })), _jsx(ChatBase, { title: title, subtitle: subtitle, brandIcon: brandIcon, showHeader: showHeader, protocol: protocolConfig, placeholder: placeholder, description: description, suggestions: suggestions, submitOnSuggestionClick: submitOnSuggestionClick, autoFocus: autoFocus, runtimeId: runtimeId, historyEndpoint: historyEndpoint, pendingPrompt: pendingPrompt, showInformation: showInformation, onInformationClick: handleInformationClick, headerContent: headerContent, headerActions: headerActions, showModelSelector: showModelSelector, showToolsMenu: showToolsMenu, showInput: showInput, disableInputPrompt: disableInputPrompt, overlay: overlay, launching: launching, launchingMessage: launchingMessage, autoConnect: autoConnect, showSkillsMenu: showSkillsMenu, showTokenUsage: showTokenUsage, codemodeEnabled: codemodeEnabled, onToggleCodemode: onToggleCodemode, initialModel: initialModel, availableModels: availableModels, mcpServers: mcpServers, initialSkills: initialSkills, connectedIdentities: identitiesForChat, onNewChat: handleNewChat, onMessagesChange: handleMessagesChange, headerButtons: headerButtons, avatarConfig: avatarConfig, backgroundColor: "canvas.default", focusTrigger: focusTrigger, chatViewMode: chatViewMode, onChatViewModeChange: onChatViewModeChange, frontendTools: frontendTools, enableEphemeralNotebook: enableEphemeralNotebook, initialEphemeralNotebookOpen: initialEphemeralNotebookOpen, onEphemeralNotebookOpenChange: onEphemeralNotebookOpenChange, enableEphemeralDocument: enableEphemeralDocument, initialEphemeralSurfaceMode: initialEphemeralSurfaceMode, onEphemeralSurfaceModeChange: onEphemeralSurfaceModeChange, collapsed: collapsed, onExpandFromCollapsed: onExpandFromCollapsed, ephemeralNotebookToolbar: ephemeralNotebookToolbar, ephemeralNotebookToolbarExtraItems: ephemeralNotebookToolbarExtraItems, ephemeralDocumentToolbarExtraItems: ephemeralDocumentToolbarExtraItems, ephemeralNotebookCollaborationProvider: ephemeralNotebookCollaborationProvider, ephemeralNotebookCollaborationDocumentId: ephemeralNotebookCollaborationDocumentId, ephemeralDocumentCollaboration: ephemeralDocumentCollaboration, ephemeralRuntimeOverride: ephemeralRuntimeOverride, onToolCallStart: onToolCallStart, onToolCallComplete: onToolCallComplete, renderToolResult: renderToolResult, hideMessagesAfterToolUI: hideMessagesAfterToolUI, contextSnapshot: contextSnapshot, mcpStatusData: mcpStatusData, sandboxStatusData: sandboxStatusData, kernel: kernel, kernelIndicatorPlacement: kernelIndicatorPlacement, kernelEnvironmentName: kernelEnvironmentName, kernelCpu: kernelCpu, kernelMemory: kernelMemory, kernelGpu: kernelGpu, themeVariant: themeVariant, colorMode: colorMode, showToolApprovalBanner: showToolApprovalBanner, pendingApprovals: pendingApprovals, onApproveApproval: onApproveApproval, onRejectApproval: onRejectApproval, disableInternalJupyterTheme: disableInternalJupyterTheme })] })] }) }) }));
|
|
368
368
|
}
|
|
369
369
|
export default Chat;
|
|
@@ -58,6 +58,28 @@ const sentPendingPromptKeys = new Set();
|
|
|
58
58
|
* ephemeral notebook/document is not yet ready. Shown in place of the surface
|
|
59
59
|
* content (never as an overlay) so structure appears as early as possible.
|
|
60
60
|
*/
|
|
61
|
+
/**
|
|
62
|
+
* Whether a frontend tool declares any parameter.
|
|
63
|
+
*
|
|
64
|
+
* The empty-args guard around execution exists for AG-UI, which emits a
|
|
65
|
+
* first tool-call with `{}` and the real arguments in a later update. A
|
|
66
|
+
* tool that declares no parameters never gets that update — `{}` IS its
|
|
67
|
+
* full argument set — so waiting on it left the call executing forever.
|
|
68
|
+
*/
|
|
69
|
+
function frontendToolExpectsArgs(tool) {
|
|
70
|
+
const parameters = tool?.parameters;
|
|
71
|
+
if (!parameters) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
if (Array.isArray(parameters)) {
|
|
75
|
+
return parameters.length > 0;
|
|
76
|
+
}
|
|
77
|
+
const properties = parameters.properties;
|
|
78
|
+
if (properties && typeof properties === 'object') {
|
|
79
|
+
return Object.keys(properties).length > 0;
|
|
80
|
+
}
|
|
81
|
+
return Object.keys(parameters).length > 0;
|
|
82
|
+
}
|
|
61
83
|
function CompanionSurfaceSkeleton({ mode }) {
|
|
62
84
|
return (_jsx(Box, { "aria-label": mode === 'notebook' ? 'Preparing notebook…' : 'Preparing document…', sx: {
|
|
63
85
|
flex: 1,
|
|
@@ -474,7 +496,7 @@ function ChatBaseInner({ title, subtitle, showHeader = false, showTokenUsage = t
|
|
|
474
496
|
// Mode selection
|
|
475
497
|
useStore: useStoreMode = true, protocol: protocolRaw, onSendMessage, enableStreaming = false,
|
|
476
498
|
// Extended props
|
|
477
|
-
brandIcon, avatarConfig, headerButtons, showPoweredBy = false, poweredByProps, emptyState, renderToolResult, footerContent, showInformation = false, onInformationClick, headerContent, children, borderRadius, backgroundColor, border, boxShadow, compact = false, placeholder, description = 'Start a conversation with the AI agent.', onStateUpdate, onNewChat, onClear, onMessagesChange, autoFocus = false, suggestions, submitOnSuggestionClick = true, hideMessagesAfterToolUI = false, focusTrigger, frontendTools: frontendToolsProp, enableEphemeralNotebook = false, initialEphemeralNotebookOpen = true, onEphemeralNotebookOpenChange, enableEphemeralDocument = false, initialEphemeralSurfaceMode, onEphemeralSurfaceModeChange, collapsed = false, onExpandFromCollapsed, ephemeralNotebookToolbar, ephemeralNotebookCollaborationProvider, ephemeralNotebookCollaborationDocumentId, ephemeralDocumentCollaboration, ephemeralRuntimeOverride,
|
|
499
|
+
brandIcon, avatarConfig, headerButtons, showPoweredBy = false, poweredByProps, emptyState, renderToolResult, footerContent, showInformation = false, onInformationClick, headerContent, children, borderRadius, backgroundColor, border, boxShadow, compact = false, placeholder, description = 'Start a conversation with the AI agent.', onStateUpdate, onNewChat, onClear, onMessagesChange, autoFocus = false, suggestions, submitOnSuggestionClick = true, hideMessagesAfterToolUI = false, focusTrigger, frontendTools: frontendToolsProp, enableEphemeralNotebook = false, initialEphemeralNotebookOpen = true, onEphemeralNotebookOpenChange, enableEphemeralDocument = false, initialEphemeralSurfaceMode, onEphemeralSurfaceModeChange, collapsed = false, onExpandFromCollapsed, ephemeralNotebookToolbar, ephemeralNotebookToolbarExtraItems, ephemeralDocumentToolbarExtraItems, ephemeralNotebookCollaborationProvider, ephemeralNotebookCollaborationDocumentId, ephemeralDocumentCollaboration, ephemeralRuntimeOverride,
|
|
478
500
|
// Tool invocation hooks
|
|
479
501
|
onToolCallStart, onToolCallComplete,
|
|
480
502
|
// Identity/Authorization props
|
|
@@ -2011,6 +2033,14 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
2011
2033
|
const toolCallId = event.toolCall.toolCallId || generateMessageId();
|
|
2012
2034
|
const toolName = event.toolCall.toolName;
|
|
2013
2035
|
const args = event.toolCall.args || {};
|
|
2036
|
+
/*
|
|
2037
|
+
* Whether these args are the full set, as the protocol tells it.
|
|
2038
|
+
* Vercel's tool event is terminal — `{}` is an answer there,
|
|
2039
|
+
* legal for a tool whose parameters are all optional. AG-UI
|
|
2040
|
+
* streams the args after a first empty event and says so with
|
|
2041
|
+
* `false`. Without the flag, the old heuristics decide.
|
|
2042
|
+
*/
|
|
2043
|
+
const argsComplete = event.toolCall.argsComplete;
|
|
2014
2044
|
if (toolCallsRef.current.has(toolCallId)) {
|
|
2015
2045
|
const existingToolCall = toolCallsRef.current.get(toolCallId);
|
|
2016
2046
|
if (existingToolCall) {
|
|
@@ -2026,7 +2056,7 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
2026
2056
|
const toolHandler = frontendTool?.handler;
|
|
2027
2057
|
if (toolHandler &&
|
|
2028
2058
|
existingToolCall.status === 'executing' &&
|
|
2029
|
-
Object.keys(args).length > 0) {
|
|
2059
|
+
(argsComplete ?? Object.keys(args).length > 0)) {
|
|
2030
2060
|
pendingToolExecutionsRef.current++;
|
|
2031
2061
|
executeFrontendTool(toolHandler, updatedToolCall, toolCallId);
|
|
2032
2062
|
}
|
|
@@ -2051,12 +2081,17 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
2051
2081
|
});
|
|
2052
2082
|
const frontendTool = frontendToolsRef.current?.find(t => t.name === toolName);
|
|
2053
2083
|
const toolHandler = frontendTool?.handler;
|
|
2054
|
-
//
|
|
2055
|
-
//
|
|
2056
|
-
// the
|
|
2057
|
-
//
|
|
2058
|
-
//
|
|
2059
|
-
|
|
2084
|
+
// Execute when the args are complete. The protocol says so
|
|
2085
|
+
// when it can (`argsComplete`); without the flag, fall back
|
|
2086
|
+
// to the old heuristics — actual args present, or a tool
|
|
2087
|
+
// that declares no parameters, for which `{}` is the full
|
|
2088
|
+
// set and no update is ever coming. A protocol that streams
|
|
2089
|
+
// its args (AG-UI start) says `false` and the update branch
|
|
2090
|
+
// above executes once the full set has arrived.
|
|
2091
|
+
if (toolHandler &&
|
|
2092
|
+
(argsComplete ??
|
|
2093
|
+
(Object.keys(args).length > 0 ||
|
|
2094
|
+
!frontendToolExpectsArgs(frontendTool)))) {
|
|
2060
2095
|
pendingToolExecutionsRef.current++;
|
|
2061
2096
|
executeFrontendTool(toolHandler, toolCallMsg, toolCallId);
|
|
2062
2097
|
}
|
|
@@ -2937,7 +2972,7 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
2937
2972
|
borderRight: '1px solid',
|
|
2938
2973
|
borderColor: 'border.default',
|
|
2939
2974
|
}),
|
|
2940
|
-
}, children: launching || overlay ? (_jsx(CompanionSurfaceSkeleton, { mode: notebookVisible ? 'notebook' : 'document' })) : notebookVisible ? (_jsx(EphemeralNotebook, { notebookId: ephemeralNotebookId, runtimePodName: runtimeId || activeAgentId, runtimeOverride: ephemeralRuntimeOverride, themeVariant: themeVariant, colorMode: colorMode, nbformat: persistedEphemeralNbformat ?? undefined, onNbformatChange: handleEphemeralNotebookChange, toolbarComponent: ephemeralNotebookToolbar, collaborationProvider: ephemeralNotebookCollaborationProvider })) : (_jsx(React.Suspense, { fallback: null, children: _jsx(EphemeralDocument, { documentId: ephemeralDocumentId, runtimePodName: runtimeId || activeAgentId, runtimeOverride: ephemeralRuntimeOverride, themeVariant: themeVariant, colorMode: colorMode, content: persistedEphemeralDocument ?? undefined, onContentChange: handleEphemeralDocumentChange, onToolsReady: handleDocumentToolsReady, onKernelChange: handleDocumentKernelChange, collaboration: ephemeralDocumentCollaboration }) })) }), !surfaceCollapsed && (_jsxs(Box, { sx: surfaceChatFloating
|
|
2975
|
+
}, children: launching || overlay ? (_jsx(CompanionSurfaceSkeleton, { mode: notebookVisible ? 'notebook' : 'document' })) : notebookVisible ? (_jsx(EphemeralNotebook, { notebookId: ephemeralNotebookId, runtimePodName: runtimeId || activeAgentId, runtimeOverride: ephemeralRuntimeOverride, themeVariant: themeVariant, colorMode: colorMode, nbformat: persistedEphemeralNbformat ?? undefined, onNbformatChange: handleEphemeralNotebookChange, toolbarComponent: ephemeralNotebookToolbar, toolbarExtraItems: ephemeralNotebookToolbarExtraItems, collaborationProvider: ephemeralNotebookCollaborationProvider })) : (_jsx(React.Suspense, { fallback: null, children: _jsx(EphemeralDocument, { documentId: ephemeralDocumentId, runtimePodName: runtimeId || activeAgentId, runtimeOverride: ephemeralRuntimeOverride, themeVariant: themeVariant, colorMode: colorMode, content: persistedEphemeralDocument ?? undefined, onContentChange: handleEphemeralDocumentChange, onToolsReady: handleDocumentToolsReady, onKernelChange: handleDocumentKernelChange, collaboration: ephemeralDocumentCollaboration, toolbarExtraItems: ephemeralDocumentToolbarExtraItems }) })) }), !surfaceCollapsed && (_jsxs(Box, { sx: surfaceChatFloating
|
|
2941
2976
|
? {
|
|
2942
2977
|
position: 'absolute',
|
|
2943
2978
|
right: 16,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { IKernelConnection } from '@jupyterlab/services/lib/kernel/kernel';
|
|
2
|
+
import { type ToolbarItem } from '@datalayer/primer-addons';
|
|
2
3
|
import type { FrontendToolDefinition } from '../../types/tools';
|
|
3
4
|
import type { EphemeralRuntimeOverride } from '../notebook/EphemeralNotebook';
|
|
4
5
|
import '@datalayer/jupyter-react/lib/css/PrismCss';
|
|
@@ -63,9 +64,19 @@ export interface EphemeralDocumentProps {
|
|
|
63
64
|
* local memory.
|
|
64
65
|
*/
|
|
65
66
|
collaboration?: EphemeralDocumentCollaboration;
|
|
67
|
+
/**
|
|
68
|
+
* Items added to the toolbar of the document.
|
|
69
|
+
*
|
|
70
|
+
* The Lexical toolbar merges them with its own and orders the whole by the
|
|
71
|
+
* `order` of each item, so a host adds what the document itself knows
|
|
72
|
+
* nothing about — the status of the sandbox it runs on, a selector to
|
|
73
|
+
* change it — the same way the notebook surface does through the
|
|
74
|
+
* `extraItems` of its toolbar.
|
|
75
|
+
*/
|
|
76
|
+
toolbarExtraItems?: ToolbarItem[];
|
|
66
77
|
}
|
|
67
78
|
/**
|
|
68
79
|
* Renders an in-memory Lexical document backed by a sandbox kernel.
|
|
69
80
|
*/
|
|
70
|
-
export declare function EphemeralDocument({ documentId, runtimePodName, runtimeOverride, themeVariant, colorMode, content, onContentChange, onToolsReady, onKernelChange, collaboration, }: EphemeralDocumentProps): import("react/jsx-runtime").JSX.Element;
|
|
81
|
+
export declare function EphemeralDocument({ documentId, runtimePodName, runtimeOverride, themeVariant, colorMode, content, onContentChange, onToolsReady, onKernelChange, collaboration, toolbarExtraItems, }: EphemeralDocumentProps): import("react/jsx-runtime").JSX.Element;
|
|
71
82
|
export default EphemeralDocument;
|
|
@@ -100,15 +100,15 @@ function CodeHighlightPlugin() {
|
|
|
100
100
|
* the active editor from the Lexical composer context and drives the shared
|
|
101
101
|
* {@link ToolbarPlugin} (block type, formatting, insert menu, …).
|
|
102
102
|
*/
|
|
103
|
-
function DocumentToolbar({ setIsLinkEditMode, }) {
|
|
103
|
+
function DocumentToolbar({ setIsLinkEditMode, extraItems, }) {
|
|
104
104
|
const [editor] = useLexicalComposerContext();
|
|
105
105
|
const [activeEditor, setActiveEditor] = useState(editor);
|
|
106
|
-
return (_jsx(ToolbarPlugin, { editor: editor, activeEditor: activeEditor, setActiveEditor: setActiveEditor, setIsLinkEditMode: setIsLinkEditMode }));
|
|
106
|
+
return (_jsx(ToolbarPlugin, { editor: editor, activeEditor: activeEditor, setActiveEditor: setActiveEditor, setIsLinkEditMode: setIsLinkEditMode, extraItems: extraItems }));
|
|
107
107
|
}
|
|
108
108
|
/**
|
|
109
109
|
* Renders an in-memory Lexical document backed by a sandbox kernel.
|
|
110
110
|
*/
|
|
111
|
-
export function EphemeralDocument({ documentId, runtimePodName, runtimeOverride, themeVariant, colorMode, content, onContentChange, onToolsReady, onKernelChange, collaboration, }) {
|
|
111
|
+
export function EphemeralDocument({ documentId, runtimePodName, runtimeOverride, themeVariant, colorMode, content, onContentChange, onToolsReady, onKernelChange, collaboration, toolbarExtraItems, }) {
|
|
112
112
|
// Real-time collaboration is active only when both a WebSocket endpoint and a
|
|
113
113
|
// room id are supplied. In that mode the shared Loro CRDT is the single source
|
|
114
114
|
// of truth: local content-seeding and undo history are disabled so the local
|
|
@@ -384,7 +384,7 @@ export function EphemeralDocument({ documentId, runtimePodName, runtimeOverride,
|
|
|
384
384
|
'& [role="toolbar"][aria-label="Editor toolbar"]': {
|
|
385
385
|
backgroundColor: themeBackground,
|
|
386
386
|
},
|
|
387
|
-
}, children: _jsx(LexicalConfigProvider, { lexicalId: documentId, serviceManager: activeServiceManager, children: _jsx(LexicalComposer, { initialConfig: initialConfig, children: _jsx(CommentsProvider, { children: _jsx(ToolbarContext, { children: _jsxs("div", { className: "editor-shell", children: [_jsx(DocumentToolbar, { setIsLinkEditMode: setIsLinkEditMode }), _jsx("div", { className: "editor-container", children: _jsxs("div", { className: "editor-inner", children: [isCollaborative && collaboration ? (_jsx(LoroCollaborationPlugin, { id: collaboration.roomId, providerFactory: createWebsocketProvider, websocketUrl: collaboration.websocketUrl, shouldBootstrap: true, showCollaborators: true, username: collaborationName, cursorColor: collaborationColor, awarenessData: collaborationAwarenessData })) : null, _jsx(LexicalStatePlugin, {}), _jsx(RichTextPlugin, { contentEditable: _jsx("div", { className: "editor-scroller", children: _jsx("div", { className: "editor", ref: onAnchorRef, children: _jsx(ContentEditable, { className: "editor-input", "aria-label": "Ephemeral document editor" }) }) }), ErrorBoundary: LexicalErrorBoundary }), !isCollaborative && (_jsx(OnChangePlugin, { onChange: handleChange })), !isCollaborative && _jsx(HistoryPlugin, {}), _jsx(AutoFocusPlugin, {}), _jsx(ListPlugin, {}), _jsx(CheckListPlugin, {}), _jsx(LinkPlugin, {}), _jsx(AutoLinkPlugin, {}), _jsx(ListMaxIndentLevelPlugin, { maxDepth: 7 }), _jsx(MarkdownShortcutPlugin, { transformers: TRANSFORMERS }), !isCollaborative && (_jsx(LoadContentPlugin, { content: initialContent })), _jsx(CodeHighlightPlugin, {}), _jsx(ImagesPlugin, { captionsEnabled: false }), _jsx(ExcalidrawPlugin, {}), _jsx(TablePlugin, {}), _jsx(TableCellResizerPlugin, {}), _jsx(TableActionMenuPlugin, {}), _jsx(TableHoverActionsV2Plugin, {}), _jsx(CollapsiblePlugin, {}), _jsx(HorizontalRulePlugin, {}), _jsx(EquationsPlugin, {}), _jsx(YouTubePlugin, {}), _jsx(AutoEmbedPlugin, {}), _jsx(JupyterCellPlugin, {}), _jsx(ComponentPickerMenuPlugin, { kernel: documentKernel }), _jsx(JupyterInputOutputPlugin, { kernel: documentKernel }), floatingAnchorElem && (_jsxs(_Fragment, { children: [_jsx(DraggableBlockPlugin, { anchorElem: floatingAnchorElem }), _jsx(FloatingTextFormatToolbarPlugin, { anchorElem: floatingAnchorElem, setIsLinkEditMode: setIsLinkEditMode }), _jsx(CodeActionMenuPlugin, { anchorElem: floatingAnchorElem })] }))] }) })] }) }) }) }) }) }) }) })) : isRuntimeStarting ? (_jsxs(Box, { sx: {
|
|
387
|
+
}, children: _jsx(LexicalConfigProvider, { lexicalId: documentId, serviceManager: activeServiceManager, children: _jsx(LexicalComposer, { initialConfig: initialConfig, children: _jsx(CommentsProvider, { children: _jsx(ToolbarContext, { children: _jsxs("div", { className: "editor-shell", children: [_jsx(DocumentToolbar, { setIsLinkEditMode: setIsLinkEditMode, extraItems: toolbarExtraItems }), _jsx("div", { className: "editor-container", children: _jsxs("div", { className: "editor-inner", children: [isCollaborative && collaboration ? (_jsx(LoroCollaborationPlugin, { id: collaboration.roomId, providerFactory: createWebsocketProvider, websocketUrl: collaboration.websocketUrl, shouldBootstrap: true, showCollaborators: true, username: collaborationName, cursorColor: collaborationColor, awarenessData: collaborationAwarenessData })) : null, _jsx(LexicalStatePlugin, {}), _jsx(RichTextPlugin, { contentEditable: _jsx("div", { className: "editor-scroller", children: _jsx("div", { className: "editor", ref: onAnchorRef, children: _jsx(ContentEditable, { className: "editor-input", "aria-label": "Ephemeral document editor" }) }) }), ErrorBoundary: LexicalErrorBoundary }), !isCollaborative && (_jsx(OnChangePlugin, { onChange: handleChange })), !isCollaborative && _jsx(HistoryPlugin, {}), _jsx(AutoFocusPlugin, {}), _jsx(ListPlugin, {}), _jsx(CheckListPlugin, {}), _jsx(LinkPlugin, {}), _jsx(AutoLinkPlugin, {}), _jsx(ListMaxIndentLevelPlugin, { maxDepth: 7 }), _jsx(MarkdownShortcutPlugin, { transformers: TRANSFORMERS }), !isCollaborative && (_jsx(LoadContentPlugin, { content: initialContent })), _jsx(CodeHighlightPlugin, {}), _jsx(ImagesPlugin, { captionsEnabled: false }), _jsx(ExcalidrawPlugin, {}), _jsx(TablePlugin, {}), _jsx(TableCellResizerPlugin, {}), _jsx(TableActionMenuPlugin, {}), _jsx(TableHoverActionsV2Plugin, {}), _jsx(CollapsiblePlugin, {}), _jsx(HorizontalRulePlugin, {}), _jsx(EquationsPlugin, {}), _jsx(YouTubePlugin, {}), _jsx(AutoEmbedPlugin, {}), _jsx(JupyterCellPlugin, {}), _jsx(ComponentPickerMenuPlugin, { kernel: documentKernel }), _jsx(JupyterInputOutputPlugin, { kernel: documentKernel }), floatingAnchorElem && (_jsxs(_Fragment, { children: [_jsx(DraggableBlockPlugin, { anchorElem: floatingAnchorElem }), _jsx(FloatingTextFormatToolbarPlugin, { anchorElem: floatingAnchorElem, setIsLinkEditMode: setIsLinkEditMode }), _jsx(CodeActionMenuPlugin, { anchorElem: floatingAnchorElem })] }))] }) })] }) }) }) }) }) }) }) })) : isRuntimeStarting ? (_jsxs(Box, { sx: {
|
|
388
388
|
height: '100%',
|
|
389
389
|
display: 'flex',
|
|
390
390
|
alignItems: 'center',
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { INotebookContent } from '@jupyterlab/nbformat';
|
|
2
|
+
import { type ToolbarItem } from '@datalayer/primer-addons';
|
|
2
3
|
import type { ICollaborationProvider } from '@datalayer/jupyter-react';
|
|
3
4
|
import type { EphemeralNotebookToolbarComponent } from '../../types/chat';
|
|
4
5
|
/**
|
|
@@ -43,6 +44,15 @@ export interface EphemeralNotebookProps {
|
|
|
43
44
|
onNbformatChange?: (content: INotebookContent) => void;
|
|
44
45
|
/** Optional toolbar component override. */
|
|
45
46
|
toolbarComponent?: EphemeralNotebookToolbarComponent;
|
|
47
|
+
/**
|
|
48
|
+
* Items added to the toolbar of the notebook.
|
|
49
|
+
*
|
|
50
|
+
* The notebook toolbar merges them with its own and orders the whole by the
|
|
51
|
+
* `order` of each item, so a host adds what the notebook itself knows
|
|
52
|
+
* nothing about — the status of the sandbox it runs on, a selector to
|
|
53
|
+
* change it — without replacing the toolbar through `toolbarComponent`.
|
|
54
|
+
*/
|
|
55
|
+
toolbarExtraItems?: ToolbarItem[];
|
|
46
56
|
/** Optional theme variant override from host chat context. */
|
|
47
57
|
themeVariant?: string;
|
|
48
58
|
/** Optional color mode override from host chat context. */
|
|
@@ -59,5 +69,5 @@ export interface EphemeralNotebookProps {
|
|
|
59
69
|
/**
|
|
60
70
|
* Renders an in-memory notebook backed by a sandbox kernel.
|
|
61
71
|
*/
|
|
62
|
-
export declare function EphemeralNotebook({ notebookId, runtimePodName, runtimeOverride, cellSidebarMargin, nbformat, onNbformatChange, toolbarComponent, themeVariant, colorMode, collaborationProvider, }: EphemeralNotebookProps): import("react/jsx-runtime").JSX.Element;
|
|
72
|
+
export declare function EphemeralNotebook({ notebookId, runtimePodName, runtimeOverride, cellSidebarMargin, nbformat, onNbformatChange, toolbarComponent, toolbarExtraItems, themeVariant, colorMode, collaborationProvider, }: EphemeralNotebookProps): import("react/jsx-runtime").JSX.Element;
|
|
63
73
|
export default EphemeralNotebook;
|
|
@@ -55,7 +55,7 @@ const EPHEMERAL_NOTEBOOK_CONTENT = {
|
|
|
55
55
|
/**
|
|
56
56
|
* Renders an in-memory notebook backed by a sandbox kernel.
|
|
57
57
|
*/
|
|
58
|
-
export function EphemeralNotebook({ notebookId, runtimePodName, runtimeOverride, cellSidebarMargin = 120, nbformat, onNbformatChange, toolbarComponent, themeVariant, colorMode, collaborationProvider, }) {
|
|
58
|
+
export function EphemeralNotebook({ notebookId, runtimePodName, runtimeOverride, cellSidebarMargin = 120, nbformat, onNbformatChange, toolbarComponent, toolbarExtraItems, themeVariant, colorMode, collaborationProvider, }) {
|
|
59
59
|
// The `nbformat` passed to the `Notebook` component MUST stay a stable
|
|
60
60
|
// reference for the lifetime of a given `notebookId`: the underlying
|
|
61
61
|
// `useNotebookModel` hook rebuilds the notebook model (and its context /
|
|
@@ -188,7 +188,18 @@ export function EphemeralNotebook({ notebookId, runtimePodName, runtimeOverride,
|
|
|
188
188
|
const activeServiceManager = runtimeServiceManager;
|
|
189
189
|
const activeKernelId = runtimeKernelId;
|
|
190
190
|
const activeStartDefaultKernel = runtimeStartDefaultKernel;
|
|
191
|
-
|
|
191
|
+
// The toolbar of the notebook, with the items of the host merged in. A host
|
|
192
|
+
// replacing the toolbar altogether receives them as well, as every toolbar
|
|
193
|
+
// built on the notebook one takes `extraItems`.
|
|
194
|
+
const ToolbarComponent = useMemo(() => {
|
|
195
|
+
const Base = toolbarComponent || NotebookToolbar;
|
|
196
|
+
if (!toolbarExtraItems?.length) {
|
|
197
|
+
return Base;
|
|
198
|
+
}
|
|
199
|
+
return function EphemeralNotebookToolbar(props) {
|
|
200
|
+
return _jsx(Base, { ...props, extraItems: toolbarExtraItems });
|
|
201
|
+
};
|
|
202
|
+
}, [toolbarComponent, toolbarExtraItems]);
|
|
192
203
|
const isRuntimeStarting = Boolean((String(runtimePodName || '').trim() ||
|
|
193
204
|
String(runtimeOverride?.baseUrl || '').trim()) &&
|
|
194
205
|
!activeServiceManager);
|
|
@@ -15,7 +15,7 @@ export interface IDatalayerCollaborationConfig {
|
|
|
15
15
|
/**
|
|
16
16
|
* Base URL for the Datalayer server (optional, uses config from store if not provided).
|
|
17
17
|
*/
|
|
18
|
-
|
|
18
|
+
spacerUrl?: string;
|
|
19
19
|
/**
|
|
20
20
|
* Authentication token (optional, uses config from store if not provided).
|
|
21
21
|
*/
|
|
@@ -60,17 +60,17 @@ export class DatalayerCollaborationProvider {
|
|
|
60
60
|
}
|
|
61
61
|
this.setStatus(CollaborationStatus.Connecting);
|
|
62
62
|
try {
|
|
63
|
-
const
|
|
63
|
+
const spacerUrl = this._config.spacerUrl;
|
|
64
64
|
const token = this._config.token;
|
|
65
|
-
if (!
|
|
66
|
-
throw new Error('Datalayer
|
|
65
|
+
if (!spacerUrl) {
|
|
66
|
+
throw new Error('The Datalayer spacerUrl is not configured - it must be explicitly provided in the DatalayerCollaborationProvider config');
|
|
67
67
|
}
|
|
68
68
|
if (!token) {
|
|
69
69
|
throw new Error('Datalayer token is not configured - must be explicitly provided in DatalayerCollaborationProvider config');
|
|
70
70
|
}
|
|
71
71
|
const { ydoc, awareness } = sharedModel;
|
|
72
|
-
const documentURL = URLExt.join(
|
|
73
|
-
const wsUrl = URLExt.join(
|
|
72
|
+
const documentURL = URLExt.join(spacerUrl, '/api/spacer/v1/documents');
|
|
73
|
+
const wsUrl = URLExt.join(spacerUrl, '/api/spacer/v1/documents/ws').replace(/^http/, 'ws');
|
|
74
74
|
const sessionId = await requestDatalayerCollaborationSessionId({
|
|
75
75
|
url: URLExt.join(documentURL, documentId),
|
|
76
76
|
token,
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { IMarkdownParser, IRenderMime } from '@jupyterlab/rendermime';
|
|
2
|
+
import type { IRemoteServicesManager } from '../../runtimes';
|
|
3
|
+
import type { ICodeSandboxSnapshot, IRuntimeDesc } from '../../models';
|
|
4
|
+
/**
|
|
5
|
+
* {@link CodeSandboxLauncher} properties.
|
|
6
|
+
*/
|
|
7
|
+
export interface ICodeSandboxLauncherProps {
|
|
8
|
+
/**
|
|
9
|
+
* Dialog title
|
|
10
|
+
*/
|
|
11
|
+
dialogTitle?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Remote Jupyter service manager
|
|
14
|
+
*/
|
|
15
|
+
manager: IRemoteServicesManager;
|
|
16
|
+
/**
|
|
17
|
+
* Form submission callback
|
|
18
|
+
*/
|
|
19
|
+
onSubmit: (spec?: IRuntimeDesc) => void;
|
|
20
|
+
/**
|
|
21
|
+
* Whether to start the kernel or not.
|
|
22
|
+
*
|
|
23
|
+
* If `with-example`, a kernel will be started an
|
|
24
|
+
* an example document will be opened (if available).
|
|
25
|
+
* If `defer`, a kernel will not be started but the
|
|
26
|
+
* kernel params will have a `creditsLimit` defined
|
|
27
|
+
* for spinning a runtime.
|
|
28
|
+
*
|
|
29
|
+
* Default: `true`
|
|
30
|
+
*/
|
|
31
|
+
startRuntime?: boolean | 'with-example' | 'defer';
|
|
32
|
+
/**
|
|
33
|
+
* Markdown parser
|
|
34
|
+
*/
|
|
35
|
+
markdownParser?: IMarkdownParser;
|
|
36
|
+
/**
|
|
37
|
+
* If provided the kernel will be started and will
|
|
38
|
+
* restore the provided snapshot in the kernel.
|
|
39
|
+
*/
|
|
40
|
+
kernelSnapshot?: ICodeSandboxSnapshot;
|
|
41
|
+
/**
|
|
42
|
+
* HTML sanitizer
|
|
43
|
+
*/
|
|
44
|
+
sanitizer?: IRenderMime.ISanitizer;
|
|
45
|
+
/**
|
|
46
|
+
* Upgrade subscription URL
|
|
47
|
+
*/
|
|
48
|
+
upgradeSubscription?: string;
|
|
49
|
+
/**
|
|
50
|
+
* Optional submit button label override.
|
|
51
|
+
*/
|
|
52
|
+
submitLabel?: string;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The launcher of a new code sandbox.
|
|
56
|
+
*/
|
|
57
|
+
export declare function CodeSandboxLauncher(props: ICodeSandboxLauncherProps): JSX.Element;
|
|
58
|
+
export declare const RuntimeLauncherDialog: typeof CodeSandboxLauncher;
|
|
59
|
+
export type IRuntimeLauncherDialogProps = ICodeSandboxLauncherProps;
|