@datalayer/agent-runtimes 0.0.2 → 0.0.3
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/components/AgentDetails.js +65 -2
- package/lib/components/chat/components/ChatFloating.d.ts +13 -3
- package/lib/components/chat/components/ChatFloating.js +20 -9
- package/lib/components/chat/components/base/ChatBase.d.ts +25 -0
- package/lib/components/chat/components/base/ChatBase.js +208 -18
- package/lib/components/chat/components/index.d.ts +1 -1
- package/lib/components/chat/components/parts/TextPart.js +5 -1
- package/lib/components/chat/index.d.ts +1 -1
- package/lib/components/chat/protocols/A2AAdapter.d.ts +2 -0
- package/lib/components/chat/protocols/A2AAdapter.js +9 -0
- package/lib/components/chat/protocols/ACPAdapter.d.ts +2 -0
- package/lib/components/chat/protocols/ACPAdapter.js +13 -0
- package/lib/components/chat/protocols/AGUIAdapter.d.ts +2 -0
- package/lib/components/chat/protocols/AGUIAdapter.js +5 -0
- package/lib/components/chat/protocols/BaseProtocolAdapter.d.ts +2 -0
- package/lib/components/chat/protocols/VercelAIAdapter.d.ts +4 -0
- package/lib/components/chat/protocols/VercelAIAdapter.js +5 -0
- package/lib/components/chat/types/protocol.d.ts +4 -0
- package/lib/examples/AgentRuntimeLexicalExample.js +1 -1
- package/lib/examples/components/AgentConfiguration.d.ts +22 -0
- package/lib/examples/components/AgentConfiguration.js +39 -3
- package/lib/examples/components/index.d.ts +1 -1
- package/lib/stubs/keytar.d.ts +30 -0
- package/lib/stubs/keytar.js +28 -0
- package/package.json +6 -4
- package/style/base.css +1 -43
|
@@ -5,9 +5,10 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
5
5
|
* AgentDetails component - Shows detailed information about the agent
|
|
6
6
|
* including name, protocol, URL, message count, and context details.
|
|
7
7
|
*/
|
|
8
|
-
import { ArrowLeftIcon, GlobeIcon, CommentDiscussionIcon, DatabaseIcon, FileIcon, ToolsIcon, ClockIcon, } from '@primer/octicons-react';
|
|
9
|
-
import { Box, Button, Heading, IconButton, Text, Label, ProgressBar, } from '@primer/react';
|
|
8
|
+
import { ArrowLeftIcon, GlobeIcon, CommentDiscussionIcon, DatabaseIcon, FileIcon, ToolsIcon, ClockIcon, CheckCircleIcon, XCircleIcon, } from '@primer/octicons-react';
|
|
9
|
+
import { Box, Button, Heading, IconButton, Text, Label, ProgressBar, Spinner, } from '@primer/react';
|
|
10
10
|
import { AiAgentIcon } from '@datalayer/icons-react';
|
|
11
|
+
import { useQuery } from '@tanstack/react-query';
|
|
11
12
|
// Mock context data for display
|
|
12
13
|
const MOCK_CONTEXT_DATA = {
|
|
13
14
|
name: 'Context',
|
|
@@ -51,6 +52,15 @@ const MOCK_CONTEXT_DATA = {
|
|
|
51
52
|
},
|
|
52
53
|
],
|
|
53
54
|
};
|
|
55
|
+
function getLocalApiBase() {
|
|
56
|
+
if (typeof window === 'undefined') {
|
|
57
|
+
return '';
|
|
58
|
+
}
|
|
59
|
+
const host = window.location.hostname;
|
|
60
|
+
return host === 'localhost' || host === '127.0.0.1'
|
|
61
|
+
? 'http://127.0.0.1:8765'
|
|
62
|
+
: '';
|
|
63
|
+
}
|
|
54
64
|
/**
|
|
55
65
|
* Format token count for display
|
|
56
66
|
*/
|
|
@@ -85,6 +95,19 @@ function getCategoryIcon(name) {
|
|
|
85
95
|
*/
|
|
86
96
|
export function AgentDetails({ name = 'AI Agent', protocol, url, messageCount, agentId, onBack, }) {
|
|
87
97
|
const contextUsagePercent = (MOCK_CONTEXT_DATA.usedTokens / MOCK_CONTEXT_DATA.totalTokens) * 100;
|
|
98
|
+
// Fetch MCP toolsets status
|
|
99
|
+
const { data: mcpStatus, isLoading: mcpLoading } = useQuery({
|
|
100
|
+
queryKey: ['mcp-toolsets-status'],
|
|
101
|
+
queryFn: async () => {
|
|
102
|
+
const apiBase = getLocalApiBase();
|
|
103
|
+
const response = await fetch(`${apiBase}/api/v1/configure/mcp-toolsets-status`);
|
|
104
|
+
if (!response.ok) {
|
|
105
|
+
throw new Error('Failed to fetch MCP status');
|
|
106
|
+
}
|
|
107
|
+
return response.json();
|
|
108
|
+
},
|
|
109
|
+
refetchInterval: 5000, // Refresh every 5 seconds
|
|
110
|
+
});
|
|
88
111
|
return (_jsxs(Box, { sx: {
|
|
89
112
|
display: 'flex',
|
|
90
113
|
flexDirection: 'column',
|
|
@@ -145,6 +168,46 @@ export function AgentDetails({ name = 'AI Agent', protocol, url, messageCount, a
|
|
|
145
168
|
fontWeight: 'semibold',
|
|
146
169
|
mb: 2,
|
|
147
170
|
color: 'fg.muted',
|
|
171
|
+
}, children: "MCP Toolsets" }), _jsx(Box, { sx: {
|
|
172
|
+
p: 3,
|
|
173
|
+
bg: 'canvas.subtle',
|
|
174
|
+
borderRadius: 2,
|
|
175
|
+
border: '1px solid',
|
|
176
|
+
borderColor: 'border.default',
|
|
177
|
+
}, children: mcpLoading ? (_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(Spinner, { size: "small" }), _jsx(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: "Loading MCP status..." })] })) : mcpStatus ? (_jsxs(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 2 }, children: [_jsx(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: _jsxs(Text, { sx: { fontSize: 1 }, children: [_jsx(Text, { as: "span", sx: { fontWeight: 'semibold' }, children: mcpStatus.ready_count }), ' ', "ready,", ' ', _jsx(Text, { as: "span", sx: { fontWeight: 'semibold' }, children: mcpStatus.failed_count }), ' ', "failed"] }) }), mcpStatus.ready_servers.length > 0 && (_jsxs(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 1 }, children: [_jsx(Text, { sx: {
|
|
178
|
+
fontSize: 0,
|
|
179
|
+
fontWeight: 'semibold',
|
|
180
|
+
color: 'fg.muted',
|
|
181
|
+
}, children: "Ready:" }), mcpStatus.ready_servers.map(server => (_jsxs(Box, { sx: {
|
|
182
|
+
display: 'flex',
|
|
183
|
+
alignItems: 'center',
|
|
184
|
+
gap: 2,
|
|
185
|
+
pl: 2,
|
|
186
|
+
}, children: [_jsx(CheckCircleIcon, { size: 16, fill: "success.fg" }), _jsx(Text, { sx: { fontSize: 1 }, children: server })] }, server)))] })), Object.keys(mcpStatus.failed_servers).length > 0 && (_jsxs(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 1 }, children: [_jsx(Text, { sx: {
|
|
187
|
+
fontSize: 0,
|
|
188
|
+
fontWeight: 'semibold',
|
|
189
|
+
color: 'fg.muted',
|
|
190
|
+
}, children: "Failed:" }), Object.entries(mcpStatus.failed_servers).map(([server, error]) => (_jsxs(Box, { sx: {
|
|
191
|
+
display: 'flex',
|
|
192
|
+
flexDirection: 'column',
|
|
193
|
+
gap: 1,
|
|
194
|
+
pl: 2,
|
|
195
|
+
}, children: [_jsxs(Box, { sx: {
|
|
196
|
+
display: 'flex',
|
|
197
|
+
alignItems: 'center',
|
|
198
|
+
gap: 2,
|
|
199
|
+
}, children: [_jsx(XCircleIcon, { size: 16, fill: "danger.fg" }), _jsx(Text, { sx: { fontSize: 1 }, children: server })] }), _jsx(Text, { sx: {
|
|
200
|
+
fontSize: 0,
|
|
201
|
+
color: 'danger.fg',
|
|
202
|
+
fontFamily: 'mono',
|
|
203
|
+
pl: 4,
|
|
204
|
+
whiteSpace: 'pre-wrap',
|
|
205
|
+
wordBreak: 'break-word',
|
|
206
|
+
}, children: error.split('\n')[0] })] }, server)))] }))] })) : (_jsx(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: "Failed to load MCP status" })) })] }), _jsxs(Box, { children: [_jsx(Heading, { as: "h4", sx: {
|
|
207
|
+
fontSize: 1,
|
|
208
|
+
fontWeight: 'semibold',
|
|
209
|
+
mb: 2,
|
|
210
|
+
color: 'fg.muted',
|
|
148
211
|
}, children: "Context Usage" }), _jsxs(Box, { sx: {
|
|
149
212
|
p: 3,
|
|
150
213
|
bg: 'canvas.subtle',
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
* @module components/chat/components/ChatFloating
|
|
13
13
|
*/
|
|
14
14
|
import React from 'react';
|
|
15
|
-
import { type ChatBaseProps, type RenderToolResult, type ToolCallRenderContext, type ToolCallStatus, type ProtocolConfig, type RespondCallback, type Suggestion } from './base/ChatBase';
|
|
15
|
+
import { type ChatBaseProps, type RenderToolResult, type ToolCallRenderContext, type ToolCallStatus, type ProtocolConfig, type RespondCallback, type Suggestion, type RemoteConfig, type ModelConfig, type BuiltinTool, type MCPServerConfig, type MCPServerTool } from './base/ChatBase';
|
|
16
16
|
import type { PoweredByTagProps } from './elements/PoweredByTag';
|
|
17
|
-
export type { ToolCallStatus, ToolCallRenderContext, RenderToolResult, RespondCallback, Suggestion, };
|
|
17
|
+
export type { ToolCallStatus, ToolCallRenderContext, RenderToolResult, RespondCallback, Suggestion, RemoteConfig, ModelConfig, BuiltinTool, MCPServerConfig, MCPServerTool, };
|
|
18
18
|
/**
|
|
19
19
|
* ChatFloating props
|
|
20
20
|
*/
|
|
@@ -135,6 +135,16 @@ export interface ChatFloatingProps {
|
|
|
135
135
|
* @default false
|
|
136
136
|
*/
|
|
137
137
|
showPanelBackdrop?: boolean;
|
|
138
|
+
/**
|
|
139
|
+
* Show model selector in footer.
|
|
140
|
+
* @default false
|
|
141
|
+
*/
|
|
142
|
+
showModelSelector?: boolean;
|
|
143
|
+
/**
|
|
144
|
+
* Show tools menu in footer.
|
|
145
|
+
* @default false
|
|
146
|
+
*/
|
|
147
|
+
showToolsMenu?: boolean;
|
|
138
148
|
/** Additional ChatBase props */
|
|
139
149
|
panelProps?: Partial<ChatBaseProps>;
|
|
140
150
|
}
|
|
@@ -142,5 +152,5 @@ export interface ChatFloatingProps {
|
|
|
142
152
|
* ChatFloating component
|
|
143
153
|
* A floating chat window built on ChatBase
|
|
144
154
|
*/
|
|
145
|
-
export declare function ChatFloating({ endpoint, protocol: protocolProp, useStore: useStoreMode, title, description, position, defaultOpen, width, height, showHeader, showButton, showNewChatButton, showClearButton, showSettingsButton, enableKeyboardShortcuts, toggleShortcut, showPoweredBy, poweredByProps, clickOutsideToClose, escapeToClose, className, onSettingsClick, onNewChat, onOpen, onClose, onStateUpdate, children, brandIcon, buttonIcon, buttonTooltip, brandColor, offset, animationDuration, renderToolResult, tools: _tools, initialState: _initialState, suggestions, submitOnSuggestionClick, hideMessagesAfterToolUI, defaultViewMode, showPanelBackdrop, panelProps, }: ChatFloatingProps): import("react/jsx-runtime").JSX.Element;
|
|
155
|
+
export declare function ChatFloating({ endpoint, protocol: protocolProp, useStore: useStoreMode, title, description, position, defaultOpen, width, height, showHeader, showButton, showNewChatButton, showClearButton, showSettingsButton, enableKeyboardShortcuts, toggleShortcut, showPoweredBy, poweredByProps, clickOutsideToClose, escapeToClose, className, onSettingsClick, onNewChat, onOpen, onClose, onStateUpdate, children, brandIcon, buttonIcon, buttonTooltip, brandColor, offset, animationDuration, renderToolResult, tools: _tools, initialState: _initialState, suggestions, submitOnSuggestionClick, hideMessagesAfterToolUI, defaultViewMode, showPanelBackdrop, showModelSelector, showToolsMenu, panelProps, }: ChatFloatingProps): import("react/jsx-runtime").JSX.Element;
|
|
146
156
|
export default ChatFloating;
|
|
@@ -43,7 +43,7 @@ function useIsMobile(breakpoint = 640) {
|
|
|
43
43
|
* ChatFloating component
|
|
44
44
|
* A floating chat window built on ChatBase
|
|
45
45
|
*/
|
|
46
|
-
export function ChatFloating({ endpoint, protocol: protocolProp, useStore: useStoreMode = true, title = 'Chat', description = 'Start a conversation with the AI agent.', position = 'bottom-right', defaultOpen = false, width = 400, height = 550, showHeader = true, showButton = true, showNewChatButton = true, showClearButton = true, showSettingsButton = false, enableKeyboardShortcuts = true, toggleShortcut = '/', showPoweredBy = true, poweredByProps, clickOutsideToClose = true, escapeToClose = true, className, onSettingsClick, onNewChat, onOpen, onClose, onStateUpdate, children, brandIcon, buttonIcon, buttonTooltip = 'Chat with AI', brandColor = '#7c3aed', offset = 20, animationDuration = 200, renderToolResult, tools: _tools, initialState: _initialState, suggestions, submitOnSuggestionClick = true, hideMessagesAfterToolUI = false, defaultViewMode = 'floating', showPanelBackdrop = false, panelProps, }) {
|
|
46
|
+
export function ChatFloating({ endpoint, protocol: protocolProp, useStore: useStoreMode = true, title = 'Chat', description = 'Start a conversation with the AI agent.', position = 'bottom-right', defaultOpen = false, width = 400, height = 550, showHeader = true, showButton = true, showNewChatButton = true, showClearButton = true, showSettingsButton = false, enableKeyboardShortcuts = true, toggleShortcut = '/', showPoweredBy = true, poweredByProps, clickOutsideToClose = true, escapeToClose = true, className, onSettingsClick, onNewChat, onOpen, onClose, onStateUpdate, children, brandIcon, buttonIcon, buttonTooltip = 'Chat with AI', brandColor = '#7c3aed', offset = 20, animationDuration = 200, renderToolResult, tools: _tools, initialState: _initialState, suggestions, submitOnSuggestionClick = true, hideMessagesAfterToolUI = false, defaultViewMode = 'floating', showPanelBackdrop = false, showModelSelector = false, showToolsMenu = false, panelProps, }) {
|
|
47
47
|
// Store-based state
|
|
48
48
|
const storeIsOpen = useChatOpen();
|
|
49
49
|
const storeMessages = useChatMessages();
|
|
@@ -63,13 +63,24 @@ export function ChatFloating({ endpoint, protocol: protocolProp, useStore: useSt
|
|
|
63
63
|
const [focusTrigger, setFocusTrigger] = useState(0);
|
|
64
64
|
// Build protocol config from endpoint if not provided directly
|
|
65
65
|
// Memoize to avoid creating new object on every render (which would trigger useEffect re-runs)
|
|
66
|
-
const protocol = useMemo(() =>
|
|
67
|
-
(
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
66
|
+
const protocol = useMemo(() => {
|
|
67
|
+
if (protocolProp)
|
|
68
|
+
return protocolProp;
|
|
69
|
+
if (!endpoint)
|
|
70
|
+
return undefined;
|
|
71
|
+
// Extract base URL from endpoint (e.g., http://localhost:8765/api/v1/ag-ui/agent/ -> http://localhost:8765)
|
|
72
|
+
const baseUrl = endpoint.match(/^(https?:\/\/[^/]+)/)?.[1] || '';
|
|
73
|
+
return {
|
|
74
|
+
type: 'ag-ui',
|
|
75
|
+
endpoint,
|
|
76
|
+
// Enable config query for model/tools selector when showModelSelector or showToolsMenu is true
|
|
77
|
+
enableConfigQuery: showModelSelector || showToolsMenu,
|
|
78
|
+
// Config endpoint is at /api/v1/configure (global, not per-agent)
|
|
79
|
+
configEndpoint: showModelSelector || showToolsMenu
|
|
80
|
+
? `${baseUrl}/api/v1/configure`
|
|
81
|
+
: undefined,
|
|
82
|
+
};
|
|
83
|
+
}, [protocolProp, endpoint, showModelSelector, showToolsMenu]);
|
|
73
84
|
// Clear messages when endpoint/protocol changes (e.g., switching examples)
|
|
74
85
|
useEffect(() => {
|
|
75
86
|
clearStoreMessages();
|
|
@@ -376,6 +387,6 @@ export function ChatFloating({ endpoint, protocol: protocolProp, useStore: useSt
|
|
|
376
387
|
...poweredByProps,
|
|
377
388
|
}, renderToolResult: renderToolResult, description: description, onStateUpdate: onStateUpdate, onNewChat: onNewChat, suggestions: suggestions, submitOnSuggestionClick: submitOnSuggestionClick, hideMessagesAfterToolUI: hideMessagesAfterToolUI, avatarConfig: {
|
|
378
389
|
showAvatars: true,
|
|
379
|
-
}, placeholder: "Type a message...", backgroundColor: "canvas.subtle", frontendTools: _tools, ...panelProps, children: children }) })] }));
|
|
390
|
+
}, placeholder: "Type a message...", backgroundColor: "canvas.subtle", frontendTools: _tools, showModelSelector: showModelSelector, showToolsMenu: showToolsMenu, ...panelProps, children: children }) })] }));
|
|
380
391
|
}
|
|
381
392
|
export default ChatFloating;
|
|
@@ -124,6 +124,7 @@ export interface ModelConfig {
|
|
|
124
124
|
id: string;
|
|
125
125
|
name: string;
|
|
126
126
|
builtinTools?: string[];
|
|
127
|
+
isAvailable?: boolean;
|
|
127
128
|
}
|
|
128
129
|
/**
|
|
129
130
|
* Builtin tool configuration
|
|
@@ -132,12 +133,36 @@ export interface BuiltinTool {
|
|
|
132
133
|
name: string;
|
|
133
134
|
id: string;
|
|
134
135
|
}
|
|
136
|
+
/**
|
|
137
|
+
* MCP Server Tool configuration
|
|
138
|
+
*/
|
|
139
|
+
export interface MCPServerTool {
|
|
140
|
+
name: string;
|
|
141
|
+
description: string;
|
|
142
|
+
enabled: boolean;
|
|
143
|
+
inputSchema?: Record<string, unknown>;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* MCP Server configuration from backend
|
|
147
|
+
*/
|
|
148
|
+
export interface MCPServerConfig {
|
|
149
|
+
id: string;
|
|
150
|
+
name: string;
|
|
151
|
+
url?: string;
|
|
152
|
+
enabled: boolean;
|
|
153
|
+
tools: MCPServerTool[];
|
|
154
|
+
command?: string;
|
|
155
|
+
args?: string[];
|
|
156
|
+
isAvailable?: boolean;
|
|
157
|
+
transport?: string;
|
|
158
|
+
}
|
|
135
159
|
/**
|
|
136
160
|
* Remote configuration from server
|
|
137
161
|
*/
|
|
138
162
|
export interface RemoteConfig {
|
|
139
163
|
models: ModelConfig[];
|
|
140
164
|
builtinTools: BuiltinTool[];
|
|
165
|
+
mcpServers?: MCPServerConfig[];
|
|
141
166
|
}
|
|
142
167
|
/**
|
|
143
168
|
* Protocol configuration for ChatBase
|
|
@@ -17,11 +17,11 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
|
|
|
17
17
|
*/
|
|
18
18
|
import { useContext } from 'react';
|
|
19
19
|
import { useCallback, useEffect, useRef, useState, } from 'react';
|
|
20
|
-
import { Heading, Text, Spinner, IconButton, Textarea, Button, ActionMenu, ActionList, LabelGroup, Label, } from '@primer/react';
|
|
20
|
+
import { Heading, Text, Spinner, IconButton, Textarea, Button, ActionMenu, ActionList, LabelGroup, Label, ToggleSwitch, } from '@primer/react';
|
|
21
21
|
import { Box } from '@datalayer/primer-addons';
|
|
22
22
|
import { AlertIcon, PlusIcon, TrashIcon, GearIcon, PersonIcon, PaperAirplaneIcon, SquareCircleIcon, ToolsIcon, AiModelIcon, } from '@primer/octicons-react';
|
|
23
23
|
import { AiAgentIcon } from '@datalayer/icons-react';
|
|
24
|
-
import { useQuery, QueryClientContext } from '@tanstack/react-query';
|
|
24
|
+
import { useQuery, QueryClient, QueryClientProvider, QueryClientContext, } from '@tanstack/react-query';
|
|
25
25
|
import { Streamdown } from 'streamdown';
|
|
26
26
|
import { PoweredByTag } from '../elements/PoweredByTag';
|
|
27
27
|
import { requestAPI } from '../../handler';
|
|
@@ -29,6 +29,51 @@ import { useChatStore } from '../../store/chatStore';
|
|
|
29
29
|
import { generateMessageId, createUserMessage, createAssistantMessage, } from '../../types/message';
|
|
30
30
|
import { AGUIAdapter, A2AAdapter, VercelAIAdapter, ACPAdapter, } from '../../protocols';
|
|
31
31
|
import { ToolCallDisplay } from '../display/ToolCallDisplay';
|
|
32
|
+
// Singleton QueryClient for ChatBase instances without external QueryClientProvider
|
|
33
|
+
const internalQueryClient = new QueryClient({
|
|
34
|
+
defaultOptions: {
|
|
35
|
+
queries: {
|
|
36
|
+
staleTime: 5 * 60 * 1000, // 5 minutes
|
|
37
|
+
refetchOnWindowFocus: false,
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
// Primer's default portal root ID
|
|
42
|
+
const PRIMER_PORTAL_ROOT_ID = '__primerPortalRoot__';
|
|
43
|
+
/**
|
|
44
|
+
* Hook to ensure Primer's default portal root has a high z-index.
|
|
45
|
+
* This ensures dropdown menus appear above floating chat panels.
|
|
46
|
+
*/
|
|
47
|
+
function useHighZIndexPortal() {
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
// Set up a MutationObserver to watch for the portal root being added
|
|
50
|
+
const setPortalZIndex = () => {
|
|
51
|
+
const portalRoot = document.getElementById(PRIMER_PORTAL_ROOT_ID);
|
|
52
|
+
if (portalRoot) {
|
|
53
|
+
portalRoot.style.zIndex = '9999';
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
return false;
|
|
57
|
+
};
|
|
58
|
+
// Try immediately
|
|
59
|
+
if (setPortalZIndex()) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
// If not found yet, observe for it
|
|
63
|
+
const observer = new MutationObserver(() => {
|
|
64
|
+
if (setPortalZIndex()) {
|
|
65
|
+
observer.disconnect();
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
observer.observe(document.body, {
|
|
69
|
+
childList: true,
|
|
70
|
+
subtree: true,
|
|
71
|
+
});
|
|
72
|
+
return () => {
|
|
73
|
+
observer.disconnect();
|
|
74
|
+
};
|
|
75
|
+
}, []);
|
|
76
|
+
}
|
|
32
77
|
/**
|
|
33
78
|
* Check if an item is a tool call message
|
|
34
79
|
*/
|
|
@@ -120,8 +165,29 @@ export function ChatBase({ title, showHeader = false, showLoadingIndicator = tru
|
|
|
120
165
|
useStore: useStoreMode = true, protocol, onSendMessage, enableStreaming = false,
|
|
121
166
|
// Extended props
|
|
122
167
|
brandIcon, avatarConfig, headerButtons, showPoweredBy = false, poweredByProps, emptyState, renderToolResult, footerContent, 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, }) {
|
|
168
|
+
// Check if QueryClientProvider is already available
|
|
169
|
+
const existingQueryClient = useContext(QueryClientContext);
|
|
170
|
+
// If no QueryClient is available, wrap with our internal provider
|
|
171
|
+
if (!existingQueryClient) {
|
|
172
|
+
return (_jsx(QueryClientProvider, { client: internalQueryClient, children: _jsx(ChatBaseInner, { title: title, showHeader: showHeader, showLoadingIndicator: showLoadingIndicator, showErrors: showErrors, showInput: showInput, showModelSelector: showModelSelector, showToolsMenu: showToolsMenu, className: className, loadingState: loadingState, headerActions: headerActions, useStore: useStoreMode, protocol: protocol, onSendMessage: onSendMessage, enableStreaming: enableStreaming, brandIcon: brandIcon, avatarConfig: avatarConfig, headerButtons: headerButtons, showPoweredBy: showPoweredBy, poweredByProps: poweredByProps, emptyState: emptyState, renderToolResult: renderToolResult, footerContent: footerContent, headerContent: headerContent, children: children, borderRadius: borderRadius, backgroundColor: backgroundColor, border: border, boxShadow: boxShadow, compact: compact, placeholder: placeholder, description: description, onStateUpdate: onStateUpdate, onNewChat: onNewChat, onClear: onClear, onMessagesChange: onMessagesChange, autoFocus: autoFocus, suggestions: suggestions, submitOnSuggestionClick: submitOnSuggestionClick, hideMessagesAfterToolUI: hideMessagesAfterToolUI, focusTrigger: focusTrigger, frontendTools: frontendTools }) }));
|
|
173
|
+
}
|
|
174
|
+
// QueryClient already available, render inner component directly
|
|
175
|
+
return (_jsx(ChatBaseInner, { title: title, showHeader: showHeader, showLoadingIndicator: showLoadingIndicator, showErrors: showErrors, showInput: showInput, showModelSelector: showModelSelector, showToolsMenu: showToolsMenu, className: className, loadingState: loadingState, headerActions: headerActions, useStore: useStoreMode, protocol: protocol, onSendMessage: onSendMessage, enableStreaming: enableStreaming, brandIcon: brandIcon, avatarConfig: avatarConfig, headerButtons: headerButtons, showPoweredBy: showPoweredBy, poweredByProps: poweredByProps, emptyState: emptyState, renderToolResult: renderToolResult, footerContent: footerContent, headerContent: headerContent, children: children, borderRadius: borderRadius, backgroundColor: backgroundColor, border: border, boxShadow: boxShadow, compact: compact, placeholder: placeholder, description: description, onStateUpdate: onStateUpdate, onNewChat: onNewChat, onClear: onClear, onMessagesChange: onMessagesChange, autoFocus: autoFocus, suggestions: suggestions, submitOnSuggestionClick: submitOnSuggestionClick, hideMessagesAfterToolUI: hideMessagesAfterToolUI, focusTrigger: focusTrigger, frontendTools: frontendTools }));
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Inner ChatBase component - contains all the actual logic
|
|
179
|
+
*/
|
|
180
|
+
function ChatBaseInner({ title, showHeader = false, showLoadingIndicator = true, showErrors = true, showInput = true, showModelSelector = false, showToolsMenu = false, className, loadingState, headerActions,
|
|
181
|
+
// Mode selection
|
|
182
|
+
useStore: useStoreMode = true, protocol, onSendMessage, enableStreaming = false,
|
|
183
|
+
// Extended props
|
|
184
|
+
brandIcon, avatarConfig, headerButtons, showPoweredBy = false, poweredByProps, emptyState, renderToolResult, footerContent, 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, }) {
|
|
185
|
+
// Ensure Primer's default portal has high z-index for ActionMenu overlays
|
|
186
|
+
useHighZIndexPortal();
|
|
123
187
|
// Store (optional for message persistence)
|
|
124
188
|
const clearStoreMessages = useChatStore(state => state.clearMessages);
|
|
189
|
+
// Check if protocol is A2A (doesn't support per-request model override)
|
|
190
|
+
const isA2AProtocol = protocol?.type === 'a2a';
|
|
125
191
|
// Component state
|
|
126
192
|
const [displayItems, setDisplayItems] = useState([]);
|
|
127
193
|
const [isLoading, setIsLoading] = useState(false);
|
|
@@ -130,10 +196,12 @@ brandIcon, avatarConfig, headerButtons, showPoweredBy = false, poweredByProps, e
|
|
|
130
196
|
const [input, setInput] = useState('');
|
|
131
197
|
// Model and tools state
|
|
132
198
|
const [selectedModel, setSelectedModel] = useState('');
|
|
133
|
-
//
|
|
199
|
+
// enabledTools tracks which MCP server tools are enabled
|
|
200
|
+
// Format: Map<serverId, Set<toolName>>
|
|
201
|
+
const [enabledMcpTools, setEnabledMcpTools] = useState(new Map());
|
|
202
|
+
// Note: legacy _enabledTools for backend-defined tools from config query
|
|
134
203
|
// Frontend tools are passed via frontendTools prop
|
|
135
|
-
const [
|
|
136
|
-
void enabledTools; // Suppress unused warning - may be used in future
|
|
204
|
+
const [_enabledTools, setEnabledTools] = useState([]);
|
|
137
205
|
// Config query (for protocols that support it)
|
|
138
206
|
// Safely handles missing QueryClientProvider
|
|
139
207
|
const configQuery = useConfigQuery(Boolean(protocol?.enableConfigQuery), protocol?.configEndpoint, protocol?.authToken);
|
|
@@ -201,14 +269,63 @@ brandIcon, avatarConfig, headerButtons, showPoweredBy = false, poweredByProps, e
|
|
|
201
269
|
// Initialize model and tools when config is available
|
|
202
270
|
useEffect(() => {
|
|
203
271
|
if (configQuery.data && !selectedModel) {
|
|
204
|
-
|
|
272
|
+
// Select first available model, or fallback to first model if none available
|
|
273
|
+
const firstAvailableModel = configQuery.data.models.find(m => m.isAvailable !== false);
|
|
274
|
+
const firstModel = firstAvailableModel || configQuery.data.models[0];
|
|
205
275
|
if (firstModel) {
|
|
206
276
|
setSelectedModel(firstModel.id);
|
|
207
277
|
const allToolIds = configQuery.data.builtinTools?.map(tool => tool.id) || [];
|
|
208
278
|
setEnabledTools(allToolIds);
|
|
209
279
|
}
|
|
280
|
+
// Initialize MCP server tools - all enabled by default
|
|
281
|
+
if (configQuery.data.mcpServers) {
|
|
282
|
+
const newEnabledMcpTools = new Map();
|
|
283
|
+
for (const server of configQuery.data.mcpServers) {
|
|
284
|
+
if (server.isAvailable && server.enabled) {
|
|
285
|
+
const enabledToolNames = new Set(server.tools.filter(t => t.enabled).map(t => t.name));
|
|
286
|
+
newEnabledMcpTools.set(server.id, enabledToolNames);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
setEnabledMcpTools(newEnabledMcpTools);
|
|
290
|
+
}
|
|
210
291
|
}
|
|
211
292
|
}, [configQuery.data, selectedModel]);
|
|
293
|
+
// Helper to toggle MCP tool enabled state
|
|
294
|
+
const toggleMcpTool = useCallback((serverId, toolName) => {
|
|
295
|
+
setEnabledMcpTools(prev => {
|
|
296
|
+
const newMap = new Map(prev);
|
|
297
|
+
const serverTools = new Set(prev.get(serverId) || []);
|
|
298
|
+
if (serverTools.has(toolName)) {
|
|
299
|
+
serverTools.delete(toolName);
|
|
300
|
+
}
|
|
301
|
+
else {
|
|
302
|
+
serverTools.add(toolName);
|
|
303
|
+
}
|
|
304
|
+
newMap.set(serverId, serverTools);
|
|
305
|
+
return newMap;
|
|
306
|
+
});
|
|
307
|
+
}, []);
|
|
308
|
+
// Helper to toggle all tools for a MCP server
|
|
309
|
+
const toggleAllMcpServerTools = useCallback((serverId, allToolNames, enable) => {
|
|
310
|
+
setEnabledMcpTools(prev => {
|
|
311
|
+
const newMap = new Map(prev);
|
|
312
|
+
if (enable) {
|
|
313
|
+
newMap.set(serverId, new Set(allToolNames));
|
|
314
|
+
}
|
|
315
|
+
else {
|
|
316
|
+
newMap.set(serverId, new Set());
|
|
317
|
+
}
|
|
318
|
+
return newMap;
|
|
319
|
+
});
|
|
320
|
+
}, []);
|
|
321
|
+
// Get all enabled MCP tool names (for sending with requests)
|
|
322
|
+
const getEnabledMcpToolNames = useCallback(() => {
|
|
323
|
+
const toolNames = [];
|
|
324
|
+
enabledMcpTools.forEach(tools => {
|
|
325
|
+
tools.forEach(toolName => toolNames.push(toolName));
|
|
326
|
+
});
|
|
327
|
+
return toolNames;
|
|
328
|
+
}, [enabledMcpTools]);
|
|
212
329
|
// Load messages from store on mount when useStoreMode is enabled
|
|
213
330
|
useEffect(() => {
|
|
214
331
|
if (useStoreMode) {
|
|
@@ -499,6 +616,8 @@ brandIcon, avatarConfig, headerButtons, showPoweredBy = false, poweredByProps, e
|
|
|
499
616
|
unsubscribeRef.current?.();
|
|
500
617
|
adapterRef.current?.disconnect();
|
|
501
618
|
};
|
|
619
|
+
// Note: frontendTools is accessed via ref-like closure, not as reactive dependency
|
|
620
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
502
621
|
}, [protocol, renderToolResult, onStateUpdate, useStoreMode]);
|
|
503
622
|
// Auto-scroll to bottom
|
|
504
623
|
useEffect(() => {
|
|
@@ -605,14 +724,15 @@ brandIcon, avatarConfig, headerButtons, showPoweredBy = false, poweredByProps, e
|
|
|
605
724
|
description: tool.description,
|
|
606
725
|
parameters: tool.parameters || { type: 'object', properties: {} },
|
|
607
726
|
}));
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
}
|
|
727
|
+
// Get enabled MCP tool names
|
|
728
|
+
const enabledMcpToolNames = getEnabledMcpToolNames();
|
|
611
729
|
await adapterRef.current.sendMessage(userMessage, {
|
|
612
730
|
threadId: threadIdRef.current,
|
|
613
731
|
messages: allMessages,
|
|
614
732
|
...(selectedModel && { model: selectedModel }),
|
|
615
733
|
tools: toolsForRequest,
|
|
734
|
+
// Include enabled MCP tools as builtin_tools for backend
|
|
735
|
+
builtinTools: enabledMcpToolNames,
|
|
616
736
|
});
|
|
617
737
|
}
|
|
618
738
|
}
|
|
@@ -639,6 +759,7 @@ brandIcon, avatarConfig, headerButtons, showPoweredBy = false, poweredByProps, e
|
|
|
639
759
|
useStoreMode,
|
|
640
760
|
onSendMessage,
|
|
641
761
|
enableStreaming,
|
|
762
|
+
getEnabledMcpToolNames,
|
|
642
763
|
]);
|
|
643
764
|
// Handle stop
|
|
644
765
|
const handleStop = useCallback(() => {
|
|
@@ -1049,8 +1170,20 @@ brandIcon, avatarConfig, headerButtons, showPoweredBy = false, poweredByProps, e
|
|
|
1049
1170
|
fontSize: 1,
|
|
1050
1171
|
whiteSpace: 'pre-wrap',
|
|
1051
1172
|
wordBreak: 'break-word',
|
|
1052
|
-
}, children: getMessageText(message) })) : (_jsx(Box, { sx: {
|
|
1053
|
-
|
|
1173
|
+
}, children: getMessageText(message) })) : (_jsx(Box, { sx: {
|
|
1174
|
+
fontSize: 1,
|
|
1175
|
+
lineHeight: 1.5,
|
|
1176
|
+
'& ul, & ol': {
|
|
1177
|
+
marginTop: '0.5em',
|
|
1178
|
+
marginBottom: '0.5em',
|
|
1179
|
+
paddingInlineStart: '1.25em',
|
|
1180
|
+
listStylePosition: 'inside',
|
|
1181
|
+
},
|
|
1182
|
+
'& li': {
|
|
1183
|
+
paddingInlineStart: '0.25em',
|
|
1184
|
+
},
|
|
1185
|
+
}, children: _jsx(Streamdown, { children: getMessageText(message) || (isStreaming ? '...' : '') }) })) })] }) }, message.id));
|
|
1186
|
+
}), showLoadingIndicator && (isLoading || isStreaming) && (_jsx(Box, { sx: {
|
|
1054
1187
|
display: 'flex',
|
|
1055
1188
|
alignItems: 'flex-start',
|
|
1056
1189
|
px: padding,
|
|
@@ -1157,13 +1290,70 @@ brandIcon, avatarConfig, headerButtons, showPoweredBy = false, poweredByProps, e
|
|
|
1157
1290
|
borderColor: 'border.default',
|
|
1158
1291
|
alignItems: 'center',
|
|
1159
1292
|
bg: 'canvas.subtle',
|
|
1160
|
-
}, children: [showToolsMenu && (_jsxs(ActionMenu, { children: [_jsx(ActionMenu.Anchor, { children: _jsx(IconButton, { icon: ToolsIcon, "aria-label": "Tools", variant: "invisible", size: "small" }) }), _jsx(ActionMenu.Overlay, { side: "outside-top", align: "start",
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1293
|
+
}, children: [showToolsMenu && (_jsxs(ActionMenu, { children: [_jsx(ActionMenu.Anchor, { children: _jsx(IconButton, { icon: ToolsIcon, "aria-label": "Tools", variant: "invisible", size: "small" }) }), _jsx(ActionMenu.Overlay, { side: "outside-top", align: "start", width: "large", children: _jsx(Box, { sx: {
|
|
1294
|
+
maxHeight: '60vh',
|
|
1295
|
+
overflowY: 'auto',
|
|
1296
|
+
}, children: _jsx(ActionList, { children: configQuery.data?.mcpServers &&
|
|
1297
|
+
configQuery.data.mcpServers.length > 0 ? (configQuery.data.mcpServers.map(server => {
|
|
1298
|
+
const serverTools = enabledMcpTools.get(server.id);
|
|
1299
|
+
const allToolNames = server.tools.map(t => t.name);
|
|
1300
|
+
const enabledCount = serverTools?.size ?? 0;
|
|
1301
|
+
const allEnabled = enabledCount === allToolNames.length &&
|
|
1302
|
+
allToolNames.length > 0;
|
|
1303
|
+
return (_jsxs(ActionList.Group, { title: `${server.name}${server.isAvailable ? '' : ' (unavailable)'}`, children: [server.isAvailable &&
|
|
1304
|
+
server.tools.length > 0 && (_jsxs(Box, { sx: {
|
|
1305
|
+
display: 'flex',
|
|
1306
|
+
alignItems: 'center',
|
|
1307
|
+
justifyContent: 'space-between',
|
|
1308
|
+
px: 3,
|
|
1309
|
+
py: 2,
|
|
1310
|
+
borderBottom: '1px solid',
|
|
1311
|
+
borderColor: 'border.muted',
|
|
1312
|
+
}, children: [_jsxs(Text, { id: `toggle-all-${server.id}`, sx: {
|
|
1313
|
+
fontSize: 0,
|
|
1314
|
+
fontWeight: 'semibold',
|
|
1315
|
+
color: 'fg.muted',
|
|
1316
|
+
}, children: ["Enable all (", enabledCount, "/", allToolNames.length, ")"] }), _jsx(ToggleSwitch, { size: "small", checked: allEnabled, onClick: () => toggleAllMcpServerTools(server.id, allToolNames, !allEnabled), "aria-labelledby": `toggle-all-${server.id}` })] })), server.isAvailable && server.tools.length > 0 ? (server.tools.map(tool => {
|
|
1317
|
+
const isEnabled = serverTools?.has(tool.name) ?? false;
|
|
1318
|
+
return (_jsxs(Box, { sx: {
|
|
1319
|
+
display: 'flex',
|
|
1320
|
+
alignItems: 'center',
|
|
1321
|
+
justifyContent: 'space-between',
|
|
1322
|
+
px: 3,
|
|
1323
|
+
py: 2,
|
|
1324
|
+
'&:hover': {
|
|
1325
|
+
backgroundColor: 'canvas.subtle',
|
|
1326
|
+
},
|
|
1327
|
+
}, children: [_jsxs(Box, { sx: { flex: 1, minWidth: 0 }, children: [_jsx(Text, { id: `toggle-tool-${server.id}-${tool.name}`, sx: { fontWeight: 'semibold' }, children: tool.name }), tool.description && (_jsx(Text, { sx: {
|
|
1328
|
+
display: 'block',
|
|
1329
|
+
fontSize: 0,
|
|
1330
|
+
color: 'fg.muted',
|
|
1331
|
+
overflow: 'hidden',
|
|
1332
|
+
textOverflow: 'ellipsis',
|
|
1333
|
+
whiteSpace: 'nowrap',
|
|
1334
|
+
}, children: tool.description }))] }), _jsx(ToggleSwitch, { size: "small", checked: isEnabled, onClick: () => toggleMcpTool(server.id, tool.name), "aria-labelledby": `toggle-tool-${server.id}-${tool.name}` })] }, `${server.id}-${tool.name}`));
|
|
1335
|
+
})) : server.isAvailable ? (_jsx(ActionList.Item, { disabled: true, children: _jsx(Text, { sx: {
|
|
1336
|
+
color: 'fg.muted',
|
|
1337
|
+
fontStyle: 'italic',
|
|
1338
|
+
}, children: "No tools discovered" }) })) : (_jsx(ActionList.Item, { disabled: true, children: _jsx(Text, { sx: {
|
|
1339
|
+
color: 'fg.muted',
|
|
1340
|
+
fontStyle: 'italic',
|
|
1341
|
+
}, children: "Server unavailable" }) }))] }, server.id));
|
|
1342
|
+
})) : (_jsx(ActionList.Group, { title: "Available Tools", children: availableTools.length > 0 ? (availableTools.map(tool => (_jsxs(ActionList.Item, { disabled: true, children: [_jsx(ActionList.LeadingVisual, { children: _jsx(Box, { sx: {
|
|
1343
|
+
width: 8,
|
|
1344
|
+
height: 8,
|
|
1345
|
+
borderRadius: '50%',
|
|
1346
|
+
backgroundColor: 'success.emphasis',
|
|
1347
|
+
} }) }), tool.name] }, tool.id)))) : (_jsx(ActionList.Item, { disabled: true, children: _jsx(Text, { sx: { color: 'fg.muted', fontStyle: 'italic' }, children: "No tools available" }) })) })) }) }) })] })), showModelSelector && models.length > 0 && selectedModel && (_jsxs(Box, { sx: {
|
|
1348
|
+
display: 'flex',
|
|
1349
|
+
flexDirection: 'column',
|
|
1350
|
+
alignItems: 'flex-end',
|
|
1351
|
+
}, children: [_jsxs(ActionMenu, { children: [_jsx(ActionMenu.Anchor, { children: _jsx(Button, { type: "button", variant: "invisible", size: "small", leadingVisual: AiModelIcon, disabled: isA2AProtocol, sx: isA2AProtocol
|
|
1352
|
+
? { opacity: 0.5, cursor: 'not-allowed' }
|
|
1353
|
+
: undefined, children: _jsx(Text, { sx: { fontSize: 0 }, children: models.find(m => m.id === selectedModel)?.name ||
|
|
1354
|
+
'Select Model' }) }) }), _jsx(ActionMenu.Overlay, { side: "outside-top", align: "end", children: _jsx(ActionList, { selectionVariant: "single", children: models.map(modelItem => (_jsxs(ActionList.Item, { selected: selectedModel === modelItem.id, onSelect: () => setSelectedModel(modelItem.id), disabled: modelItem.isAvailable === false || isA2AProtocol, sx: modelItem.isAvailable === false
|
|
1355
|
+
? { color: 'fg.muted' }
|
|
1356
|
+
: undefined, children: [modelItem.name, modelItem.isAvailable === false && (_jsx(ActionList.Description, { variant: "block", children: "Missing API key" }))] }, modelItem.id))) }) })] }), isA2AProtocol && (_jsx(Text, { sx: { fontSize: 0, color: 'attention.fg', mt: 1 }, children: "A2A: Model set by agent config" }))] }))] }))] }));
|
|
1167
1357
|
};
|
|
1168
1358
|
return (_jsxs(Box, { className: className, sx: {
|
|
1169
1359
|
display: 'flex',
|
|
@@ -17,5 +17,5 @@ export { MessagePart, type MessagePartProps } from './elements/MessagePart';
|
|
|
17
17
|
export { TextPart, type TextPartProps, ReasoningPart, type ReasoningPartProps, ToolPart, type ToolPartProps, DynamicToolPart, type DynamicToolPartProps, } from './parts';
|
|
18
18
|
export { ToolCallDisplay, type ToolCallDisplayProps } from './display';
|
|
19
19
|
export { Chat, type ChatProps, type Transport, type Extension } from './Chat';
|
|
20
|
-
export { ChatFloating, type ChatFloatingProps, type ToolCallRenderContext, type ToolCallStatus, type RenderToolResult, type RespondCallback, type Suggestion, } from './ChatFloating';
|
|
20
|
+
export { ChatFloating, type ChatFloatingProps, type ToolCallRenderContext, type ToolCallStatus, type RenderToolResult, type RespondCallback, type Suggestion, type RemoteConfig, type ModelConfig, type BuiltinTool, type MCPServerConfig, type MCPServerTool, } from './ChatFloating';
|
|
21
21
|
export { ChatInline, type ChatInlineProps, type ChatInlineProtocolConfig, } from './ChatInline';
|
|
@@ -47,7 +47,11 @@ export function TextPart({ text, message, isLastPart, onRegenerate, }) {
|
|
|
47
47
|
'& ul, & ol': {
|
|
48
48
|
marginTop: '0.5em',
|
|
49
49
|
marginBottom: '0.5em',
|
|
50
|
-
paddingLeft: '1.
|
|
50
|
+
paddingLeft: '1.2em',
|
|
51
|
+
marginLeft: '0.3em',
|
|
52
|
+
},
|
|
53
|
+
'& li': {
|
|
54
|
+
listStylePosition: 'inside',
|
|
51
55
|
},
|
|
52
56
|
'& code': {
|
|
53
57
|
backgroundColor: 'neutral.muted',
|
|
@@ -56,6 +56,6 @@ export { BaseProtocolAdapter, AGUIAdapter, A2AAdapter, ACPAdapter, type AGUIAdap
|
|
|
56
56
|
export { ToolExecutor, type ToolExecutionContext } from './tools';
|
|
57
57
|
export { MiddlewarePipeline, createMiddleware, loggingMiddleware, createHITLMiddleware, type RequestContext, type ResponseContext, } from './middleware';
|
|
58
58
|
export { ExtensionRegistry, createMessageRenderer, createActivityRenderer, createA2UIRenderer, A2UIExtensionImpl, type A2UIMessage, } from './extensions';
|
|
59
|
-
export { ChatMessages, ChatInputPrompt, ChatSidebar, ChatStandalone, ChatBase, ToolApprovalDialog, useToolApprovalDialog, PoweredByTag, FloatingBrandButton, ChatHeader, MessagePart, TextPart, ReasoningPart, ToolPart, DynamicToolPart, ToolCallDisplay, Chat, ChatFloating, type ChatMessagesProps, type ChatInputPromptProps, type ChatSidebarProps, type ChatStandaloneProps, type MessageHandler, type ChatBaseProps, type ProtocolConfig, type ToolApprovalDialogProps, type PoweredByTagProps, type FloatingBrandButtonProps, type ChatFloatingProps, type ToolCallRenderContext, type ToolCallStatus, type RenderToolResult, type RespondCallback, type Suggestion, type ChatHeaderProps, type ConnectionState, type MessagePartProps, type TextPartProps, type ReasoningPartProps, type ToolPartProps, type DynamicToolPartProps, type ToolCallDisplayProps, type ChatProps, type Transport, type Extension, } from './components';
|
|
59
|
+
export { ChatMessages, ChatInputPrompt, ChatSidebar, ChatStandalone, ChatBase, ToolApprovalDialog, useToolApprovalDialog, PoweredByTag, FloatingBrandButton, ChatHeader, MessagePart, TextPart, ReasoningPart, ToolPart, DynamicToolPart, ToolCallDisplay, Chat, ChatFloating, type ChatMessagesProps, type ChatInputPromptProps, type ChatSidebarProps, type ChatStandaloneProps, type MessageHandler, type ChatBaseProps, type ProtocolConfig, type ToolApprovalDialogProps, type PoweredByTagProps, type FloatingBrandButtonProps, type ChatFloatingProps, type ToolCallRenderContext, type ToolCallStatus, type RenderToolResult, type RespondCallback, type Suggestion, type RemoteConfig, type ModelConfig, type BuiltinTool, type MCPServerConfig, type MCPServerTool, type ChatHeaderProps, type ConnectionState, type MessagePartProps, type TextPartProps, type ReasoningPartProps, type ToolPartProps, type DynamicToolPartProps, type ToolCallDisplayProps, type ChatProps, type Transport, type Extension, } from './components';
|
|
60
60
|
export { requestAPI } from './handler';
|
|
61
61
|
export { useKeyboardShortcuts, useChatKeyboardShortcuts, getShortcutDisplay, type KeyboardShortcut, type UseKeyboardShortcutsOptions, } from '../../hooks';
|
|
@@ -51,6 +51,8 @@ export declare class A2AAdapter extends BaseProtocolAdapter {
|
|
|
51
51
|
tools?: ToolDefinition[];
|
|
52
52
|
threadId?: string;
|
|
53
53
|
metadata?: Record<string, unknown>;
|
|
54
|
+
/** Model to use for this request (overrides agent default) */
|
|
55
|
+
model?: string;
|
|
54
56
|
}): Promise<void>;
|
|
55
57
|
/**
|
|
56
58
|
* Send tool result back
|
|
@@ -137,10 +137,19 @@ export class A2AAdapter extends BaseProtocolAdapter {
|
|
|
137
137
|
configuration: {
|
|
138
138
|
acceptedOutputModes: ['text', 'text/plain'],
|
|
139
139
|
requestedExtensions: this.a2aConfig.enableA2UI ? ['a2ui'] : [],
|
|
140
|
+
// Model override for per-request model selection
|
|
141
|
+
// Note: fasta2a/pydantic-ai A2A doesn't currently support per-request model override
|
|
142
|
+
// The model is configured at agent creation time
|
|
143
|
+
...(options?.model && { model: options.model }),
|
|
140
144
|
},
|
|
145
|
+
// Also send model in metadata for potential future support
|
|
146
|
+
...(options?.model && { metadata: { model: options.model } }),
|
|
141
147
|
},
|
|
142
148
|
id: taskId,
|
|
143
149
|
};
|
|
150
|
+
if (options?.model) {
|
|
151
|
+
console.log('[A2AAdapter] Sending with model:', options.model, '(Note: A2A uses agent-level model, not per-request)');
|
|
152
|
+
}
|
|
144
153
|
try {
|
|
145
154
|
const response = await fetch(this.a2aConfig.baseUrl, {
|
|
146
155
|
method: 'POST',
|
|
@@ -113,6 +113,8 @@ export declare class ACPAdapter extends BaseProtocolAdapter {
|
|
|
113
113
|
tools?: ToolDefinition[];
|
|
114
114
|
threadId?: string;
|
|
115
115
|
metadata?: Record<string, unknown>;
|
|
116
|
+
/** Model to use for this request (overrides agent default) */
|
|
117
|
+
model?: string;
|
|
116
118
|
}): Promise<void>;
|
|
117
119
|
/**
|
|
118
120
|
* Send tool result back through ACP
|
|
@@ -221,9 +221,14 @@ export class ACPAdapter extends BaseProtocolAdapter {
|
|
|
221
221
|
.filter(c => c.type === 'text')
|
|
222
222
|
.map(c => c.text || '')
|
|
223
223
|
.join('');
|
|
224
|
+
if (_options?.model) {
|
|
225
|
+
console.log('[ACPAdapter] Sending with model:', _options.model);
|
|
226
|
+
}
|
|
224
227
|
await this.sendRequest(AGENT_METHODS.session_prompt, {
|
|
225
228
|
sessionId: this.session.sessionId,
|
|
226
229
|
content: [{ type: 'text', text: content }],
|
|
230
|
+
// Include model for per-request model override
|
|
231
|
+
...(_options?.model && { metadata: { model: _options.model } }),
|
|
227
232
|
});
|
|
228
233
|
}
|
|
229
234
|
catch (error) {
|
|
@@ -450,6 +455,14 @@ export class ACPAdapter extends BaseProtocolAdapter {
|
|
|
450
455
|
timestamp: new Date(),
|
|
451
456
|
});
|
|
452
457
|
}
|
|
458
|
+
// Handle error events - emit as error, not as message
|
|
459
|
+
if (params.error) {
|
|
460
|
+
this.emit({
|
|
461
|
+
type: 'error',
|
|
462
|
+
error: new Error(params.error),
|
|
463
|
+
timestamp: new Date(),
|
|
464
|
+
});
|
|
465
|
+
}
|
|
453
466
|
}
|
|
454
467
|
/**
|
|
455
468
|
* Handle permission request from agent
|
|
@@ -52,6 +52,8 @@ export declare class AGUIAdapter extends BaseProtocolAdapter {
|
|
|
52
52
|
metadata?: Record<string, unknown>;
|
|
53
53
|
/** Full conversation history to send with the message */
|
|
54
54
|
messages?: ChatMessage[];
|
|
55
|
+
/** Model to use for this request (overrides agent default) */
|
|
56
|
+
model?: string;
|
|
55
57
|
}): Promise<void>;
|
|
56
58
|
/**
|
|
57
59
|
* Send tool result back through AG-UI and continue the conversation
|
|
@@ -135,7 +135,12 @@ export class AGUIAdapter extends BaseProtocolAdapter {
|
|
|
135
135
|
tools: options?.tools || [],
|
|
136
136
|
context: [],
|
|
137
137
|
forwardedProps: null,
|
|
138
|
+
// Include model for per-request model override
|
|
139
|
+
...(options?.model && { model: options.model }),
|
|
138
140
|
};
|
|
141
|
+
if (options?.model) {
|
|
142
|
+
console.log('[AGUIAdapter] Sending with model:', options.model);
|
|
143
|
+
}
|
|
139
144
|
try {
|
|
140
145
|
const response = await fetch(this.aguiConfig.baseUrl, {
|
|
141
146
|
method: 'POST',
|
|
@@ -35,6 +35,8 @@ export declare abstract class BaseProtocolAdapter implements ProtocolAdapter {
|
|
|
35
35
|
metadata?: Record<string, unknown>;
|
|
36
36
|
/** Full conversation history to send with the message */
|
|
37
37
|
messages?: ChatMessage[];
|
|
38
|
+
/** Model to use for this request (overrides agent default) */
|
|
39
|
+
model?: string;
|
|
38
40
|
}): Promise<void>;
|
|
39
41
|
/**
|
|
40
42
|
* Send tool execution result back
|
|
@@ -57,6 +57,10 @@ export declare class VercelAIAdapter extends BaseProtocolAdapter {
|
|
|
57
57
|
tools?: ToolDefinition[];
|
|
58
58
|
threadId?: string;
|
|
59
59
|
metadata?: Record<string, unknown>;
|
|
60
|
+
/** Model to use for this request (overrides agent default) */
|
|
61
|
+
model?: string;
|
|
62
|
+
/** Full conversation history to send with the message */
|
|
63
|
+
messages?: ChatMessage[];
|
|
60
64
|
}): Promise<void>;
|
|
61
65
|
/**
|
|
62
66
|
* Parse SSE stream from Vercel AI
|
|
@@ -105,7 +105,12 @@ export class VercelAIAdapter extends BaseProtocolAdapter {
|
|
|
105
105
|
trigger: 'submit-message',
|
|
106
106
|
// Optional fields based on Pydantic AI's Vercel adapter
|
|
107
107
|
...(options?.tools && { tools: options.tools }),
|
|
108
|
+
// Model override for per-request model selection
|
|
109
|
+
...(options?.model && { model: options.model }),
|
|
108
110
|
};
|
|
111
|
+
if (options?.model) {
|
|
112
|
+
console.log('[VercelAIAdapter] Sending with model:', options.model);
|
|
113
|
+
}
|
|
109
114
|
// Merge custom headers with defaults
|
|
110
115
|
const headers = {
|
|
111
116
|
'Content-Type': 'application/json',
|
|
@@ -115,6 +115,8 @@ export interface ProtocolAdapter {
|
|
|
115
115
|
metadata?: Record<string, unknown>;
|
|
116
116
|
/** Full conversation history to send with the message */
|
|
117
117
|
messages?: ChatMessage[];
|
|
118
|
+
/** Model to use for this request (overrides agent default) */
|
|
119
|
+
model?: string;
|
|
118
120
|
}): Promise<void>;
|
|
119
121
|
/**
|
|
120
122
|
* Send tool execution result back
|
|
@@ -161,6 +163,8 @@ export declare namespace AGUI {
|
|
|
161
163
|
content: string;
|
|
162
164
|
}>;
|
|
163
165
|
forwardedProps: Record<string, unknown> | null;
|
|
166
|
+
/** Optional model override for per-request model selection */
|
|
167
|
+
model?: string;
|
|
164
168
|
}
|
|
165
169
|
interface Event {
|
|
166
170
|
type: string;
|
|
@@ -239,7 +239,7 @@ function LexicalWithChat({ content, serviceManager, }) {
|
|
|
239
239
|
color: 'danger.fg',
|
|
240
240
|
borderRadius: 2,
|
|
241
241
|
maxWidth: 300,
|
|
242
|
-
}, children: [_jsx("strong", { children: "Error:" }), " ", error] })), isReady && (_jsx(ChatFloating, { endpoint: AG_UI_ENDPOINT, title: "Lexical AI Agent Runtime", description: "Hi! I can help you edit documents. Try: 'Insert a heading', 'Add a code block', or 'Create a list'", defaultOpen: true, defaultViewMode: "panel", position: "bottom-right", brandColor: "#7c3aed", tools: tools, useStore: false, suggestions: [
|
|
242
|
+
}, children: [_jsx("strong", { children: "Error:" }), " ", error] })), isReady && (_jsx(ChatFloating, { endpoint: AG_UI_ENDPOINT, title: "Lexical AI Agent Runtime", description: "Hi! I can help you edit documents. Try: 'Insert a heading', 'Add a code block', or 'Create a list'", defaultOpen: true, defaultViewMode: "panel", position: "bottom-right", brandColor: "#7c3aed", tools: tools, useStore: false, showModelSelector: true, showToolsMenu: true, suggestions: [
|
|
243
243
|
{
|
|
244
244
|
title: 'Insert heading',
|
|
245
245
|
message: 'Insert a heading that says "Welcome"',
|
|
@@ -1,6 +1,28 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { Agent } from '../stores/examplesStore';
|
|
3
3
|
import type { Transport, Extension } from '../../components/chat';
|
|
4
|
+
/**
|
|
5
|
+
* MCP Server Tool type
|
|
6
|
+
*/
|
|
7
|
+
export interface MCPServerTool {
|
|
8
|
+
name: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
enabled: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* MCP Server configuration from backend
|
|
14
|
+
*/
|
|
15
|
+
export interface MCPServerConfig {
|
|
16
|
+
id: string;
|
|
17
|
+
name: string;
|
|
18
|
+
url?: string;
|
|
19
|
+
enabled: boolean;
|
|
20
|
+
tools: MCPServerTool[];
|
|
21
|
+
command?: string;
|
|
22
|
+
args?: string[];
|
|
23
|
+
isAvailable?: boolean;
|
|
24
|
+
transport?: string;
|
|
25
|
+
}
|
|
4
26
|
type AgentLibrary = 'pydantic-ai' | 'langchain' | 'jupyter-ai';
|
|
5
27
|
export type { AgentLibrary };
|
|
6
28
|
export type { Transport };
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
4
|
+
* Distributed under the terms of the Modified BSD License.
|
|
5
|
+
*/
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { Text, TextInput, Button, FormControl, Select, Checkbox, Spinner, Flash, Label, ActionList, } from '@primer/react';
|
|
8
|
+
import { CheckIcon, XIcon, ToolsIcon } from '@primer/octicons-react';
|
|
9
|
+
import { useQuery } from '@tanstack/react-query';
|
|
3
10
|
import { Box } from '@datalayer/primer-addons';
|
|
4
11
|
const AGENT_LIBRARIES = [
|
|
5
12
|
{
|
|
@@ -65,6 +72,21 @@ const EXTENSIONS = [
|
|
|
65
72
|
* Form for configuring agent connection settings.
|
|
66
73
|
*/
|
|
67
74
|
export const AgentConfiguration = ({ agentLibrary, transport, extensions, wsUrl, baseUrl, agentName, agents, selectedAgentId, isCreatingAgent = false, createError = null, onAgentLibraryChange, onTransportChange, onExtensionsChange, onWsUrlChange, onBaseUrlChange, onAgentNameChange, onAgentSelect, onConnect, }) => {
|
|
75
|
+
// Fetch MCP servers configuration from the backend
|
|
76
|
+
const configQuery = useQuery({
|
|
77
|
+
queryKey: ['agent-config', baseUrl],
|
|
78
|
+
queryFn: async () => {
|
|
79
|
+
const response = await fetch(`${baseUrl}/api/v1/configure`);
|
|
80
|
+
if (!response.ok) {
|
|
81
|
+
throw new Error('Failed to fetch configuration');
|
|
82
|
+
}
|
|
83
|
+
return response.json();
|
|
84
|
+
},
|
|
85
|
+
enabled: !!baseUrl,
|
|
86
|
+
staleTime: 1000 * 60 * 5, // 5 minutes
|
|
87
|
+
retry: 1,
|
|
88
|
+
});
|
|
89
|
+
const mcpServers = configQuery.data?.mcpServers || [];
|
|
68
90
|
// Determine which extensions are enabled based on transport
|
|
69
91
|
const isExtensionEnabled = (ext) => {
|
|
70
92
|
if (selectedAgentId !== 'new-agent')
|
|
@@ -95,7 +117,7 @@ export const AgentConfiguration = ({ agentLibrary, transport, extensions, wsUrl,
|
|
|
95
117
|
fontWeight: 'bold',
|
|
96
118
|
display: 'block',
|
|
97
119
|
marginBottom: 3,
|
|
98
|
-
}, children: "
|
|
120
|
+
}, children: "Create a new Agent" }), _jsxs(FormControl, { sx: { marginBottom: 3 }, children: [_jsx(FormControl.Label, { children: "Available Agents" }), _jsxs(Select, { value: selectedAgentId, onChange: e => onAgentSelect(e.target.value), sx: { width: '100%' }, children: [_jsx(Select.Option, { value: "new-agent", children: "+ New Agent..." }), agents.map(agent => (_jsxs(Select.Option, { value: agent.id, children: [agent.status === 'running' && '● ', agent.name] }, agent.id)))] }), _jsx(FormControl.Caption, { children: selectedAgentId === 'new-agent'
|
|
99
121
|
? 'Configure a new custom agent'
|
|
100
122
|
: 'Selected agent - form fields below are disabled' })] }), _jsxs(Box, { sx: { display: 'flex', gap: 3, marginBottom: 3 }, children: [_jsxs(FormControl, { sx: { flex: 1 }, children: [_jsx(FormControl.Label, { children: "Agent Library" }), _jsx(Select, { value: agentLibrary, onChange: e => onAgentLibraryChange(e.target.value), disabled: selectedAgentId !== 'new-agent', sx: { width: '100%' }, children: AGENT_LIBRARIES.map(lib => (_jsxs(Select.Option, { value: lib.value, disabled: lib.disabled, children: [lib.label, lib.disabled && ' (Coming Soon)'] }, lib.value))) })] }), _jsxs(FormControl, { sx: { flex: 1 }, children: [_jsx(FormControl.Label, { children: "Transport" }), _jsx(Select, { value: transport, onChange: e => onTransportChange(e.target.value), disabled: selectedAgentId !== 'new-agent', sx: { width: '100%' }, children: TRANSPORTS.map(t => (_jsx(Select.Option, { value: t.value, children: t.label }, t.value))) })] }), _jsxs(FormControl, { sx: { flex: 1 }, children: [_jsx(FormControl.Label, { children: "Extensions" }), _jsx(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 2 }, children: EXTENSIONS.map(ext => (_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(Checkbox, { value: ext.value, checked: extensions.includes(ext.value), disabled: !isExtensionEnabled(ext.value), onChange: e => handleExtensionChange(ext.value, e.target.checked) }), _jsx(Text, { children: ext.label })] }, ext.value))) })] })] }), _jsxs(FormControl, { sx: { marginBottom: 3 }, children: [_jsx(FormControl.Label, { children: transport === 'acp' ? 'WebSocket URL' : 'Base URL' }), _jsx(TextInput, { value: transport === 'acp' ? wsUrl : baseUrl, onChange: e => transport === 'acp'
|
|
101
123
|
? onWsUrlChange(e.target.value)
|
|
@@ -103,7 +125,21 @@ export const AgentConfiguration = ({ agentLibrary, transport, extensions, wsUrl,
|
|
|
103
125
|
? 'ws://localhost:8000/api/v1/acp/ws'
|
|
104
126
|
: 'http://localhost:8000', sx: { width: '100%' } }), _jsx(FormControl.Caption, { children: transport === 'acp'
|
|
105
127
|
? 'The WebSocket endpoint of your agent-runtimes server'
|
|
106
|
-
: 'The base URL of your agent-runtimes server' })] }), _jsxs(FormControl, { sx: { marginBottom: 3 }, children: [_jsx(FormControl.Label, { children: "Agent Name" }), _jsx(TextInput, { value: agentName, onChange: e => onAgentNameChange(e.target.value), disabled: selectedAgentId !== 'new-agent', placeholder: "demo-agent", sx: { width: '100%' } }), _jsx(FormControl.Caption, { children: "The name of the agent to connect to" })] }), _jsxs(
|
|
128
|
+
: 'The base URL of your agent-runtimes server' })] }), _jsxs(FormControl, { sx: { marginBottom: 3 }, children: [_jsx(FormControl.Label, { children: "Agent Name" }), _jsx(TextInput, { value: agentName, onChange: e => onAgentNameChange(e.target.value), disabled: selectedAgentId !== 'new-agent', placeholder: "demo-agent", sx: { width: '100%' } }), _jsx(FormControl.Caption, { children: "The name of the agent to connect to" })] }), _jsxs(Box, { sx: {
|
|
129
|
+
marginBottom: 3,
|
|
130
|
+
padding: 3,
|
|
131
|
+
border: '1px solid',
|
|
132
|
+
borderColor: 'border.default',
|
|
133
|
+
borderRadius: 2,
|
|
134
|
+
backgroundColor: 'canvas.default',
|
|
135
|
+
}, children: [_jsxs(Box, { sx: {
|
|
136
|
+
display: 'flex',
|
|
137
|
+
alignItems: 'center',
|
|
138
|
+
gap: 2,
|
|
139
|
+
marginBottom: 2,
|
|
140
|
+
}, children: [_jsx(ToolsIcon, { size: 16 }), _jsx(Text, { sx: { fontSize: 1, fontWeight: 'bold' }, children: "MCP Servers" }), configQuery.isLoading && _jsx(Spinner, { size: "small" })] }), configQuery.isError && (_jsx(Flash, { variant: "warning", sx: { marginBottom: 2 }, children: _jsx(Text, { sx: { fontSize: 0 }, children: "Unable to fetch MCP servers. Check that the server is running." }) })), mcpServers.length === 0 &&
|
|
141
|
+
!configQuery.isLoading &&
|
|
142
|
+
!configQuery.isError && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "No MCP servers configured." })), mcpServers.length > 0 && (_jsx(ActionList, { children: mcpServers.map((server, index) => (_jsxs(React.Fragment, { children: [index > 0 && _jsx(ActionList.Divider, {}), _jsxs(ActionList.Item, { disabled: true, children: [_jsx(ActionList.LeadingVisual, { children: server.isAvailable ? (_jsx(CheckIcon, { size: 16 })) : (_jsx(XIcon, { size: 16 })) }), _jsxs(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 1 }, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(Text, { sx: { fontWeight: 'semibold' }, children: server.name }), _jsx(Label, { variant: server.isAvailable ? 'success' : 'secondary', size: "small", children: server.isAvailable ? 'Available' : 'Not Available' })] }), server.tools.length > 0 && (_jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: ["Tools: ", server.tools.map(t => t.name).join(', ')] }))] })] })] }, server.id))) }))] }), createError && (_jsx(Flash, { variant: "danger", sx: { marginBottom: 3 }, children: createError })), _jsx(Button, { variant: "primary", onClick: onConnect, disabled: isCreatingAgent ||
|
|
107
143
|
!agentName ||
|
|
108
144
|
(transport === 'acp' ? !wsUrl : !baseUrl), sx: { width: '100%' }, children: isCreatingAgent ? (_jsxs(Box, { sx: {
|
|
109
145
|
display: 'flex',
|
|
@@ -8,4 +8,4 @@ export { TimeTravel } from './TimeTravel';
|
|
|
8
8
|
export { LexicalEditor } from './LexicalEditor';
|
|
9
9
|
export { Rating } from './Rating';
|
|
10
10
|
export { AgentConfiguration, AGENT_LIBRARIES, TRANSPORTS, EXTENSIONS, } from './AgentConfiguration';
|
|
11
|
-
export type { AgentLibrary, Transport, Extension } from './AgentConfiguration';
|
|
11
|
+
export type { AgentLibrary, Transport, Extension, MCPServerConfig, MCPServerTool, } from './AgentConfiguration';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stub for keytar module in browser environments.
|
|
3
|
+
* keytar is a native Node.js module for system keychain access
|
|
4
|
+
* and cannot run in the browser.
|
|
5
|
+
*/
|
|
6
|
+
export declare const getPassword: (_service: string, _account: string) => Promise<string | null>;
|
|
7
|
+
export declare const setPassword: (_service: string, _account: string, _password: string) => Promise<void>;
|
|
8
|
+
export declare const deletePassword: (_service: string, _account: string) => Promise<boolean>;
|
|
9
|
+
export declare const findPassword: (_service: string) => Promise<string | null>;
|
|
10
|
+
export declare const findCredentials: (_service: string) => Promise<Array<{
|
|
11
|
+
account: string;
|
|
12
|
+
password: string;
|
|
13
|
+
}>>;
|
|
14
|
+
export declare const getPasswordSync: (_service: string, _account: string) => string | null;
|
|
15
|
+
export declare const setPasswordSync: (_service: string, _account: string, _password: string) => void;
|
|
16
|
+
export declare const deletePasswordSync: (_service: string, _account: string) => boolean;
|
|
17
|
+
declare const _default: {
|
|
18
|
+
getPassword: (_service: string, _account: string) => Promise<string | null>;
|
|
19
|
+
setPassword: (_service: string, _account: string, _password: string) => Promise<void>;
|
|
20
|
+
deletePassword: (_service: string, _account: string) => Promise<boolean>;
|
|
21
|
+
findPassword: (_service: string) => Promise<string | null>;
|
|
22
|
+
findCredentials: (_service: string) => Promise<Array<{
|
|
23
|
+
account: string;
|
|
24
|
+
password: string;
|
|
25
|
+
}>>;
|
|
26
|
+
getPasswordSync: (_service: string, _account: string) => string | null;
|
|
27
|
+
setPasswordSync: (_service: string, _account: string, _password: string) => void;
|
|
28
|
+
deletePasswordSync: (_service: string, _account: string) => boolean;
|
|
29
|
+
};
|
|
30
|
+
export default _default;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Stub for keytar module in browser environments.
|
|
7
|
+
* keytar is a native Node.js module for system keychain access
|
|
8
|
+
* and cannot run in the browser.
|
|
9
|
+
*/
|
|
10
|
+
export const getPassword = async (_service, _account) => null;
|
|
11
|
+
export const setPassword = async (_service, _account, _password) => { };
|
|
12
|
+
export const deletePassword = async (_service, _account) => false;
|
|
13
|
+
export const findPassword = async (_service) => null;
|
|
14
|
+
export const findCredentials = async (_service) => [];
|
|
15
|
+
// Sync versions (if any code tries to use them)
|
|
16
|
+
export const getPasswordSync = (_service, _account) => null;
|
|
17
|
+
export const setPasswordSync = (_service, _account, _password) => { };
|
|
18
|
+
export const deletePasswordSync = (_service, _account) => false;
|
|
19
|
+
export default {
|
|
20
|
+
getPassword,
|
|
21
|
+
setPassword,
|
|
22
|
+
deletePassword,
|
|
23
|
+
findPassword,
|
|
24
|
+
findCredentials,
|
|
25
|
+
getPasswordSync,
|
|
26
|
+
setPasswordSync,
|
|
27
|
+
deletePasswordSync,
|
|
28
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datalayer/agent-runtimes",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"workspaces": [
|
|
6
6
|
".",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"clean:dist": "rimraf dist",
|
|
66
66
|
"clean:lib": "rimraf lib tsconfig.tsbuildinfo",
|
|
67
67
|
"create:patches": "bash scripts/create-patches.sh",
|
|
68
|
-
"examples": "run-p
|
|
68
|
+
"examples": "run-p server:start examples:vite",
|
|
69
69
|
"examples:fresh": "npm run clean:cache && npm run examples",
|
|
70
70
|
"examples:nextjs": "npm run dev --workspace=nextjs-notebook-example",
|
|
71
71
|
"examples:vite": "VITE_APP_TARGET=examples VITE_DATALAYER_RUN_URL=http://localhost:8888 vite",
|
|
@@ -118,9 +118,9 @@
|
|
|
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": "
|
|
121
|
+
"@ai-sdk/react": "3.0.0-beta.172",
|
|
122
122
|
"@anthropic-ai/sdk": "^0.52.0",
|
|
123
|
-
"@datalayer/core": "^0.0.
|
|
123
|
+
"@datalayer/core": "^0.0.24",
|
|
124
124
|
"@datalayer/icons-react": "^1.0.6",
|
|
125
125
|
"@datalayer/jupyter-lexical": "^1.0.6",
|
|
126
126
|
"@datalayer/jupyter-react": "^2.0.0",
|
|
@@ -281,6 +281,7 @@
|
|
|
281
281
|
"vitest": "^3.2.4"
|
|
282
282
|
},
|
|
283
283
|
"resolutions": {
|
|
284
|
+
"@ai-sdk/react": "3.0.0-beta.172",
|
|
284
285
|
"@microsoft/fast-colors": "5.3.1",
|
|
285
286
|
"@microsoft/fast-components": "2.30.6",
|
|
286
287
|
"@microsoft/fast-element": "1.13.0",
|
|
@@ -297,6 +298,7 @@
|
|
|
297
298
|
"typescript": "^5.8.3"
|
|
298
299
|
},
|
|
299
300
|
"overrides": {
|
|
301
|
+
"@ai-sdk/react": "3.0.0-beta.172",
|
|
300
302
|
"@microsoft/fast-colors": "5.3.1",
|
|
301
303
|
"@microsoft/fast-components": "2.30.6",
|
|
302
304
|
"@microsoft/fast-element": "1.13.0",
|
package/style/base.css
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
3
3
|
* Distributed under the terms of the Modified BSD License.
|
|
4
4
|
*/
|
|
5
|
+
|
|
5
6
|
/*
|
|
6
7
|
---break---
|
|
7
8
|
*/
|
|
@@ -64,49 +65,6 @@ body {
|
|
|
64
65
|
/* --jp-ui-font-size1: 12px; */
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
.Primer_Brand__Hero-module__Hero___EM3jf {
|
|
68
|
-
padding-top: 88px;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
#dla-hero .Primer_Brand__Heading-module__Heading--1___Ufc7G {
|
|
72
|
-
font-size: 62px;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
#dla-hero .Primer_Brand__Grid-module__Grid___q48mT {
|
|
76
|
-
grid-column-gap: 12px !important;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
#dla-hero .Primer_Brand__Text-module__Text___pecHN {
|
|
80
|
-
max-width: 1000px;
|
|
81
|
-
padding-right: 15px;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
#dla-hero .Primer_Brand__Text-module__Text___pecHN {
|
|
85
|
-
line-height: 16px;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/* TODO Check the specificity of this rule */
|
|
89
|
-
.jp-ThemedContainer a {
|
|
90
|
-
color: var(--jp-brand-color1, #1976d2) !important;
|
|
91
|
-
text-decoration: none !important
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
.jp-Shout-button {
|
|
95
|
-
height: 30px;
|
|
96
|
-
width: 150px;
|
|
97
|
-
margin: 8px;
|
|
98
|
-
padding-top: 9px;
|
|
99
|
-
text-align: center;
|
|
100
|
-
vertical-align: middle;
|
|
101
|
-
border-radius: 2px;
|
|
102
|
-
background-color: #2296f3;
|
|
103
|
-
color: #212121;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
.jp-Shout-summary {
|
|
107
|
-
margin: 4px;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
68
|
/*
|
|
111
69
|
---break---
|
|
112
70
|
*/
|