@datalayer/agent-runtimes 0.0.2 → 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/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 +6 -0
- package/lib/components/chat/protocols/VercelAIAdapter.js +10 -0
- package/lib/components/chat/types/protocol.d.ts +4 -0
- package/lib/examples/AgentRuntimeCustomExample.d.ts +2 -1
- package/lib/examples/AgentRuntimeCustomExample.js +120 -5
- 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/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/lib/stubs/keytar.d.ts +30 -0
- package/lib/stubs/keytar.js +28 -0
- package/package.json +9 -7
- 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
|