@datalayer/agent-runtimes 0.0.5 → 0.0.8
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 +150 -22
- package/lib/components/chat/components/AgentDetails.d.ts +15 -2
- package/lib/components/chat/components/AgentDetails.js +9 -93
- package/lib/components/chat/components/AgentIdentity.d.ts +92 -0
- package/lib/components/chat/components/AgentIdentity.js +318 -0
- package/lib/components/chat/components/Chat.d.ts +24 -1
- package/lib/components/chat/components/Chat.js +41 -19
- package/lib/components/chat/components/ChatFloating.d.ts +6 -1
- package/lib/components/chat/components/ChatFloating.js +12 -6
- package/lib/components/chat/components/ContextDistribution.d.ts +47 -0
- package/lib/components/chat/components/ContextDistribution.js +146 -0
- package/lib/components/chat/components/ContextUsage.d.ts +33 -0
- package/lib/components/chat/components/ContextUsage.js +127 -0
- package/lib/components/chat/components/base/ChatBase.d.ts +51 -1
- package/lib/components/chat/components/base/ChatBase.js +278 -74
- package/lib/components/chat/components/display/ToolCallDisplay.d.ts +16 -2
- package/lib/components/chat/components/display/ToolCallDisplay.js +148 -6
- package/lib/components/chat/components/display/index.d.ts +1 -1
- package/lib/components/chat/components/display/index.js +1 -1
- package/lib/components/chat/components/elements/ChatInputPrompt.d.ts +12 -1
- package/lib/components/chat/components/elements/ChatInputPrompt.js +8 -3
- package/lib/components/chat/components/index.d.ts +3 -0
- package/lib/components/chat/components/index.js +3 -0
- package/lib/components/chat/components/parts/ToolPart.d.ts +1 -1
- package/lib/components/chat/components/parts/ToolPart.js +142 -6
- package/lib/components/chat/index.d.ts +1 -1
- package/lib/components/chat/index.js +1 -1
- package/lib/components/chat/protocols/A2AAdapter.d.ts +9 -0
- package/lib/components/chat/protocols/A2AAdapter.js +13 -2
- package/lib/components/chat/protocols/ACPAdapter.d.ts +9 -0
- package/lib/components/chat/protocols/ACPAdapter.js +13 -2
- package/lib/components/chat/protocols/AGUIAdapter.d.ts +9 -0
- package/lib/components/chat/protocols/AGUIAdapter.js +19 -1
- package/lib/components/chat/protocols/VercelAIAdapter.d.ts +7 -0
- package/lib/components/chat/protocols/VercelAIAdapter.js +19 -0
- package/lib/components/chat/types/execution.d.ts +78 -0
- package/lib/components/chat/types/execution.js +64 -0
- package/lib/components/chat/types/index.d.ts +1 -0
- package/lib/components/chat/types/index.js +1 -0
- package/lib/components/chat/types/protocol.d.ts +9 -0
- package/lib/components/ui/pagination.d.ts +2 -2
- package/lib/components/ui/pagination.js +4 -4
- package/lib/components/ui/resizable.d.ts +4 -4
- package/lib/components/ui/resizable.js +4 -4
- package/lib/examples/A2UiRestaurantExample.js +2 -2
- package/lib/examples/AgUiAgenticExample.js +2 -2
- package/lib/examples/AgUiBackendToolRenderingExample.js +2 -2
- package/lib/examples/AgUiHaikuGenUIExample.js +2 -2
- package/lib/examples/AgUiHumanInTheLoopExample.js +2 -2
- package/lib/examples/AgUiSharedStateExample.js +2 -2
- package/lib/examples/AgUiToolsBasedGenUIExample.js +2 -2
- package/lib/examples/AgentRuntimeCustomExample.js +2 -2
- package/lib/examples/AgentRuntimeLexical2Example.js +2 -1
- package/lib/examples/AgentRuntimeLexicalExample.js +5 -2
- package/lib/examples/AgentRuntimeLexicalSidebarExample.js +4 -2
- package/lib/examples/AgentRuntimeNotebookExample.js +1 -1
- package/lib/examples/AgentRuntimeStandaloneExample.js +2 -2
- package/lib/examples/AgentSpaceFormExample.d.ts +70 -2
- package/lib/examples/AgentSpaceFormExample.js +204 -35
- package/lib/examples/CopilotKitLexicalExample.js +2 -1
- package/lib/examples/components/AgentConfiguration.d.ts +37 -0
- package/lib/examples/components/AgentConfiguration.js +239 -8
- package/lib/examples/components/Header.d.ts +0 -2
- package/lib/examples/components/Header.js +2 -16
- package/lib/examples/components/LexicalEditor.js +2 -1
- package/lib/examples/components/MockFileBrowser.js +6 -2
- package/lib/examples/components/index.d.ts +0 -1
- package/lib/examples/components/index.js +0 -1
- package/lib/examples/example-selector.js +0 -1
- package/lib/examples/index.d.ts +0 -1
- package/lib/examples/index.js +0 -1
- package/lib/examples/lexical/editorConfig.d.ts +3 -2
- package/lib/examples/lexical/editorConfig.js +7 -1
- package/lib/examples/lexical/initial-content.json +2210 -0
- package/lib/examples/main.js +15 -1
- package/lib/identity/IdentityConnect.d.ts +90 -0
- package/lib/identity/IdentityConnect.js +316 -0
- package/lib/identity/OAuthCallback.d.ts +58 -0
- package/lib/identity/OAuthCallback.js +223 -0
- package/lib/identity/dcr.d.ts +257 -0
- package/lib/identity/dcr.js +282 -0
- package/lib/identity/identityStore.d.ts +72 -0
- package/lib/identity/identityStore.js +529 -0
- package/lib/identity/index.d.ts +46 -0
- package/lib/identity/index.js +17 -0
- package/lib/identity/pkce.d.ts +30 -0
- package/lib/identity/pkce.js +65 -0
- package/lib/identity/types.d.ts +293 -0
- package/lib/identity/types.js +73 -0
- package/lib/identity/useIdentity.d.ts +108 -0
- package/lib/identity/useIdentity.js +323 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +2 -0
- package/lib/lib/utils.js +1 -1
- package/lib/renderers/a2ui/lib/utils.js +1 -1
- package/lib/runtime/index.d.ts +35 -0
- package/lib/runtime/index.js +40 -0
- package/lib/runtime/runtimeStore.d.ts +77 -0
- package/lib/runtime/runtimeStore.js +184 -0
- package/lib/runtime/types.d.ts +84 -0
- package/lib/runtime/types.js +15 -0
- package/lib/runtime/useAgentConnection.d.ts +46 -0
- package/lib/runtime/useAgentConnection.js +112 -0
- package/lib/runtime/useAgentRuntime.d.ts +94 -0
- package/lib/runtime/useAgentRuntime.js +125 -0
- package/lib/test-setup.d.ts +1 -1
- package/lib/test-setup.js +1 -0
- package/lib/tools/adapters/agent-runtimes/AgentRuntimesToolAdapter.js +32 -1
- package/lib/tools/adapters/agent-runtimes/lexicalHooks.d.ts +6 -0
- package/lib/tools/adapters/agent-runtimes/lexicalHooks.js +16 -17
- package/package.json +20 -7
- package/patches/@datalayer+jupyter-lexical+1.0.8.patch +11628 -0
- package/patches/@datalayer+jupyter-react+2.0.2.patch +5338 -0
- package/lib/examples/AgentSpaceHomeExample.d.ts +0 -8
- package/lib/examples/AgentSpaceHomeExample.js +0 -171
- package/lib/examples/components/AgentsDataTable.d.ts +0 -13
- package/lib/examples/components/AgentsDataTable.js +0 -74
- package/lib/examples/components/Rating.d.ts +0 -14
- package/lib/examples/components/Rating.js +0 -12
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Zustand store for runtime management.
|
|
7
|
+
*
|
|
8
|
+
* Provides a global store for managing cloud runtimes and agent connections.
|
|
9
|
+
*
|
|
10
|
+
* @module runtime/runtimeStore
|
|
11
|
+
*/
|
|
12
|
+
import { create } from 'zustand';
|
|
13
|
+
const initialState = {
|
|
14
|
+
runtime: null,
|
|
15
|
+
agent: null,
|
|
16
|
+
status: 'idle',
|
|
17
|
+
error: null,
|
|
18
|
+
isLaunching: false,
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Create an agent on a runtime.
|
|
22
|
+
*/
|
|
23
|
+
async function createAgentOnRuntime(agentBaseUrl, agentId, config = {}) {
|
|
24
|
+
const response = await fetch(`${agentBaseUrl}/api/v1/agents`, {
|
|
25
|
+
method: 'POST',
|
|
26
|
+
headers: { 'Content-Type': 'application/json' },
|
|
27
|
+
body: JSON.stringify({
|
|
28
|
+
name: config.name || agentId,
|
|
29
|
+
description: config.description || 'AI assistant',
|
|
30
|
+
agent_library: config.agentLibrary || 'pydantic-ai',
|
|
31
|
+
transport: config.transport || 'ag-ui',
|
|
32
|
+
model: config.model || 'anthropic:claude-sonnet-4-5',
|
|
33
|
+
system_prompt: config.systemPrompt || 'You are a helpful AI assistant.',
|
|
34
|
+
}),
|
|
35
|
+
});
|
|
36
|
+
if (response.ok || response.status === 400) {
|
|
37
|
+
// 400 means agent already exists, which is fine
|
|
38
|
+
const endpoint = `${agentBaseUrl}/api/v1/ag-ui/${agentId}/`;
|
|
39
|
+
return {
|
|
40
|
+
agentId,
|
|
41
|
+
endpoint,
|
|
42
|
+
isReady: true,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
const errorData = await response.json().catch(() => ({}));
|
|
46
|
+
throw new Error(errorData.detail || `Failed to create agent: ${response.status}`);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Zustand store for runtime management.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```typescript
|
|
53
|
+
* import { useRuntimeStore } from '@datalayer/agent-runtimes/lib/runtime';
|
|
54
|
+
*
|
|
55
|
+
* // In a component
|
|
56
|
+
* const { runtime, launchRuntime, status } = useRuntimeStore();
|
|
57
|
+
*
|
|
58
|
+
* // Launch a runtime
|
|
59
|
+
* await launchRuntime({ environmentName: 'python-simple', creditsLimit: 100 });
|
|
60
|
+
*
|
|
61
|
+
* // Access runtime info
|
|
62
|
+
* console.log(runtime?.agentBaseUrl);
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export const useRuntimeStore = create((set, get) => ({
|
|
66
|
+
...initialState,
|
|
67
|
+
connectToRuntime: connection => {
|
|
68
|
+
const baseUrl = connection.serviceManager.serverSettings.baseUrl;
|
|
69
|
+
const agentBaseUrl = baseUrl.replace('/jupyter/server/', '/agent-runtimes/');
|
|
70
|
+
const fullConnection = {
|
|
71
|
+
podName: connection.podName,
|
|
72
|
+
environmentName: connection.environmentName,
|
|
73
|
+
jupyterBaseUrl: baseUrl,
|
|
74
|
+
agentBaseUrl,
|
|
75
|
+
serviceManager: connection.serviceManager,
|
|
76
|
+
status: 'ready',
|
|
77
|
+
kernelId: connection.kernelId,
|
|
78
|
+
};
|
|
79
|
+
set({
|
|
80
|
+
runtime: fullConnection,
|
|
81
|
+
status: 'ready',
|
|
82
|
+
error: null,
|
|
83
|
+
});
|
|
84
|
+
},
|
|
85
|
+
launchRuntime: async (config) => {
|
|
86
|
+
set({ status: 'launching', error: null, isLaunching: true });
|
|
87
|
+
try {
|
|
88
|
+
// Import @datalayer/core dynamically to avoid circular dependencies
|
|
89
|
+
const { createRuntime, makeDatalayerSettings } = await import('@datalayer/core/lib/api');
|
|
90
|
+
const { ServiceManager } = await import('@jupyterlab/services');
|
|
91
|
+
// Create the runtime using IRuntimeOptions from @datalayer/core
|
|
92
|
+
const runtimePod = await createRuntime({
|
|
93
|
+
environmentName: config.environmentName,
|
|
94
|
+
creditsLimit: config.creditsLimit,
|
|
95
|
+
type: config.type || 'notebook',
|
|
96
|
+
givenName: config.givenName,
|
|
97
|
+
capabilities: config.capabilities,
|
|
98
|
+
snapshot: config.snapshot,
|
|
99
|
+
});
|
|
100
|
+
set({ status: 'connecting' });
|
|
101
|
+
// Create service manager for the runtime
|
|
102
|
+
const serverSettings = makeDatalayerSettings(runtimePod.ingress, runtimePod.token);
|
|
103
|
+
const serviceManager = new ServiceManager({ serverSettings });
|
|
104
|
+
// Wait for the service manager to be ready
|
|
105
|
+
await serviceManager.ready;
|
|
106
|
+
// Construct URLs
|
|
107
|
+
const jupyterBaseUrl = serverSettings.baseUrl;
|
|
108
|
+
const agentBaseUrl = jupyterBaseUrl.replace('/jupyter/server/', '/agent-runtimes/');
|
|
109
|
+
const connection = {
|
|
110
|
+
podName: runtimePod.pod_name,
|
|
111
|
+
environmentName: runtimePod.environment_name,
|
|
112
|
+
jupyterBaseUrl,
|
|
113
|
+
agentBaseUrl,
|
|
114
|
+
serviceManager,
|
|
115
|
+
status: 'ready',
|
|
116
|
+
};
|
|
117
|
+
set({
|
|
118
|
+
runtime: connection,
|
|
119
|
+
status: 'ready',
|
|
120
|
+
isLaunching: false,
|
|
121
|
+
});
|
|
122
|
+
return connection;
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
const errorMessage = err instanceof Error ? err.message : 'Failed to launch runtime';
|
|
126
|
+
set({
|
|
127
|
+
status: 'error',
|
|
128
|
+
error: errorMessage,
|
|
129
|
+
isLaunching: false,
|
|
130
|
+
});
|
|
131
|
+
throw err;
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
createAgent: async (config = {}) => {
|
|
135
|
+
const { runtime } = get();
|
|
136
|
+
if (!runtime) {
|
|
137
|
+
throw new Error('No runtime connected. Launch or connect to a runtime first.');
|
|
138
|
+
}
|
|
139
|
+
try {
|
|
140
|
+
const agentId = config.name || runtime.podName;
|
|
141
|
+
const agentConnection = await createAgentOnRuntime(runtime.agentBaseUrl, agentId, config);
|
|
142
|
+
set({ agent: agentConnection });
|
|
143
|
+
return agentConnection;
|
|
144
|
+
}
|
|
145
|
+
catch (err) {
|
|
146
|
+
const errorMessage = err instanceof Error ? err.message : 'Failed to create agent';
|
|
147
|
+
set({ error: errorMessage });
|
|
148
|
+
throw err;
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
disconnect: () => {
|
|
152
|
+
set({
|
|
153
|
+
runtime: null,
|
|
154
|
+
agent: null,
|
|
155
|
+
status: 'disconnected',
|
|
156
|
+
error: null,
|
|
157
|
+
});
|
|
158
|
+
},
|
|
159
|
+
clearError: () => {
|
|
160
|
+
set({ error: null });
|
|
161
|
+
},
|
|
162
|
+
setError: error => {
|
|
163
|
+
set({ error, status: 'error' });
|
|
164
|
+
},
|
|
165
|
+
reset: () => {
|
|
166
|
+
set(initialState);
|
|
167
|
+
},
|
|
168
|
+
}));
|
|
169
|
+
/**
|
|
170
|
+
* Selector hooks for common use cases.
|
|
171
|
+
*/
|
|
172
|
+
export const useRuntime = () => useRuntimeStore(state => state.runtime);
|
|
173
|
+
export const useAgent = () => useRuntimeStore(state => state.agent);
|
|
174
|
+
export const useRuntimeStatus = () => useRuntimeStore(state => state.status);
|
|
175
|
+
export const useRuntimeError = () => useRuntimeStore(state => state.error);
|
|
176
|
+
export const useIsLaunching = () => useRuntimeStore(state => state.isLaunching);
|
|
177
|
+
/**
|
|
178
|
+
* Get runtime store state without React (for use outside components).
|
|
179
|
+
*/
|
|
180
|
+
export const getRuntimeState = () => useRuntimeStore.getState();
|
|
181
|
+
/**
|
|
182
|
+
* Subscribe to runtime store changes (for use outside React).
|
|
183
|
+
*/
|
|
184
|
+
export const subscribeToRuntime = useRuntimeStore.subscribe;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for runtime management.
|
|
3
|
+
*
|
|
4
|
+
* Re-exports relevant types from @datalayer/core and defines
|
|
5
|
+
* agent-runtimes specific types for AI agent management.
|
|
6
|
+
*
|
|
7
|
+
* @module runtime/types
|
|
8
|
+
*/
|
|
9
|
+
import type { ServiceManager } from '@jupyterlab/services';
|
|
10
|
+
export type { IRuntimeLocation, IRuntimeType, IRuntimeCapabilities, IRuntimePod, IRuntimeDesc, } from '@datalayer/core/lib/models';
|
|
11
|
+
export type { IRuntimeOptions } from '@datalayer/core/lib/stateful/runtimes/apis';
|
|
12
|
+
/**
|
|
13
|
+
* Runtime connection status for the agent-runtimes store.
|
|
14
|
+
*/
|
|
15
|
+
export type AgentRuntimeStatus = 'idle' | 'launching' | 'connecting' | 'ready' | 'error' | 'disconnected';
|
|
16
|
+
/**
|
|
17
|
+
* Information about a connected runtime with agent-runtimes server.
|
|
18
|
+
* Extends the basic runtime info with URLs for both Jupyter and agent services.
|
|
19
|
+
*/
|
|
20
|
+
export interface RuntimeConnection {
|
|
21
|
+
/** Runtime pod name (unique identifier) */
|
|
22
|
+
podName: string;
|
|
23
|
+
/** Environment name */
|
|
24
|
+
environmentName: string;
|
|
25
|
+
/** Base URL for the Jupyter server */
|
|
26
|
+
jupyterBaseUrl: string;
|
|
27
|
+
/** Base URL for the agent-runtimes server */
|
|
28
|
+
agentBaseUrl: string;
|
|
29
|
+
/** JupyterLab ServiceManager for the runtime */
|
|
30
|
+
serviceManager: ServiceManager.IManager;
|
|
31
|
+
/** Runtime status */
|
|
32
|
+
status: AgentRuntimeStatus;
|
|
33
|
+
/** Kernel ID if connected */
|
|
34
|
+
kernelId?: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Configuration for creating an agent on a runtime.
|
|
38
|
+
*/
|
|
39
|
+
export interface AgentConfig {
|
|
40
|
+
/** Agent name/ID (defaults to runtime pod name) */
|
|
41
|
+
name?: string;
|
|
42
|
+
/** Agent description */
|
|
43
|
+
description?: string;
|
|
44
|
+
/** AI model to use (e.g., 'anthropic:claude-sonnet-4-5') */
|
|
45
|
+
model?: string;
|
|
46
|
+
/** System prompt for the agent */
|
|
47
|
+
systemPrompt?: string;
|
|
48
|
+
/** Agent library (defaults to 'pydantic-ai') */
|
|
49
|
+
agentLibrary?: 'pydantic-ai' | 'langchain' | 'openai';
|
|
50
|
+
/** Transport protocol (defaults to 'ag-ui') */
|
|
51
|
+
transport?: 'ag-ui' | 'vercel-ai' | 'acp' | 'a2a';
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Information about a connected agent.
|
|
55
|
+
*/
|
|
56
|
+
export interface AgentConnection {
|
|
57
|
+
/** Agent ID */
|
|
58
|
+
agentId: string;
|
|
59
|
+
/** Full endpoint URL for the agent */
|
|
60
|
+
endpoint: string;
|
|
61
|
+
/** Whether the agent is ready to use */
|
|
62
|
+
isReady: boolean;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Complete state for an agent runtime in the Zustand store.
|
|
66
|
+
*/
|
|
67
|
+
export interface AgentRuntimeState {
|
|
68
|
+
/** Runtime connection (null if not connected) */
|
|
69
|
+
runtime: RuntimeConnection | null;
|
|
70
|
+
/** Agent connection (null if not created) */
|
|
71
|
+
agent: AgentConnection | null;
|
|
72
|
+
/** Current status */
|
|
73
|
+
status: AgentRuntimeStatus;
|
|
74
|
+
/** Error message if any */
|
|
75
|
+
error: string | null;
|
|
76
|
+
/** Whether the runtime is launching */
|
|
77
|
+
isLaunching: boolean;
|
|
78
|
+
/** Whether the agent is ready */
|
|
79
|
+
isReady: boolean;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Default agent configuration values.
|
|
83
|
+
*/
|
|
84
|
+
export declare const DEFAULT_AGENT_CONFIG: Required<AgentConfig>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Default agent configuration values.
|
|
7
|
+
*/
|
|
8
|
+
export const DEFAULT_AGENT_CONFIG = {
|
|
9
|
+
name: 'ai-agent',
|
|
10
|
+
description: 'AI Assistant',
|
|
11
|
+
model: 'anthropic:claude-sonnet-4-5',
|
|
12
|
+
systemPrompt: 'You are a helpful AI assistant.',
|
|
13
|
+
agentLibrary: 'pydantic-ai',
|
|
14
|
+
transport: 'ag-ui',
|
|
15
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { AgentConfig, AgentConnection } from './types';
|
|
2
|
+
interface UseAgentConnectionOptions {
|
|
3
|
+
/** Agent configuration */
|
|
4
|
+
config?: AgentConfig;
|
|
5
|
+
/** Auto-create agent when runtime is ready */
|
|
6
|
+
autoCreate?: boolean;
|
|
7
|
+
}
|
|
8
|
+
interface UseAgentConnectionReturn {
|
|
9
|
+
/** Current agent connection */
|
|
10
|
+
agent: AgentConnection | null;
|
|
11
|
+
/** Whether the agent is ready */
|
|
12
|
+
isReady: boolean;
|
|
13
|
+
/** Whether agent creation is in progress */
|
|
14
|
+
isCreating: boolean;
|
|
15
|
+
/** Error message if any */
|
|
16
|
+
error: string | null;
|
|
17
|
+
/** Create an agent on the runtime */
|
|
18
|
+
create: (config?: AgentConfig) => Promise<AgentConnection>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Hook for creating and managing agent connections.
|
|
22
|
+
* Uses the Zustand store for runtime state.
|
|
23
|
+
*
|
|
24
|
+
* @param options - Configuration options
|
|
25
|
+
* @returns Agent state and control functions
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```tsx
|
|
29
|
+
* function MyComponent() {
|
|
30
|
+
* const { runtime } = useRuntimeStore();
|
|
31
|
+
* const { agent, isReady } = useAgentConnection({
|
|
32
|
+
* autoCreate: true,
|
|
33
|
+
* config: {
|
|
34
|
+
* model: 'anthropic:claude-sonnet-4-5',
|
|
35
|
+
* systemPrompt: 'You are a helpful assistant.',
|
|
36
|
+
* },
|
|
37
|
+
* });
|
|
38
|
+
*
|
|
39
|
+
* if (!isReady) return <div>Creating agent...</div>;
|
|
40
|
+
*
|
|
41
|
+
* return <ChatFloating endpoint={agent.endpoint} />;
|
|
42
|
+
* }
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export declare function useAgentConnection(options?: UseAgentConnectionOptions): UseAgentConnectionReturn;
|
|
46
|
+
export {};
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Hook for creating and managing agent connections on a runtime.
|
|
7
|
+
*
|
|
8
|
+
* @module runtime/useAgentConnection
|
|
9
|
+
*/
|
|
10
|
+
import { useState, useCallback, useEffect, useRef } from 'react';
|
|
11
|
+
import { useRuntimeStore } from './runtimeStore';
|
|
12
|
+
const DEFAULT_AGENT_CONFIG = {
|
|
13
|
+
model: 'anthropic:claude-sonnet-4-5',
|
|
14
|
+
systemPrompt: 'You are a helpful AI assistant.',
|
|
15
|
+
agentLibrary: 'pydantic-ai',
|
|
16
|
+
transport: 'ag-ui',
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Hook for creating and managing agent connections.
|
|
20
|
+
* Uses the Zustand store for runtime state.
|
|
21
|
+
*
|
|
22
|
+
* @param options - Configuration options
|
|
23
|
+
* @returns Agent state and control functions
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```tsx
|
|
27
|
+
* function MyComponent() {
|
|
28
|
+
* const { runtime } = useRuntimeStore();
|
|
29
|
+
* const { agent, isReady } = useAgentConnection({
|
|
30
|
+
* autoCreate: true,
|
|
31
|
+
* config: {
|
|
32
|
+
* model: 'anthropic:claude-sonnet-4-5',
|
|
33
|
+
* systemPrompt: 'You are a helpful assistant.',
|
|
34
|
+
* },
|
|
35
|
+
* });
|
|
36
|
+
*
|
|
37
|
+
* if (!isReady) return <div>Creating agent...</div>;
|
|
38
|
+
*
|
|
39
|
+
* return <ChatFloating endpoint={agent.endpoint} />;
|
|
40
|
+
* }
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export function useAgentConnection(options = {}) {
|
|
44
|
+
const { config, autoCreate = false } = options;
|
|
45
|
+
const runtime = useRuntimeStore(state => state.runtime);
|
|
46
|
+
const storeAgent = useRuntimeStore(state => state.agent);
|
|
47
|
+
const createStoreAgent = useRuntimeStore(state => state.createAgent);
|
|
48
|
+
const [isCreating, setIsCreating] = useState(false);
|
|
49
|
+
const [error, setError] = useState(null);
|
|
50
|
+
const creatingRef = useRef(false);
|
|
51
|
+
const createdForRuntimeRef = useRef(null);
|
|
52
|
+
const create = useCallback(async (overrideConfig) => {
|
|
53
|
+
if (!runtime) {
|
|
54
|
+
throw new Error('No runtime connected. Launch or connect to a runtime first.');
|
|
55
|
+
}
|
|
56
|
+
if (creatingRef.current) {
|
|
57
|
+
throw new Error('Agent creation already in progress');
|
|
58
|
+
}
|
|
59
|
+
creatingRef.current = true;
|
|
60
|
+
setIsCreating(true);
|
|
61
|
+
setError(null);
|
|
62
|
+
try {
|
|
63
|
+
// Merge configs: defaults < options.config < overrideConfig
|
|
64
|
+
const mergedConfig = {
|
|
65
|
+
...DEFAULT_AGENT_CONFIG,
|
|
66
|
+
...config,
|
|
67
|
+
...overrideConfig,
|
|
68
|
+
name: overrideConfig?.name || config?.name || runtime.podName,
|
|
69
|
+
};
|
|
70
|
+
const agentConnection = await createStoreAgent(mergedConfig);
|
|
71
|
+
createdForRuntimeRef.current = runtime.podName;
|
|
72
|
+
return agentConnection;
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
const errorMessage = err instanceof Error ? err.message : 'Failed to create agent';
|
|
76
|
+
setError(errorMessage);
|
|
77
|
+
throw err;
|
|
78
|
+
}
|
|
79
|
+
finally {
|
|
80
|
+
creatingRef.current = false;
|
|
81
|
+
setIsCreating(false);
|
|
82
|
+
}
|
|
83
|
+
}, [runtime, config, createStoreAgent]);
|
|
84
|
+
// Auto-create agent when runtime is ready (and not already created for this runtime)
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
if (autoCreate &&
|
|
87
|
+
runtime &&
|
|
88
|
+
runtime.status === 'ready' &&
|
|
89
|
+
!storeAgent &&
|
|
90
|
+
!creatingRef.current) {
|
|
91
|
+
// Only create if we haven't already created for this runtime
|
|
92
|
+
if (createdForRuntimeRef.current !== runtime.podName) {
|
|
93
|
+
create().catch(err => {
|
|
94
|
+
console.error('[useAgentConnection] Auto-create failed:', err);
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}, [autoCreate, runtime, storeAgent, create]);
|
|
99
|
+
// Reset created tracking when runtime changes
|
|
100
|
+
useEffect(() => {
|
|
101
|
+
if (!runtime) {
|
|
102
|
+
createdForRuntimeRef.current = null;
|
|
103
|
+
}
|
|
104
|
+
}, [runtime]);
|
|
105
|
+
return {
|
|
106
|
+
agent: storeAgent,
|
|
107
|
+
isReady: !!storeAgent?.isReady,
|
|
108
|
+
isCreating,
|
|
109
|
+
error,
|
|
110
|
+
create,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { ServiceManager } from '@jupyterlab/services';
|
|
2
|
+
import type { IRuntimeOptions, AgentConfig, RuntimeConnection, AgentConnection, AgentRuntimeStatus } from './types';
|
|
3
|
+
interface UseAgentRuntimeOptions {
|
|
4
|
+
/** Agent configuration */
|
|
5
|
+
agentConfig?: AgentConfig;
|
|
6
|
+
/** Auto-create agent when runtime connects */
|
|
7
|
+
autoCreateAgent?: boolean;
|
|
8
|
+
}
|
|
9
|
+
interface UseAgentRuntimeReturn {
|
|
10
|
+
/** Current runtime connection */
|
|
11
|
+
runtime: RuntimeConnection | null;
|
|
12
|
+
/** Current agent connection */
|
|
13
|
+
agent: AgentConnection | null;
|
|
14
|
+
/** Runtime status */
|
|
15
|
+
status: AgentRuntimeStatus;
|
|
16
|
+
/** Error message if any */
|
|
17
|
+
error: string | null;
|
|
18
|
+
/** Whether the runtime is launching */
|
|
19
|
+
isLaunching: boolean;
|
|
20
|
+
/** Whether everything is ready (runtime + agent) */
|
|
21
|
+
isReady: boolean;
|
|
22
|
+
/** Agent endpoint URL (shortcut) */
|
|
23
|
+
endpoint: string | null;
|
|
24
|
+
/** ServiceManager for the runtime */
|
|
25
|
+
serviceManager: ServiceManager.IManager | null;
|
|
26
|
+
/** Launch a new runtime */
|
|
27
|
+
launchRuntime: (options: IRuntimeOptions) => Promise<RuntimeConnection>;
|
|
28
|
+
/** Connect to an existing runtime */
|
|
29
|
+
connectToRuntime: (options: {
|
|
30
|
+
podName: string;
|
|
31
|
+
environmentName: string;
|
|
32
|
+
serviceManager: ServiceManager.IManager;
|
|
33
|
+
kernelId?: string;
|
|
34
|
+
}) => void;
|
|
35
|
+
/** Create an agent (if not auto-created) */
|
|
36
|
+
createAgent: (config?: AgentConfig) => Promise<AgentConnection>;
|
|
37
|
+
/** Disconnect from the runtime */
|
|
38
|
+
disconnect: () => void;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Combined hook for using a runtime with an AI agent.
|
|
42
|
+
*
|
|
43
|
+
* This hook provides everything needed to:
|
|
44
|
+
* 1. Connect to an existing runtime (or launch a new one)
|
|
45
|
+
* 2. Create an AI agent on the runtime
|
|
46
|
+
*
|
|
47
|
+
* Use this in conjunction with useNotebookTools or useLexicalTools
|
|
48
|
+
* for frontend tool execution.
|
|
49
|
+
*
|
|
50
|
+
* @param options - Configuration options
|
|
51
|
+
* @returns Complete agent runtime state and controls
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```tsx
|
|
55
|
+
* // For notebooks
|
|
56
|
+
* import { useAgentRuntime } from '@datalayer/agent-runtimes/lib/runtime';
|
|
57
|
+
* import { useNotebookTools } from '@datalayer/agent-runtimes/lib/tools/adapters/agent-runtimes';
|
|
58
|
+
*
|
|
59
|
+
* function NotebookEditor({ notebookId }) {
|
|
60
|
+
* const {
|
|
61
|
+
* isReady,
|
|
62
|
+
* endpoint,
|
|
63
|
+
* error,
|
|
64
|
+
* connectToRuntime,
|
|
65
|
+
* } = useAgentRuntime({
|
|
66
|
+
* autoCreateAgent: true,
|
|
67
|
+
* agentConfig: {
|
|
68
|
+
* model: 'anthropic:claude-sonnet-4-5',
|
|
69
|
+
* systemPrompt: 'You help users with Jupyter notebooks.',
|
|
70
|
+
* },
|
|
71
|
+
* });
|
|
72
|
+
*
|
|
73
|
+
* // Get tools separately
|
|
74
|
+
* const tools = useNotebookTools(notebookId);
|
|
75
|
+
*
|
|
76
|
+
* // Connect when user assigns a runtime
|
|
77
|
+
* const onRuntimeAssigned = (serviceManager, podName, poolName) => {
|
|
78
|
+
* connectToRuntime({ serviceManager, podName, jupyterpoolName: poolName });
|
|
79
|
+
* };
|
|
80
|
+
*
|
|
81
|
+
* return (
|
|
82
|
+
* <>
|
|
83
|
+
* <Notebook />
|
|
84
|
+
* {isReady && (
|
|
85
|
+
* <ChatFloating endpoint={endpoint} tools={tools} />
|
|
86
|
+
* )}
|
|
87
|
+
* {error && <ErrorBanner>{error}</ErrorBanner>}
|
|
88
|
+
* </>
|
|
89
|
+
* );
|
|
90
|
+
* }
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
export declare function useAgentRuntime(options?: UseAgentRuntimeOptions): UseAgentRuntimeReturn;
|
|
94
|
+
export {};
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Combined hook for using a runtime with an AI agent.
|
|
7
|
+
*
|
|
8
|
+
* This is the main entry point for consumers who want a simple,
|
|
9
|
+
* all-in-one solution for cloud runtime + agent management.
|
|
10
|
+
*
|
|
11
|
+
* @module runtime/useAgentRuntime
|
|
12
|
+
*/
|
|
13
|
+
import { useEffect, useRef, useCallback } from 'react';
|
|
14
|
+
import { useRuntimeStore, useRuntime, useAgent, useRuntimeStatus, useRuntimeError, useIsLaunching, } from './runtimeStore';
|
|
15
|
+
/**
|
|
16
|
+
* Combined hook for using a runtime with an AI agent.
|
|
17
|
+
*
|
|
18
|
+
* This hook provides everything needed to:
|
|
19
|
+
* 1. Connect to an existing runtime (or launch a new one)
|
|
20
|
+
* 2. Create an AI agent on the runtime
|
|
21
|
+
*
|
|
22
|
+
* Use this in conjunction with useNotebookTools or useLexicalTools
|
|
23
|
+
* for frontend tool execution.
|
|
24
|
+
*
|
|
25
|
+
* @param options - Configuration options
|
|
26
|
+
* @returns Complete agent runtime state and controls
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```tsx
|
|
30
|
+
* // For notebooks
|
|
31
|
+
* import { useAgentRuntime } from '@datalayer/agent-runtimes/lib/runtime';
|
|
32
|
+
* import { useNotebookTools } from '@datalayer/agent-runtimes/lib/tools/adapters/agent-runtimes';
|
|
33
|
+
*
|
|
34
|
+
* function NotebookEditor({ notebookId }) {
|
|
35
|
+
* const {
|
|
36
|
+
* isReady,
|
|
37
|
+
* endpoint,
|
|
38
|
+
* error,
|
|
39
|
+
* connectToRuntime,
|
|
40
|
+
* } = useAgentRuntime({
|
|
41
|
+
* autoCreateAgent: true,
|
|
42
|
+
* agentConfig: {
|
|
43
|
+
* model: 'anthropic:claude-sonnet-4-5',
|
|
44
|
+
* systemPrompt: 'You help users with Jupyter notebooks.',
|
|
45
|
+
* },
|
|
46
|
+
* });
|
|
47
|
+
*
|
|
48
|
+
* // Get tools separately
|
|
49
|
+
* const tools = useNotebookTools(notebookId);
|
|
50
|
+
*
|
|
51
|
+
* // Connect when user assigns a runtime
|
|
52
|
+
* const onRuntimeAssigned = (serviceManager, podName, poolName) => {
|
|
53
|
+
* connectToRuntime({ serviceManager, podName, jupyterpoolName: poolName });
|
|
54
|
+
* };
|
|
55
|
+
*
|
|
56
|
+
* return (
|
|
57
|
+
* <>
|
|
58
|
+
* <Notebook />
|
|
59
|
+
* {isReady && (
|
|
60
|
+
* <ChatFloating endpoint={endpoint} tools={tools} />
|
|
61
|
+
* )}
|
|
62
|
+
* {error && <ErrorBanner>{error}</ErrorBanner>}
|
|
63
|
+
* </>
|
|
64
|
+
* );
|
|
65
|
+
* }
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export function useAgentRuntime(options = {}) {
|
|
69
|
+
const { agentConfig, autoCreateAgent = true } = options;
|
|
70
|
+
// Get store state
|
|
71
|
+
const runtime = useRuntime();
|
|
72
|
+
const agent = useAgent();
|
|
73
|
+
const status = useRuntimeStatus();
|
|
74
|
+
const error = useRuntimeError();
|
|
75
|
+
const isLaunching = useIsLaunching();
|
|
76
|
+
// Get store actions
|
|
77
|
+
const launchRuntime = useRuntimeStore(state => state.launchRuntime);
|
|
78
|
+
const connectToRuntime = useRuntimeStore(state => state.connectToRuntime);
|
|
79
|
+
const disconnect = useRuntimeStore(state => state.disconnect);
|
|
80
|
+
const createAgentAction = useRuntimeStore(state => state.createAgent);
|
|
81
|
+
// Track if we've created the agent to prevent duplicates
|
|
82
|
+
const hasCreatedAgentRef = useRef(false);
|
|
83
|
+
const agentConfigRef = useRef(agentConfig);
|
|
84
|
+
agentConfigRef.current = agentConfig;
|
|
85
|
+
// Auto-create agent when runtime is ready
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
if (autoCreateAgent &&
|
|
88
|
+
runtime &&
|
|
89
|
+
status === 'ready' &&
|
|
90
|
+
!agent &&
|
|
91
|
+
!hasCreatedAgentRef.current) {
|
|
92
|
+
hasCreatedAgentRef.current = true;
|
|
93
|
+
createAgentAction(agentConfigRef.current).catch(err => {
|
|
94
|
+
console.error('[useAgentRuntime] Failed to auto-create agent:', err);
|
|
95
|
+
hasCreatedAgentRef.current = false;
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}, [autoCreateAgent, runtime, status, agent, createAgentAction]);
|
|
99
|
+
// Reset agent creation tracking on disconnect
|
|
100
|
+
useEffect(() => {
|
|
101
|
+
if (status === 'disconnected' || status === 'idle') {
|
|
102
|
+
hasCreatedAgentRef.current = false;
|
|
103
|
+
}
|
|
104
|
+
}, [status]);
|
|
105
|
+
// Memoized create agent function
|
|
106
|
+
const createAgent = useCallback((config) => createAgentAction(config || agentConfig), [createAgentAction, agentConfig]);
|
|
107
|
+
// Derived state
|
|
108
|
+
const isReady = status === 'ready' && !!agent?.isReady;
|
|
109
|
+
const endpoint = agent?.endpoint || null;
|
|
110
|
+
const serviceManager = runtime?.serviceManager || null;
|
|
111
|
+
return {
|
|
112
|
+
runtime,
|
|
113
|
+
agent,
|
|
114
|
+
status,
|
|
115
|
+
error,
|
|
116
|
+
isLaunching,
|
|
117
|
+
isReady,
|
|
118
|
+
endpoint,
|
|
119
|
+
serviceManager,
|
|
120
|
+
launchRuntime,
|
|
121
|
+
connectToRuntime,
|
|
122
|
+
createAgent,
|
|
123
|
+
disconnect,
|
|
124
|
+
};
|
|
125
|
+
}
|
package/lib/test-setup.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
import '@testing-library/jest-dom/vitest';
|
package/lib/test-setup.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
// Test setup for unit tests
|
|
6
6
|
// Add any global test configuration here
|
|
7
|
+
import '@testing-library/jest-dom/vitest';
|
|
7
8
|
// Define webpack globals that are expected by some dependencies
|
|
8
9
|
global.__webpack_public_path__ = '';
|
|
9
10
|
// Native FormData and fetch should work in Node.js 20+
|