@datalayer/agent-runtimes 0.0.3 → 0.0.4
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/lib/components/chat/protocols/VercelAIAdapter.d.ts +2 -0
- package/lib/components/chat/protocols/VercelAIAdapter.js +5 -0
- package/lib/examples/AgentRuntimeCustomExample.d.ts +2 -1
- package/lib/examples/AgentRuntimeCustomExample.js +120 -5
- package/lib/hooks/useNotebookAIAgent.d.ts +2 -2
- package/lib/hooks/useNotebookAIAgent.js +26 -9
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/state/substates/AIAgentState.d.ts +80 -10
- package/lib/state/substates/AIAgentState.js +89 -23
- package/package.json +7 -7
|
@@ -61,6 +61,8 @@ export declare class VercelAIAdapter extends BaseProtocolAdapter {
|
|
|
61
61
|
model?: string;
|
|
62
62
|
/** Full conversation history to send with the message */
|
|
63
63
|
messages?: ChatMessage[];
|
|
64
|
+
/** Builtin tools / MCP tools to enable for this request */
|
|
65
|
+
builtinTools?: string[];
|
|
64
66
|
}): Promise<void>;
|
|
65
67
|
/**
|
|
66
68
|
* Parse SSE stream from Vercel AI
|
|
@@ -107,6 +107,11 @@ export class VercelAIAdapter extends BaseProtocolAdapter {
|
|
|
107
107
|
...(options?.tools && { tools: options.tools }),
|
|
108
108
|
// Model override for per-request model selection
|
|
109
109
|
...(options?.model && { model: options.model }),
|
|
110
|
+
// Builtin tools / MCP tools to enable
|
|
111
|
+
...(options?.builtinTools &&
|
|
112
|
+
options.builtinTools.length > 0 && {
|
|
113
|
+
builtinTools: options.builtinTools,
|
|
114
|
+
}),
|
|
110
115
|
};
|
|
111
116
|
if (options?.model) {
|
|
112
117
|
console.log('[VercelAIAdapter] Sending with model:', options.model);
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Agent Runtime Custom Example Component
|
|
3
3
|
*
|
|
4
|
-
* Demonstrates the unified Chat component with
|
|
4
|
+
* Demonstrates the unified Chat component with AG-UI transport
|
|
5
5
|
* and all necessary providers:
|
|
6
6
|
* - QueryClientProvider for data fetching
|
|
7
|
+
* - Auto-creates agent on the server if it doesn't exist
|
|
7
8
|
*/
|
|
8
9
|
declare const AgentRuntimeCustomExample: React.FC;
|
|
9
10
|
export default AgentRuntimeCustomExample;
|
|
@@ -3,7 +3,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
4
4
|
* Distributed under the terms of the Modified BSD License.
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
6
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
7
|
+
import { Spinner, Text } from '@primer/react';
|
|
7
8
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
8
9
|
import { Box } from '@datalayer/primer-addons';
|
|
9
10
|
import { datalayerTheme, DatalayerThemeProvider } from '@datalayer/core';
|
|
@@ -19,14 +20,107 @@ const queryClient = new QueryClient({
|
|
|
19
20
|
},
|
|
20
21
|
},
|
|
21
22
|
});
|
|
23
|
+
const AGENT_NAME = 'datalayer-assistant';
|
|
24
|
+
const BASE_URL = 'http://localhost:8765';
|
|
25
|
+
/**
|
|
26
|
+
* Hook to ensure the agent exists on the server
|
|
27
|
+
* Creates the agent if it doesn't exist
|
|
28
|
+
*/
|
|
29
|
+
function useEnsureAgent() {
|
|
30
|
+
const [agentId, setAgentId] = useState(null);
|
|
31
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
32
|
+
const [error, setError] = useState(null);
|
|
33
|
+
const createAgent = useCallback(async () => {
|
|
34
|
+
try {
|
|
35
|
+
const response = await fetch(`${BASE_URL}/api/v1/agents`, {
|
|
36
|
+
method: 'POST',
|
|
37
|
+
headers: {
|
|
38
|
+
'Content-Type': 'application/json',
|
|
39
|
+
},
|
|
40
|
+
body: JSON.stringify({
|
|
41
|
+
name: AGENT_NAME,
|
|
42
|
+
description: 'Datalayer AI Assistant - Your helpful coding companion',
|
|
43
|
+
agent_library: 'pydantic-ai',
|
|
44
|
+
transport: 'ag-ui',
|
|
45
|
+
model: 'openai:gpt-4o-mini',
|
|
46
|
+
system_prompt: `You are Datalayer Assistant, a helpful AI assistant specialized in data science, Python programming, and Jupyter notebooks.
|
|
47
|
+
|
|
48
|
+
You can help users with:
|
|
49
|
+
- Writing and debugging Python code
|
|
50
|
+
- Data analysis with pandas, numpy, and other libraries
|
|
51
|
+
- Creating visualizations with matplotlib, plotly, etc.
|
|
52
|
+
- Machine learning with scikit-learn, pytorch, etc.
|
|
53
|
+
- General programming questions
|
|
54
|
+
|
|
55
|
+
Be concise, helpful, and provide working code examples when appropriate.`,
|
|
56
|
+
}),
|
|
57
|
+
});
|
|
58
|
+
if (!response.ok) {
|
|
59
|
+
const errorData = await response
|
|
60
|
+
.json()
|
|
61
|
+
.catch(() => ({ detail: 'Unknown error' }));
|
|
62
|
+
throw new Error(errorData.detail || `Failed to create agent: ${response.status}`);
|
|
63
|
+
}
|
|
64
|
+
const data = await response.json();
|
|
65
|
+
console.log('[AgentRuntimeCustomExample] Agent created:', data);
|
|
66
|
+
return data.id;
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
console.error('[AgentRuntimeCustomExample] Error creating agent:', err);
|
|
70
|
+
throw err;
|
|
71
|
+
}
|
|
72
|
+
}, []);
|
|
73
|
+
const checkOrCreateAgent = useCallback(async () => {
|
|
74
|
+
setIsLoading(true);
|
|
75
|
+
setError(null);
|
|
76
|
+
try {
|
|
77
|
+
// First, try to find existing agent by name
|
|
78
|
+
const listResponse = await fetch(`${BASE_URL}/api/v1/agents`);
|
|
79
|
+
if (listResponse.ok) {
|
|
80
|
+
const data = await listResponse.json();
|
|
81
|
+
// API may return { agents: [...] } or just [...]
|
|
82
|
+
const agents = Array.isArray(data) ? data : data.agents || [];
|
|
83
|
+
const existingAgent = agents.find((a) => a.name === AGENT_NAME);
|
|
84
|
+
if (existingAgent) {
|
|
85
|
+
console.log('[AgentRuntimeCustomExample] Found existing agent:', existingAgent.id);
|
|
86
|
+
setAgentId(existingAgent.id);
|
|
87
|
+
setIsLoading(false);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// Agent doesn't exist, create it
|
|
92
|
+
console.log('[AgentRuntimeCustomExample] Creating new agent...');
|
|
93
|
+
const newAgentId = await createAgent();
|
|
94
|
+
if (newAgentId) {
|
|
95
|
+
setAgentId(newAgentId);
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
setError('Failed to create agent');
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
const errorMessage = err instanceof Error ? err.message : 'Failed to initialize agent';
|
|
103
|
+
setError(errorMessage);
|
|
104
|
+
}
|
|
105
|
+
finally {
|
|
106
|
+
setIsLoading(false);
|
|
107
|
+
}
|
|
108
|
+
}, [createAgent]);
|
|
109
|
+
useEffect(() => {
|
|
110
|
+
checkOrCreateAgent();
|
|
111
|
+
}, [checkOrCreateAgent]);
|
|
112
|
+
return { agentId, isLoading, error, retry: checkOrCreateAgent };
|
|
113
|
+
}
|
|
22
114
|
/**
|
|
23
115
|
* Agent Runtime Custom Example Component
|
|
24
116
|
*
|
|
25
|
-
* Demonstrates the unified Chat component with
|
|
117
|
+
* Demonstrates the unified Chat component with AG-UI transport
|
|
26
118
|
* and all necessary providers:
|
|
27
119
|
* - QueryClientProvider for data fetching
|
|
120
|
+
* - Auto-creates agent on the server if it doesn't exist
|
|
28
121
|
*/
|
|
29
122
|
const AgentRuntimeCustomExample = () => {
|
|
123
|
+
const { agentId, isLoading, error, retry } = useEnsureAgent();
|
|
30
124
|
return (_jsx(QueryClientProvider, { client: queryClient, children: _jsx(DatalayerThemeProvider, { theme: datalayerTheme, children: _jsxs(Box, { sx: {
|
|
31
125
|
display: 'flex',
|
|
32
126
|
flexDirection: 'column',
|
|
@@ -41,12 +135,33 @@ const AgentRuntimeCustomExample = () => {
|
|
|
41
135
|
fontWeight: 'bold',
|
|
42
136
|
display: 'block',
|
|
43
137
|
marginBottom: 1,
|
|
44
|
-
}, children: "
|
|
138
|
+
}, children: "Datalayer Assistant" }), _jsx(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: "Interactive chat interface with AI assistance" })] }), _jsx(Box, { as: "main", sx: {
|
|
45
139
|
flex: 1,
|
|
46
140
|
overflow: 'hidden',
|
|
47
141
|
display: 'flex',
|
|
48
142
|
flexDirection: 'column',
|
|
49
|
-
}, children:
|
|
143
|
+
}, children: isLoading ? (_jsxs(Box, { sx: {
|
|
144
|
+
display: 'flex',
|
|
145
|
+
flexDirection: 'column',
|
|
146
|
+
alignItems: 'center',
|
|
147
|
+
justifyContent: 'center',
|
|
148
|
+
height: '100%',
|
|
149
|
+
gap: 3,
|
|
150
|
+
}, children: [_jsx(Spinner, { size: "large" }), _jsx(Text, { sx: { color: 'fg.muted' }, children: "Initializing agent..." })] })) : error ? (_jsxs(Box, { sx: {
|
|
151
|
+
display: 'flex',
|
|
152
|
+
flexDirection: 'column',
|
|
153
|
+
alignItems: 'center',
|
|
154
|
+
justifyContent: 'center',
|
|
155
|
+
height: '100%',
|
|
156
|
+
gap: 3,
|
|
157
|
+
p: 4,
|
|
158
|
+
}, children: [_jsx(Text, { sx: { color: 'danger.fg', fontWeight: 'bold' }, children: "Failed to initialize agent" }), _jsx(Text, { sx: { color: 'fg.muted', textAlign: 'center' }, children: error }), _jsx(Text, { as: "button", onClick: retry, sx: {
|
|
159
|
+
color: 'accent.fg',
|
|
160
|
+
cursor: 'pointer',
|
|
161
|
+
textDecoration: 'underline',
|
|
162
|
+
border: 'none',
|
|
163
|
+
background: 'none',
|
|
164
|
+
}, children: "Retry" })] })) : agentId ? (_jsx(Chat, { transport: "ag-ui", agentId: agentId, showModelSelector: true, showToolsMenu: true, height: "100%", suggestions: [
|
|
50
165
|
{
|
|
51
166
|
title: '👋 Say hello',
|
|
52
167
|
message: 'Hello! What can you help me with today?',
|
|
@@ -63,6 +178,6 @@ const AgentRuntimeCustomExample = () => {
|
|
|
63
178
|
title: '📊 Data analysis',
|
|
64
179
|
message: 'How do I analyze data with pandas?',
|
|
65
180
|
},
|
|
66
|
-
] }) })] }) }) }));
|
|
181
|
+
] })) : null })] }) }) }));
|
|
67
182
|
};
|
|
68
183
|
export default AgentRuntimeCustomExample;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Agent } from '../state';
|
|
2
2
|
/**
|
|
3
3
|
* Get the document AI Agent if any.
|
|
4
4
|
*
|
|
5
5
|
* It handles checking the AI Agent is alive so it should only be use once per document.
|
|
6
6
|
*/
|
|
7
|
-
export declare function useNotebookAIAgent(notebookId: string):
|
|
7
|
+
export declare function useNotebookAIAgent(notebookId: string): Agent | undefined;
|
|
8
8
|
export default useNotebookAIAgent;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Distributed under the terms of the Modified BSD License.
|
|
4
4
|
*/
|
|
5
5
|
import { useEffect } from 'react';
|
|
6
|
-
import {
|
|
6
|
+
import { useAgentStore } from '../state';
|
|
7
7
|
import { useAIAgents } from './useAgents';
|
|
8
8
|
/**
|
|
9
9
|
* Get the document AI Agent if any.
|
|
@@ -12,7 +12,10 @@ import { useAIAgents } from './useAgents';
|
|
|
12
12
|
*/
|
|
13
13
|
export function useNotebookAIAgent(notebookId) {
|
|
14
14
|
const { getAIAgent } = useAIAgents();
|
|
15
|
-
const
|
|
15
|
+
const agents = useAgentStore(state => state.agents);
|
|
16
|
+
const upsertAgent = useAgentStore(state => state.upsertAgent);
|
|
17
|
+
const deleteAgent = useAgentStore(state => state.deleteAgent);
|
|
18
|
+
const getAgentById = useAgentStore(state => state.getAgentById);
|
|
16
19
|
// Check AI Agent is alive.
|
|
17
20
|
useEffect(() => {
|
|
18
21
|
let abortController;
|
|
@@ -23,25 +26,39 @@ export function useNotebookAIAgent(notebookId) {
|
|
|
23
26
|
signal: abortController.signal,
|
|
24
27
|
});
|
|
25
28
|
if (!response.success) {
|
|
26
|
-
|
|
29
|
+
deleteAgent(notebookId);
|
|
27
30
|
return;
|
|
28
31
|
}
|
|
29
|
-
const currentAgent =
|
|
32
|
+
const currentAgent = getAgentById(notebookId);
|
|
30
33
|
const runtimeId = response.agent.runtime?.id;
|
|
31
34
|
if (currentAgent) {
|
|
35
|
+
// Update existing agent if runtime changed
|
|
32
36
|
if (currentAgent.runtimeId !== runtimeId) {
|
|
33
|
-
|
|
37
|
+
upsertAgent({
|
|
38
|
+
id: notebookId,
|
|
39
|
+
baseUrl: currentAgent.baseUrl,
|
|
40
|
+
transport: currentAgent.transport,
|
|
41
|
+
runtimeId,
|
|
42
|
+
status: 'running',
|
|
43
|
+
});
|
|
34
44
|
}
|
|
35
45
|
}
|
|
36
46
|
else {
|
|
37
|
-
|
|
47
|
+
// Add new agent - assume it's a notebook agent with document tracking
|
|
48
|
+
upsertAgent({
|
|
49
|
+
id: notebookId,
|
|
50
|
+
name: `Notebook ${notebookId}`,
|
|
51
|
+
description: 'AI agent for notebook',
|
|
52
|
+
baseUrl: '', // Will be set by the actual agent implementation
|
|
53
|
+
transport: 'vercel-ai', // Default transport for notebook agents
|
|
38
54
|
documentId: notebookId,
|
|
39
55
|
runtimeId,
|
|
56
|
+
status: 'running',
|
|
40
57
|
});
|
|
41
58
|
}
|
|
42
59
|
}
|
|
43
60
|
catch (r) {
|
|
44
|
-
|
|
61
|
+
deleteAgent(notebookId);
|
|
45
62
|
}
|
|
46
63
|
};
|
|
47
64
|
const refreshInterval = setInterval(refreshAIAgent, 60_000);
|
|
@@ -49,8 +66,8 @@ export function useNotebookAIAgent(notebookId) {
|
|
|
49
66
|
abortController?.abort('Component unmounted');
|
|
50
67
|
clearInterval(refreshInterval);
|
|
51
68
|
};
|
|
52
|
-
}, [
|
|
53
|
-
const aiAgent =
|
|
69
|
+
}, [agents, notebookId, getAIAgent, deleteAgent, getAgentById, upsertAgent]);
|
|
70
|
+
const aiAgent = getAgentById(notebookId);
|
|
54
71
|
return aiAgent;
|
|
55
72
|
}
|
|
56
73
|
export default useNotebookAIAgent;
|
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -1,11 +1,81 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export type
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import type { Transport } from '../../components/chat/components/Chat';
|
|
2
|
+
export type AgentStatus = 'running' | 'paused' | 'initializing' | 'error';
|
|
3
|
+
export type { Transport };
|
|
4
|
+
/**
|
|
5
|
+
* Unified Agent model combining runtime tracking and UI state
|
|
6
|
+
*/
|
|
7
|
+
export interface Agent {
|
|
8
|
+
/** Unique agent identifier */
|
|
9
|
+
id: string;
|
|
10
|
+
/** Display name */
|
|
11
|
+
name: string;
|
|
12
|
+
/** Agent description */
|
|
13
|
+
description: string;
|
|
14
|
+
/** Base URL for the agent (for Jupyter: baseUrl, for FastAPI: baseUrl) */
|
|
15
|
+
baseUrl: string;
|
|
16
|
+
/** Transport protocol used */
|
|
17
|
+
transport: Transport;
|
|
18
|
+
/** Current status */
|
|
19
|
+
status: AgentStatus;
|
|
20
|
+
/** Last error message if status is 'error' */
|
|
21
|
+
error?: string | null;
|
|
22
|
+
/** Timestamp of last update */
|
|
23
|
+
lastUpdated: number;
|
|
24
|
+
/** Document ID (for document-based agents) */
|
|
25
|
+
documentId?: string;
|
|
26
|
+
/** Runtime ID (for Jupyter kernel-based agents) */
|
|
27
|
+
runtimeId?: string;
|
|
28
|
+
/** Author name (optional, for display) */
|
|
29
|
+
author?: string;
|
|
30
|
+
/** Avatar URL (optional, for display) */
|
|
31
|
+
avatarUrl?: string;
|
|
32
|
+
}
|
|
33
|
+
export type AgentState = {
|
|
34
|
+
/** All registered agents */
|
|
35
|
+
agents: readonly Agent[];
|
|
36
|
+
/** Add or update an agent */
|
|
37
|
+
upsertAgent: (agent: Partial<Agent> & {
|
|
38
|
+
id: string;
|
|
39
|
+
baseUrl: string;
|
|
40
|
+
transport: Transport;
|
|
41
|
+
}) => void;
|
|
42
|
+
/** Get agent by ID */
|
|
43
|
+
getAgentById: (id: string) => Agent | undefined;
|
|
44
|
+
/** Get agent by baseUrl and transport */
|
|
45
|
+
getAgentByUrl: (baseUrl: string, transport: Transport) => Agent | undefined;
|
|
46
|
+
/** Update agent status */
|
|
47
|
+
updateAgentStatus: (id: string, status: AgentStatus, error?: string | null) => void;
|
|
48
|
+
/** Toggle agent status between running/paused */
|
|
49
|
+
toggleAgentStatus: (id: string) => void;
|
|
50
|
+
/** Delete an agent */
|
|
51
|
+
deleteAgent: (id: string) => void;
|
|
52
|
+
/** Clear all agents */
|
|
53
|
+
clearAgents: () => void;
|
|
7
54
|
};
|
|
8
|
-
export declare const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
55
|
+
export declare const agentStore: Omit<import("zustand").StoreApi<AgentState>, "persist"> & {
|
|
56
|
+
persist: {
|
|
57
|
+
setOptions: (options: Partial<import("zustand/middleware").PersistOptions<AgentState, unknown>>) => void;
|
|
58
|
+
clearStorage: () => void;
|
|
59
|
+
rehydrate: () => Promise<void> | void;
|
|
60
|
+
hasHydrated: () => boolean;
|
|
61
|
+
onHydrate: (fn: (state: AgentState) => void) => () => void;
|
|
62
|
+
onFinishHydration: (fn: (state: AgentState) => void) => () => void;
|
|
63
|
+
getOptions: () => Partial<import("zustand/middleware").PersistOptions<AgentState, unknown>>;
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
export declare function useAgentStore(): AgentState;
|
|
67
|
+
export declare function useAgentStore<T>(selector: (state: AgentState) => T): T;
|
|
68
|
+
export type AIAgentState = AgentState;
|
|
69
|
+
export declare const aiAgentStore: Omit<import("zustand").StoreApi<AgentState>, "persist"> & {
|
|
70
|
+
persist: {
|
|
71
|
+
setOptions: (options: Partial<import("zustand/middleware").PersistOptions<AgentState, unknown>>) => void;
|
|
72
|
+
clearStorage: () => void;
|
|
73
|
+
rehydrate: () => Promise<void> | void;
|
|
74
|
+
hasHydrated: () => boolean;
|
|
75
|
+
onHydrate: (fn: (state: AgentState) => void) => () => void;
|
|
76
|
+
onFinishHydration: (fn: (state: AgentState) => void) => () => void;
|
|
77
|
+
getOptions: () => Partial<import("zustand/middleware").PersistOptions<AgentState, unknown>>;
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
export declare const useAIAgentStore: typeof useAgentStore;
|
|
81
|
+
export default useAgentStore;
|
|
@@ -4,39 +4,105 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { createStore } from 'zustand/vanilla';
|
|
6
6
|
import { useStore } from 'zustand';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
import { persist, createJSONStorage } from 'zustand/middleware';
|
|
8
|
+
export const agentStore = createStore()(persist((set, get) => ({
|
|
9
|
+
agents: [],
|
|
10
|
+
upsertAgent: agentData => {
|
|
11
|
+
set(state => {
|
|
12
|
+
const existingIndex = state.agents.findIndex(a => a.id === agentData.id);
|
|
13
|
+
const now = Date.now();
|
|
14
|
+
if (existingIndex >= 0) {
|
|
15
|
+
// Update existing agent
|
|
16
|
+
const updatedAgents = [...state.agents];
|
|
17
|
+
updatedAgents[existingIndex] = {
|
|
18
|
+
...updatedAgents[existingIndex],
|
|
19
|
+
...agentData,
|
|
20
|
+
lastUpdated: now,
|
|
21
|
+
};
|
|
22
|
+
return { agents: updatedAgents };
|
|
13
23
|
}
|
|
14
24
|
else {
|
|
15
|
-
|
|
25
|
+
// Add new agent
|
|
26
|
+
const newAgent = {
|
|
27
|
+
name: agentData.name || agentData.id,
|
|
28
|
+
description: agentData.description || '',
|
|
29
|
+
status: agentData.status || 'initializing',
|
|
30
|
+
lastUpdated: now,
|
|
31
|
+
...agentData,
|
|
32
|
+
};
|
|
33
|
+
return { agents: [...state.agents, newAgent] };
|
|
16
34
|
}
|
|
17
35
|
});
|
|
18
36
|
},
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
});
|
|
37
|
+
getAgentById: (id) => {
|
|
38
|
+
const { agents } = get();
|
|
39
|
+
return agents.find(agent => agent.id === id);
|
|
40
|
+
},
|
|
41
|
+
getAgentByUrl: (baseUrl, transport) => {
|
|
42
|
+
const { agents } = get();
|
|
43
|
+
return agents.find(agent => agent.baseUrl === baseUrl && agent.transport === transport);
|
|
25
44
|
},
|
|
26
|
-
|
|
27
|
-
set(
|
|
28
|
-
const index = state.
|
|
45
|
+
updateAgentStatus: (id, status, error = null) => {
|
|
46
|
+
set(state => {
|
|
47
|
+
const index = state.agents.findIndex(a => a.id === id);
|
|
29
48
|
if (index >= 0) {
|
|
30
|
-
state.
|
|
31
|
-
|
|
49
|
+
const updatedAgents = [...state.agents];
|
|
50
|
+
updatedAgents[index] = {
|
|
51
|
+
...updatedAgents[index],
|
|
52
|
+
status,
|
|
53
|
+
error,
|
|
54
|
+
lastUpdated: Date.now(),
|
|
55
|
+
};
|
|
56
|
+
return { agents: updatedAgents };
|
|
32
57
|
}
|
|
33
|
-
|
|
34
|
-
|
|
58
|
+
return {};
|
|
59
|
+
});
|
|
60
|
+
},
|
|
61
|
+
toggleAgentStatus: (id) => {
|
|
62
|
+
set(state => {
|
|
63
|
+
const index = state.agents.findIndex(a => a.id === id);
|
|
64
|
+
if (index >= 0) {
|
|
65
|
+
const updatedAgents = [...state.agents];
|
|
66
|
+
const currentStatus = updatedAgents[index].status;
|
|
67
|
+
updatedAgents[index] = {
|
|
68
|
+
...updatedAgents[index],
|
|
69
|
+
status: currentStatus === 'running' ? 'paused' : 'running',
|
|
70
|
+
lastUpdated: Date.now(),
|
|
71
|
+
};
|
|
72
|
+
return { agents: updatedAgents };
|
|
35
73
|
}
|
|
74
|
+
return {};
|
|
36
75
|
});
|
|
37
76
|
},
|
|
77
|
+
deleteAgent: (id) => {
|
|
78
|
+
set(state => ({
|
|
79
|
+
agents: state.agents.filter(a => a.id !== id),
|
|
80
|
+
}));
|
|
81
|
+
},
|
|
82
|
+
clearAgents: () => {
|
|
83
|
+
set({ agents: [] });
|
|
84
|
+
},
|
|
85
|
+
}), {
|
|
86
|
+
name: 'agent-runtimes-storage',
|
|
87
|
+
storage: createJSONStorage(() => localStorage),
|
|
88
|
+
// Only persist essential fields
|
|
89
|
+
partialize: state => ({
|
|
90
|
+
agents: state.agents.map(agent => ({
|
|
91
|
+
id: agent.id,
|
|
92
|
+
name: agent.name,
|
|
93
|
+
description: agent.description,
|
|
94
|
+
baseUrl: agent.baseUrl,
|
|
95
|
+
transport: agent.transport,
|
|
96
|
+
status: agent.status,
|
|
97
|
+
lastUpdated: agent.lastUpdated,
|
|
98
|
+
documentId: agent.documentId,
|
|
99
|
+
runtimeId: agent.runtimeId,
|
|
100
|
+
})),
|
|
101
|
+
}),
|
|
38
102
|
}));
|
|
39
|
-
export function
|
|
40
|
-
return useStore(
|
|
103
|
+
export function useAgentStore(selector) {
|
|
104
|
+
return useStore(agentStore, selector);
|
|
41
105
|
}
|
|
42
|
-
export
|
|
106
|
+
export const aiAgentStore = agentStore;
|
|
107
|
+
export const useAIAgentStore = useAgentStore;
|
|
108
|
+
export default useAgentStore;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datalayer/agent-runtimes",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"workspaces": [
|
|
6
6
|
".",
|
|
@@ -118,7 +118,7 @@
|
|
|
118
118
|
"@ag-ui/encoder": "^0.0.42",
|
|
119
119
|
"@ag-ui/proto": "^0.0.42",
|
|
120
120
|
"@agentclientprotocol/sdk": "^0.8.0",
|
|
121
|
-
"@ai-sdk/react": "3.0.
|
|
121
|
+
"@ai-sdk/react": "3.0.30",
|
|
122
122
|
"@anthropic-ai/sdk": "^0.52.0",
|
|
123
123
|
"@datalayer/core": "^0.0.24",
|
|
124
124
|
"@datalayer/icons-react": "^1.0.6",
|
|
@@ -177,7 +177,7 @@
|
|
|
177
177
|
"@tanstack/react-query": "^5.90.6",
|
|
178
178
|
"@toon-format/toon": "^1.3.0",
|
|
179
179
|
"@xyflow/react": "^12.10.0",
|
|
180
|
-
"ai": "
|
|
180
|
+
"ai": "6.0.28",
|
|
181
181
|
"ansi-to-html": "^0.7.2",
|
|
182
182
|
"axios": "^1.7.7",
|
|
183
183
|
"boring-avatars": "^2.0.1",
|
|
@@ -281,7 +281,7 @@
|
|
|
281
281
|
"vitest": "^3.2.4"
|
|
282
282
|
},
|
|
283
283
|
"resolutions": {
|
|
284
|
-
"@ai-sdk/react": "3.0.
|
|
284
|
+
"@ai-sdk/react": "3.0.30",
|
|
285
285
|
"@microsoft/fast-colors": "5.3.1",
|
|
286
286
|
"@microsoft/fast-components": "2.30.6",
|
|
287
287
|
"@microsoft/fast-element": "1.13.0",
|
|
@@ -291,14 +291,14 @@
|
|
|
291
291
|
"@microsoft/load-themed-styles": "1.10.295",
|
|
292
292
|
"@types/react": "18.3.20",
|
|
293
293
|
"@types/react-dom": "18.3.6",
|
|
294
|
-
"ai": "
|
|
294
|
+
"ai": "6.0.28",
|
|
295
295
|
"pyodide": "0.28.0",
|
|
296
296
|
"react": "18.3.1",
|
|
297
297
|
"react-dom": "18.3.1",
|
|
298
298
|
"typescript": "^5.8.3"
|
|
299
299
|
},
|
|
300
300
|
"overrides": {
|
|
301
|
-
"@ai-sdk/react": "3.0.
|
|
301
|
+
"@ai-sdk/react": "3.0.30",
|
|
302
302
|
"@microsoft/fast-colors": "5.3.1",
|
|
303
303
|
"@microsoft/fast-components": "2.30.6",
|
|
304
304
|
"@microsoft/fast-element": "1.13.0",
|
|
@@ -308,7 +308,7 @@
|
|
|
308
308
|
"@microsoft/load-themed-styles": "1.10.295",
|
|
309
309
|
"@types/react": "18.3.20",
|
|
310
310
|
"@types/react-dom": "18.3.6",
|
|
311
|
-
"ai": "
|
|
311
|
+
"ai": "6.0.28",
|
|
312
312
|
"pyodide": "0.28.0",
|
|
313
313
|
"react": "18.3.1",
|
|
314
314
|
"react-dom": "18.3.1",
|