@datalayer/agent-runtimes 0.0.5 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +150 -22
- package/lib/components/chat/components/AgentDetails.d.ts +15 -2
- package/lib/components/chat/components/AgentDetails.js +9 -93
- package/lib/components/chat/components/AgentIdentity.d.ts +92 -0
- package/lib/components/chat/components/AgentIdentity.js +318 -0
- package/lib/components/chat/components/Chat.d.ts +24 -1
- package/lib/components/chat/components/Chat.js +41 -19
- package/lib/components/chat/components/ChatFloating.d.ts +6 -1
- package/lib/components/chat/components/ChatFloating.js +12 -6
- package/lib/components/chat/components/ContextDistribution.d.ts +47 -0
- package/lib/components/chat/components/ContextDistribution.js +146 -0
- package/lib/components/chat/components/ContextUsage.d.ts +33 -0
- package/lib/components/chat/components/ContextUsage.js +127 -0
- package/lib/components/chat/components/base/ChatBase.d.ts +51 -1
- package/lib/components/chat/components/base/ChatBase.js +278 -74
- package/lib/components/chat/components/display/ToolCallDisplay.d.ts +16 -2
- package/lib/components/chat/components/display/ToolCallDisplay.js +148 -6
- package/lib/components/chat/components/display/index.d.ts +1 -1
- package/lib/components/chat/components/display/index.js +1 -1
- package/lib/components/chat/components/elements/ChatInputPrompt.d.ts +12 -1
- package/lib/components/chat/components/elements/ChatInputPrompt.js +8 -3
- package/lib/components/chat/components/index.d.ts +3 -0
- package/lib/components/chat/components/index.js +3 -0
- package/lib/components/chat/components/parts/ToolPart.d.ts +1 -1
- package/lib/components/chat/components/parts/ToolPart.js +142 -6
- package/lib/components/chat/index.d.ts +1 -1
- package/lib/components/chat/index.js +1 -1
- package/lib/components/chat/protocols/A2AAdapter.d.ts +9 -0
- package/lib/components/chat/protocols/A2AAdapter.js +13 -2
- package/lib/components/chat/protocols/ACPAdapter.d.ts +9 -0
- package/lib/components/chat/protocols/ACPAdapter.js +13 -2
- package/lib/components/chat/protocols/AGUIAdapter.d.ts +9 -0
- package/lib/components/chat/protocols/AGUIAdapter.js +19 -1
- package/lib/components/chat/protocols/VercelAIAdapter.d.ts +7 -0
- package/lib/components/chat/protocols/VercelAIAdapter.js +19 -0
- package/lib/components/chat/types/execution.d.ts +78 -0
- package/lib/components/chat/types/execution.js +64 -0
- package/lib/components/chat/types/index.d.ts +1 -0
- package/lib/components/chat/types/index.js +1 -0
- package/lib/components/chat/types/protocol.d.ts +9 -0
- package/lib/components/ui/pagination.d.ts +2 -2
- package/lib/components/ui/pagination.js +4 -4
- package/lib/components/ui/resizable.d.ts +4 -4
- package/lib/components/ui/resizable.js +4 -4
- package/lib/examples/A2UiRestaurantExample.js +2 -2
- package/lib/examples/AgUiAgenticExample.js +2 -2
- package/lib/examples/AgUiBackendToolRenderingExample.js +2 -2
- package/lib/examples/AgUiHaikuGenUIExample.js +2 -2
- package/lib/examples/AgUiHumanInTheLoopExample.js +2 -2
- package/lib/examples/AgUiSharedStateExample.js +2 -2
- package/lib/examples/AgUiToolsBasedGenUIExample.js +2 -2
- package/lib/examples/AgentRuntimeCustomExample.js +2 -2
- package/lib/examples/AgentRuntimeLexical2Example.js +2 -1
- package/lib/examples/AgentRuntimeLexicalExample.js +5 -2
- package/lib/examples/AgentRuntimeLexicalSidebarExample.js +4 -2
- package/lib/examples/AgentRuntimeNotebookExample.js +1 -1
- package/lib/examples/AgentRuntimeStandaloneExample.js +2 -2
- package/lib/examples/AgentSpaceFormExample.d.ts +70 -2
- package/lib/examples/AgentSpaceFormExample.js +204 -35
- package/lib/examples/CopilotKitLexicalExample.js +2 -1
- package/lib/examples/components/AgentConfiguration.d.ts +37 -0
- package/lib/examples/components/AgentConfiguration.js +239 -8
- package/lib/examples/components/Header.d.ts +0 -2
- package/lib/examples/components/Header.js +2 -16
- package/lib/examples/components/LexicalEditor.js +2 -1
- package/lib/examples/components/MockFileBrowser.js +6 -2
- package/lib/examples/components/index.d.ts +0 -1
- package/lib/examples/components/index.js +0 -1
- package/lib/examples/example-selector.js +0 -1
- package/lib/examples/index.d.ts +0 -1
- package/lib/examples/index.js +0 -1
- package/lib/examples/lexical/editorConfig.d.ts +3 -2
- package/lib/examples/lexical/editorConfig.js +7 -1
- package/lib/examples/lexical/initial-content.json +2210 -0
- package/lib/examples/main.js +15 -1
- package/lib/identity/IdentityConnect.d.ts +90 -0
- package/lib/identity/IdentityConnect.js +316 -0
- package/lib/identity/OAuthCallback.d.ts +58 -0
- package/lib/identity/OAuthCallback.js +223 -0
- package/lib/identity/dcr.d.ts +257 -0
- package/lib/identity/dcr.js +282 -0
- package/lib/identity/identityStore.d.ts +72 -0
- package/lib/identity/identityStore.js +529 -0
- package/lib/identity/index.d.ts +46 -0
- package/lib/identity/index.js +17 -0
- package/lib/identity/pkce.d.ts +30 -0
- package/lib/identity/pkce.js +65 -0
- package/lib/identity/types.d.ts +293 -0
- package/lib/identity/types.js +73 -0
- package/lib/identity/useIdentity.d.ts +108 -0
- package/lib/identity/useIdentity.js +323 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +2 -0
- package/lib/lib/utils.js +1 -1
- package/lib/renderers/a2ui/lib/utils.js +1 -1
- package/lib/runtime/index.d.ts +35 -0
- package/lib/runtime/index.js +40 -0
- package/lib/runtime/runtimeStore.d.ts +77 -0
- package/lib/runtime/runtimeStore.js +184 -0
- package/lib/runtime/types.d.ts +84 -0
- package/lib/runtime/types.js +15 -0
- package/lib/runtime/useAgentConnection.d.ts +46 -0
- package/lib/runtime/useAgentConnection.js +112 -0
- package/lib/runtime/useAgentRuntime.d.ts +94 -0
- package/lib/runtime/useAgentRuntime.js +125 -0
- package/lib/test-setup.d.ts +1 -1
- package/lib/test-setup.js +1 -0
- package/lib/tools/adapters/agent-runtimes/AgentRuntimesToolAdapter.js +32 -1
- package/lib/tools/adapters/agent-runtimes/lexicalHooks.d.ts +6 -0
- package/lib/tools/adapters/agent-runtimes/lexicalHooks.js +16 -17
- package/package.json +20 -7
- package/patches/@datalayer+jupyter-lexical+1.0.8.patch +11628 -0
- package/patches/@datalayer+jupyter-react+2.0.2.patch +5338 -0
- package/lib/examples/AgentSpaceHomeExample.d.ts +0 -8
- package/lib/examples/AgentSpaceHomeExample.js +0 -171
- package/lib/examples/components/AgentsDataTable.d.ts +0 -13
- package/lib/examples/components/AgentsDataTable.js +0 -74
- package/lib/examples/components/Rating.d.ts +0 -14
- package/lib/examples/components/Rating.js +0 -12
|
@@ -19,7 +19,7 @@ import { useContext } from 'react';
|
|
|
19
19
|
import { useCallback, useEffect, useRef, useState, } from 'react';
|
|
20
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
|
-
import { AlertIcon, PlusIcon, TrashIcon, GearIcon, PersonIcon, PaperAirplaneIcon, SquareCircleIcon, ToolsIcon, AiModelIcon, } from '@primer/octicons-react';
|
|
22
|
+
import { AlertIcon, PlusIcon, TrashIcon, GearIcon, PersonIcon, PaperAirplaneIcon, SquareCircleIcon, ToolsIcon, AiModelIcon, BriefcaseIcon, } from '@primer/octicons-react';
|
|
23
23
|
import { AiAgentIcon } from '@datalayer/icons-react';
|
|
24
24
|
import { useQuery, QueryClient, QueryClientProvider, QueryClientContext, } from '@tanstack/react-query';
|
|
25
25
|
import { Streamdown } from 'streamdown';
|
|
@@ -157,31 +157,75 @@ function useConfigQuery(enabled, configEndpoint, authToken) {
|
|
|
157
157
|
enabled,
|
|
158
158
|
});
|
|
159
159
|
}
|
|
160
|
+
/**
|
|
161
|
+
* Hook to fetch available skills from backend
|
|
162
|
+
*/
|
|
163
|
+
function useSkillsQuery(enabled, baseEndpoint, authToken) {
|
|
164
|
+
const queryClient = useContext(QueryClientContext);
|
|
165
|
+
// If no QueryClient is available, return a mock result
|
|
166
|
+
if (!queryClient) {
|
|
167
|
+
return {
|
|
168
|
+
data: undefined,
|
|
169
|
+
isLoading: false,
|
|
170
|
+
isError: false,
|
|
171
|
+
error: null,
|
|
172
|
+
refetch: () => Promise.resolve({ data: undefined }),
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
176
|
+
return useQuery({
|
|
177
|
+
queryFn: async () => {
|
|
178
|
+
if (!baseEndpoint) {
|
|
179
|
+
return { skills: [], total: 0 };
|
|
180
|
+
}
|
|
181
|
+
// Derive skills endpoint from config endpoint
|
|
182
|
+
const skillsEndpoint = baseEndpoint.replace('/configure', '/skills');
|
|
183
|
+
const headers = {
|
|
184
|
+
'Content-Type': 'application/json',
|
|
185
|
+
};
|
|
186
|
+
if (authToken) {
|
|
187
|
+
headers['Authorization'] = `Bearer ${authToken}`;
|
|
188
|
+
}
|
|
189
|
+
const response = await fetch(skillsEndpoint, { headers });
|
|
190
|
+
if (!response.ok) {
|
|
191
|
+
throw new Error(`Skills fetch failed: ${response.statusText}`);
|
|
192
|
+
}
|
|
193
|
+
return response.json();
|
|
194
|
+
},
|
|
195
|
+
queryKey: ['skills', baseEndpoint || 'jupyter'],
|
|
196
|
+
enabled,
|
|
197
|
+
staleTime: 5 * 60 * 1000, // 5 minutes
|
|
198
|
+
});
|
|
199
|
+
}
|
|
160
200
|
/**
|
|
161
201
|
* ChatBase component - Universal chat panel supporting store, protocol, and custom modes
|
|
162
202
|
*/
|
|
163
|
-
export function ChatBase({ title, showHeader = false, showLoadingIndicator = true, showErrors = true, showInput = true, showModelSelector = false, showToolsMenu = false, className, loadingState, headerActions,
|
|
203
|
+
export function ChatBase({ title, showHeader = false, showLoadingIndicator = true, showErrors = true, showInput = true, showModelSelector = false, showToolsMenu = false, showSkillsMenu = false, codemodeEnabled = false, initialModel, initialMcpServers, initialSkills, className, loadingState, headerActions,
|
|
164
204
|
// Mode selection
|
|
165
205
|
useStore: useStoreMode = true, protocol, onSendMessage, enableStreaming = false,
|
|
166
206
|
// Extended props
|
|
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,
|
|
207
|
+
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,
|
|
208
|
+
// Identity/Authorization props
|
|
209
|
+
onAuthorizationRequired, connectedIdentities, }) {
|
|
168
210
|
// Check if QueryClientProvider is already available
|
|
169
211
|
const existingQueryClient = useContext(QueryClientContext);
|
|
170
212
|
// If no QueryClient is available, wrap with our internal provider
|
|
171
213
|
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 }) }));
|
|
214
|
+
return (_jsx(QueryClientProvider, { client: internalQueryClient, children: _jsx(ChatBaseInner, { title: title, showHeader: showHeader, showLoadingIndicator: showLoadingIndicator, showErrors: showErrors, showInput: showInput, showModelSelector: showModelSelector, showToolsMenu: showToolsMenu, showSkillsMenu: showSkillsMenu, codemodeEnabled: codemodeEnabled, initialModel: initialModel, initialMcpServers: initialMcpServers, initialSkills: initialSkills, 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, onAuthorizationRequired: onAuthorizationRequired, connectedIdentities: connectedIdentities }) }));
|
|
173
215
|
}
|
|
174
216
|
// 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 }));
|
|
217
|
+
return (_jsx(ChatBaseInner, { title: title, showHeader: showHeader, showLoadingIndicator: showLoadingIndicator, showErrors: showErrors, showInput: showInput, showModelSelector: showModelSelector, showToolsMenu: showToolsMenu, showSkillsMenu: showSkillsMenu, codemodeEnabled: codemodeEnabled, initialModel: initialModel, initialMcpServers: initialMcpServers, initialSkills: initialSkills, 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, onAuthorizationRequired: onAuthorizationRequired, connectedIdentities: connectedIdentities }));
|
|
176
218
|
}
|
|
177
219
|
/**
|
|
178
220
|
* Inner ChatBase component - contains all the actual logic
|
|
179
221
|
*/
|
|
180
|
-
function ChatBaseInner({ title, showHeader = false, showLoadingIndicator = true, showErrors = true, showInput = true, showModelSelector = false, showToolsMenu = false, className, loadingState, headerActions,
|
|
222
|
+
function ChatBaseInner({ title, showHeader = false, showLoadingIndicator = true, showErrors = true, showInput = true, showModelSelector = false, showToolsMenu = false, showSkillsMenu = false, codemodeEnabled = false, initialModel, initialMcpServers, initialSkills, className, loadingState, headerActions,
|
|
181
223
|
// Mode selection
|
|
182
224
|
useStore: useStoreMode = true, protocol, onSendMessage, enableStreaming = false,
|
|
183
225
|
// 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,
|
|
226
|
+
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,
|
|
227
|
+
// Identity/Authorization props
|
|
228
|
+
onAuthorizationRequired, connectedIdentities, }) {
|
|
185
229
|
// Ensure Primer's default portal has high z-index for ActionMenu overlays
|
|
186
230
|
useHighZIndexPortal();
|
|
187
231
|
// Store (optional for message persistence)
|
|
@@ -202,9 +246,13 @@ brandIcon, avatarConfig, headerButtons, showPoweredBy = false, poweredByProps, e
|
|
|
202
246
|
// Note: legacy _enabledTools for backend-defined tools from config query
|
|
203
247
|
// Frontend tools are passed via frontendTools prop
|
|
204
248
|
const [_enabledTools, setEnabledTools] = useState([]);
|
|
249
|
+
// Skills state - tracks which skills are enabled
|
|
250
|
+
const [enabledSkills, setEnabledSkills] = useState(new Set());
|
|
205
251
|
// Config query (for protocols that support it)
|
|
206
252
|
// Safely handles missing QueryClientProvider
|
|
207
253
|
const configQuery = useConfigQuery(Boolean(protocol?.enableConfigQuery), protocol?.configEndpoint, protocol?.authToken);
|
|
254
|
+
// Skills query (for protocols that support it)
|
|
255
|
+
const skillsQuery = useSkillsQuery(Boolean(protocol?.enableConfigQuery) && showSkillsMenu, protocol?.configEndpoint, protocol?.authToken);
|
|
208
256
|
// Refs
|
|
209
257
|
const adapterRef = useRef(null);
|
|
210
258
|
const unsubscribeRef = useRef(null);
|
|
@@ -214,6 +262,10 @@ brandIcon, avatarConfig, headerButtons, showPoweredBy = false, poweredByProps, e
|
|
|
214
262
|
const messagesEndRef = useRef(null);
|
|
215
263
|
const inputRef = useRef(null);
|
|
216
264
|
const abortControllerRef = useRef(null);
|
|
265
|
+
// Use a ref for connectedIdentities to avoid infinite loops in useCallback
|
|
266
|
+
// (the array reference changes on every render even if contents are the same)
|
|
267
|
+
const connectedIdentitiesRef = useRef(connectedIdentities);
|
|
268
|
+
connectedIdentitiesRef.current = connectedIdentities;
|
|
217
269
|
// Auto-focus input on mount
|
|
218
270
|
useEffect(() => {
|
|
219
271
|
if (autoFocus && inputRef.current) {
|
|
@@ -255,7 +307,8 @@ brandIcon, avatarConfig, headerButtons, showPoweredBy = false, poweredByProps, e
|
|
|
255
307
|
textarea.style.height = 'auto';
|
|
256
308
|
// Set height to scrollHeight, capped at maxHeight (120px)
|
|
257
309
|
const maxHeight = 120;
|
|
258
|
-
const
|
|
310
|
+
const minHeight = 40;
|
|
311
|
+
const newHeight = Math.min(Math.max(textarea.scrollHeight, minHeight), maxHeight);
|
|
259
312
|
textarea.style.height = `${newHeight}px`;
|
|
260
313
|
// Add overflow if content exceeds maxHeight
|
|
261
314
|
textarea.style.overflowY =
|
|
@@ -266,30 +319,66 @@ brandIcon, avatarConfig, headerButtons, showPoweredBy = false, poweredByProps, e
|
|
|
266
319
|
useEffect(() => {
|
|
267
320
|
adjustTextareaHeight();
|
|
268
321
|
}, [input, adjustTextareaHeight]);
|
|
322
|
+
// Ensure textarea has a minimum height on mount
|
|
323
|
+
useEffect(() => {
|
|
324
|
+
const timer = setTimeout(adjustTextareaHeight, 0);
|
|
325
|
+
return () => clearTimeout(timer);
|
|
326
|
+
}, [adjustTextareaHeight]);
|
|
269
327
|
// Initialize model and tools when config is available
|
|
270
328
|
useEffect(() => {
|
|
271
329
|
if (configQuery.data && !selectedModel) {
|
|
272
|
-
//
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
330
|
+
// Use initialModel if provided, otherwise select first available model
|
|
331
|
+
if (initialModel) {
|
|
332
|
+
// Check if the initial model exists in the config
|
|
333
|
+
const modelExists = configQuery.data.models.some(m => m.id === initialModel);
|
|
334
|
+
if (modelExists) {
|
|
335
|
+
setSelectedModel(initialModel);
|
|
336
|
+
}
|
|
337
|
+
else {
|
|
338
|
+
// Fallback to first available model if initialModel not found
|
|
339
|
+
const firstAvailableModel = configQuery.data.models.find(m => m.isAvailable !== false);
|
|
340
|
+
const firstModel = firstAvailableModel || configQuery.data.models[0];
|
|
341
|
+
if (firstModel) {
|
|
342
|
+
setSelectedModel(firstModel.id);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
else {
|
|
347
|
+
// No initialModel provided, select first available model
|
|
348
|
+
const firstAvailableModel = configQuery.data.models.find(m => m.isAvailable !== false);
|
|
349
|
+
const firstModel = firstAvailableModel || configQuery.data.models[0];
|
|
350
|
+
if (firstModel) {
|
|
351
|
+
setSelectedModel(firstModel.id);
|
|
352
|
+
}
|
|
279
353
|
}
|
|
280
|
-
|
|
354
|
+
const allToolIds = configQuery.data.builtinTools?.map(tool => tool.id) || [];
|
|
355
|
+
setEnabledTools(allToolIds);
|
|
356
|
+
// Initialize MCP server tools
|
|
281
357
|
if (configQuery.data.mcpServers) {
|
|
282
358
|
const newEnabledMcpTools = new Map();
|
|
283
359
|
for (const server of configQuery.data.mcpServers) {
|
|
284
360
|
if (server.isAvailable && server.enabled) {
|
|
285
|
-
|
|
286
|
-
|
|
361
|
+
// If initialMcpServers is provided, only enable those servers
|
|
362
|
+
// If not provided, enable all available servers
|
|
363
|
+
const shouldEnableServer = initialMcpServers
|
|
364
|
+
? initialMcpServers.includes(server.id)
|
|
365
|
+
: true;
|
|
366
|
+
if (shouldEnableServer) {
|
|
367
|
+
const enabledToolNames = new Set(server.tools.filter(t => t.enabled).map(t => t.name));
|
|
368
|
+
newEnabledMcpTools.set(server.id, enabledToolNames);
|
|
369
|
+
}
|
|
287
370
|
}
|
|
288
371
|
}
|
|
289
372
|
setEnabledMcpTools(newEnabledMcpTools);
|
|
290
373
|
}
|
|
291
374
|
}
|
|
292
|
-
}, [configQuery.data, selectedModel]);
|
|
375
|
+
}, [configQuery.data, selectedModel, initialModel, initialMcpServers]);
|
|
376
|
+
// Initialize enabled skills from initialSkills prop
|
|
377
|
+
useEffect(() => {
|
|
378
|
+
if (initialSkills && initialSkills.length > 0) {
|
|
379
|
+
setEnabledSkills(new Set(initialSkills));
|
|
380
|
+
}
|
|
381
|
+
}, [initialSkills]);
|
|
293
382
|
// Helper to toggle MCP tool enabled state
|
|
294
383
|
const toggleMcpTool = useCallback((serverId, toolName) => {
|
|
295
384
|
setEnabledMcpTools(prev => {
|
|
@@ -318,6 +407,23 @@ brandIcon, avatarConfig, headerButtons, showPoweredBy = false, poweredByProps, e
|
|
|
318
407
|
return newMap;
|
|
319
408
|
});
|
|
320
409
|
}, []);
|
|
410
|
+
// Helper to toggle skill enabled state
|
|
411
|
+
const toggleSkill = useCallback((skillId) => {
|
|
412
|
+
setEnabledSkills(prev => {
|
|
413
|
+
const newSet = new Set(prev);
|
|
414
|
+
if (newSet.has(skillId)) {
|
|
415
|
+
newSet.delete(skillId);
|
|
416
|
+
}
|
|
417
|
+
else {
|
|
418
|
+
newSet.add(skillId);
|
|
419
|
+
}
|
|
420
|
+
return newSet;
|
|
421
|
+
});
|
|
422
|
+
}, []);
|
|
423
|
+
// Helper to toggle all skills
|
|
424
|
+
const toggleAllSkills = useCallback((allSkillIds, enable) => {
|
|
425
|
+
setEnabledSkills(enable ? new Set(allSkillIds) : new Set());
|
|
426
|
+
}, []);
|
|
321
427
|
// Get all enabled MCP tool names (for sending with requests)
|
|
322
428
|
const getEnabledMcpToolNames = useCallback(() => {
|
|
323
429
|
const toolNames = [];
|
|
@@ -326,6 +432,10 @@ brandIcon, avatarConfig, headerButtons, showPoweredBy = false, poweredByProps, e
|
|
|
326
432
|
});
|
|
327
433
|
return toolNames;
|
|
328
434
|
}, [enabledMcpTools]);
|
|
435
|
+
// Get all enabled skill IDs (for sending with requests)
|
|
436
|
+
const getEnabledSkillIds = useCallback(() => {
|
|
437
|
+
return Array.from(enabledSkills);
|
|
438
|
+
}, [enabledSkills]);
|
|
329
439
|
// Load messages from store on mount when useStoreMode is enabled
|
|
330
440
|
useEffect(() => {
|
|
331
441
|
if (useStoreMode) {
|
|
@@ -338,10 +448,16 @@ brandIcon, avatarConfig, headerButtons, showPoweredBy = false, poweredByProps, e
|
|
|
338
448
|
// Derived state
|
|
339
449
|
const messages = displayItems.filter((item) => !isToolCallMessage(item));
|
|
340
450
|
const ready = true;
|
|
341
|
-
//
|
|
451
|
+
// Track previous message count to avoid unnecessary callbacks
|
|
452
|
+
const prevMessageCountRef = useRef(0);
|
|
453
|
+
// Notify parent when messages change (only when count actually changes)
|
|
342
454
|
useEffect(() => {
|
|
343
|
-
|
|
344
|
-
|
|
455
|
+
const currentCount = messages.length;
|
|
456
|
+
if (currentCount !== prevMessageCountRef.current) {
|
|
457
|
+
prevMessageCountRef.current = currentCount;
|
|
458
|
+
onMessagesChange?.(messages);
|
|
459
|
+
}
|
|
460
|
+
}, [displayItems, onMessagesChange]); // Use displayItems instead of messages to avoid infinite loop
|
|
345
461
|
// Padding based on compact mode
|
|
346
462
|
const padding = compact ? 2 : 3;
|
|
347
463
|
// Default avatar config
|
|
@@ -548,16 +664,58 @@ brandIcon, avatarConfig, headerButtons, showPoweredBy = false, poweredByProps, e
|
|
|
548
664
|
const isHumanInTheLoop = existingToolCall.args &&
|
|
549
665
|
'steps' in existingToolCall.args &&
|
|
550
666
|
Array.isArray(existingToolCall.args.steps);
|
|
667
|
+
// Extract rich error information from result if available
|
|
668
|
+
const resultData = event.toolResult.result;
|
|
669
|
+
let executionError;
|
|
670
|
+
let codeError;
|
|
671
|
+
let exitCode;
|
|
672
|
+
let hasError = !!event.toolResult.error;
|
|
673
|
+
if (resultData && typeof resultData === 'object') {
|
|
674
|
+
// Check for execution_error (infrastructure/sandbox errors)
|
|
675
|
+
if (resultData.execution_error &&
|
|
676
|
+
typeof resultData.execution_error === 'string') {
|
|
677
|
+
executionError = resultData.execution_error;
|
|
678
|
+
hasError = true;
|
|
679
|
+
}
|
|
680
|
+
// Check for code_error (Python exceptions)
|
|
681
|
+
if (resultData.code_error &&
|
|
682
|
+
typeof resultData.code_error === 'object') {
|
|
683
|
+
const ce = resultData.code_error;
|
|
684
|
+
codeError = {
|
|
685
|
+
name: ce.name || 'Error',
|
|
686
|
+
value: ce.value || 'Unknown error',
|
|
687
|
+
traceback: ce.traceback,
|
|
688
|
+
};
|
|
689
|
+
hasError = true;
|
|
690
|
+
}
|
|
691
|
+
// Check for exit_code (non-zero exit from sys.exit())
|
|
692
|
+
if ('exit_code' in resultData) {
|
|
693
|
+
const ec = resultData.exit_code;
|
|
694
|
+
exitCode = typeof ec === 'number' ? ec : null;
|
|
695
|
+
// Non-zero exit code counts as an error condition
|
|
696
|
+
if (exitCode != null && exitCode !== 0) {
|
|
697
|
+
hasError = true;
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
// Check for execution_ok flag
|
|
701
|
+
if ('execution_ok' in resultData &&
|
|
702
|
+
resultData.execution_ok === false) {
|
|
703
|
+
hasError = true;
|
|
704
|
+
}
|
|
705
|
+
}
|
|
551
706
|
const updatedToolCall = {
|
|
552
707
|
...existingToolCall,
|
|
553
708
|
result: event.toolResult.result,
|
|
554
709
|
// Keep executing for HITL, otherwise mark complete/error
|
|
555
|
-
status:
|
|
710
|
+
status: hasError
|
|
556
711
|
? 'error'
|
|
557
712
|
: isHumanInTheLoop
|
|
558
713
|
? 'executing'
|
|
559
714
|
: 'complete',
|
|
560
715
|
error: event.toolResult.error,
|
|
716
|
+
executionError,
|
|
717
|
+
codeError,
|
|
718
|
+
exitCode,
|
|
561
719
|
};
|
|
562
720
|
toolCallsRef.current.set(toolCallId, updatedToolCall);
|
|
563
721
|
setDisplayItems(prev => prev.map(item => isToolCallMessage(item) && item.toolCallId === toolCallId
|
|
@@ -724,8 +882,9 @@ brandIcon, avatarConfig, headerButtons, showPoweredBy = false, poweredByProps, e
|
|
|
724
882
|
description: tool.description,
|
|
725
883
|
parameters: tool.parameters || { type: 'object', properties: {} },
|
|
726
884
|
}));
|
|
727
|
-
// Get enabled MCP tool names
|
|
885
|
+
// Get enabled MCP tool names and skill IDs
|
|
728
886
|
const enabledMcpToolNames = getEnabledMcpToolNames();
|
|
887
|
+
const enabledSkillIds = getEnabledSkillIds();
|
|
729
888
|
await adapterRef.current.sendMessage(userMessage, {
|
|
730
889
|
threadId: threadIdRef.current,
|
|
731
890
|
messages: allMessages,
|
|
@@ -733,6 +892,10 @@ brandIcon, avatarConfig, headerButtons, showPoweredBy = false, poweredByProps, e
|
|
|
733
892
|
tools: toolsForRequest,
|
|
734
893
|
// Include enabled MCP tools as builtin_tools for backend
|
|
735
894
|
builtinTools: enabledMcpToolNames,
|
|
895
|
+
// Include enabled skills for backend
|
|
896
|
+
skills: enabledSkillIds,
|
|
897
|
+
// Include connected identities with access tokens (use ref to avoid infinite loops)
|
|
898
|
+
identities: connectedIdentitiesRef.current,
|
|
736
899
|
});
|
|
737
900
|
}
|
|
738
901
|
}
|
|
@@ -760,6 +923,7 @@ brandIcon, avatarConfig, headerButtons, showPoweredBy = false, poweredByProps, e
|
|
|
760
923
|
onSendMessage,
|
|
761
924
|
enableStreaming,
|
|
762
925
|
getEnabledMcpToolNames,
|
|
926
|
+
getEnabledSkillIds,
|
|
763
927
|
]);
|
|
764
928
|
// Handle stop
|
|
765
929
|
const handleStop = useCallback(() => {
|
|
@@ -1018,7 +1182,7 @@ brandIcon, avatarConfig, headerButtons, showPoweredBy = false, poweredByProps, e
|
|
|
1018
1182
|
status: item.status,
|
|
1019
1183
|
error: item.error,
|
|
1020
1184
|
respond,
|
|
1021
|
-
})) : (_jsx(ToolCallDisplay, { toolCallId: item.toolCallId, toolName: item.toolName, args: item.args, result: item.result, status: item.status, error: item.error }));
|
|
1185
|
+
})) : (_jsx(ToolCallDisplay, { toolCallId: item.toolCallId, toolName: item.toolName, args: item.args, result: item.result, status: item.status, error: item.error, executionError: item.executionError, codeError: item.codeError, exitCode: item.exitCode }));
|
|
1022
1186
|
// Skip if custom render returns null/undefined
|
|
1023
1187
|
if (toolUI === null || toolUI === undefined)
|
|
1024
1188
|
return null;
|
|
@@ -1281,7 +1445,8 @@ brandIcon, avatarConfig, headerButtons, showPoweredBy = false, poweredByProps, e
|
|
|
1281
1445
|
maxHeight: '120px',
|
|
1282
1446
|
overflow: 'hidden',
|
|
1283
1447
|
transition: 'height 0.1s ease-out',
|
|
1284
|
-
}, rows: 1 }), isLoading ? (_jsx(IconButton, { icon: SquareCircleIcon, "aria-label": "Stop", onClick: handleStop, sx: { alignSelf: 'flex-end' } })) : (_jsx(IconButton, { icon: PaperAirplaneIcon, "aria-label": "Send", onClick: handleSend, disabled: !input.trim(), sx: { alignSelf: 'flex-end' } }))] }) }), (showModelSelector || showToolsMenu
|
|
1448
|
+
}, rows: 1 }), isLoading ? (_jsx(IconButton, { icon: SquareCircleIcon, "aria-label": "Stop", onClick: handleStop, sx: { alignSelf: 'flex-end' } })) : (_jsx(IconButton, { icon: PaperAirplaneIcon, "aria-label": "Send", onClick: handleSend, disabled: !input.trim(), sx: { alignSelf: 'flex-end' } }))] }) }), (showModelSelector || showToolsMenu || showSkillsMenu) &&
|
|
1449
|
+
(configQuery.data || skillsQuery.data) && (_jsxs(Box, { sx: {
|
|
1285
1450
|
display: 'flex',
|
|
1286
1451
|
gap: 2,
|
|
1287
1452
|
px: padding,
|
|
@@ -1290,61 +1455,100 @@ brandIcon, avatarConfig, headerButtons, showPoweredBy = false, poweredByProps, e
|
|
|
1290
1455
|
borderColor: 'border.default',
|
|
1291
1456
|
alignItems: 'center',
|
|
1292
1457
|
bg: 'canvas.subtle',
|
|
1293
|
-
}, children: [showToolsMenu && (_jsxs(ActionMenu, { children: [_jsx(ActionMenu.Anchor, { children: _jsx(
|
|
1458
|
+
}, children: [showToolsMenu && (_jsxs(ActionMenu, { children: [_jsx(ActionMenu.Anchor, { children: _jsx(Button, { type: "button", variant: "invisible", size: "small", leadingVisual: ToolsIcon, children: _jsxs(Text, { sx: { fontSize: 0 }, children: ["Tools", getEnabledMcpToolNames().length > 0 &&
|
|
1459
|
+
` (${getEnabledMcpToolNames().length})`] }) }) }), _jsx(ActionMenu.Overlay, { side: "outside-top", align: "start", width: "large", children: _jsx(Box, { sx: {
|
|
1294
1460
|
maxHeight: '60vh',
|
|
1295
1461
|
overflowY: 'auto',
|
|
1296
|
-
}, children: _jsx(ActionList, { children: configQuery.data?.mcpServers &&
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
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: {
|
|
1462
|
+
}, children: _jsxs(ActionList, { children: [codemodeEnabled && (_jsx(ActionList.Group, { title: "Codemode", children: _jsx(ActionList.Item, { disabled: true, children: _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "MCP tools are accessible via Codemode meta-tools (search_tools, list_tool_names, execute_code)." }) }) })), configQuery.data?.mcpServers &&
|
|
1463
|
+
configQuery.data.mcpServers.length > 0 ? (configQuery.data.mcpServers.map(server => {
|
|
1464
|
+
const serverTools = enabledMcpTools.get(server.id);
|
|
1465
|
+
const allToolNames = server.tools.map(t => t.name);
|
|
1466
|
+
const enabledCount = serverTools?.size ?? 0;
|
|
1467
|
+
const allEnabled = enabledCount === allToolNames.length &&
|
|
1468
|
+
allToolNames.length > 0;
|
|
1469
|
+
return (_jsxs(ActionList.Group, { title: `${server.name}${server.isAvailable ? '' : ' (unavailable)'}`, children: [server.isAvailable &&
|
|
1470
|
+
server.tools.length > 0 && (_jsxs(Box, { sx: {
|
|
1319
1471
|
display: 'flex',
|
|
1320
1472
|
alignItems: 'center',
|
|
1321
1473
|
justifyContent: 'space-between',
|
|
1322
1474
|
px: 3,
|
|
1323
1475
|
py: 2,
|
|
1324
|
-
'
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1476
|
+
borderBottom: '1px solid',
|
|
1477
|
+
borderColor: 'border.muted',
|
|
1478
|
+
}, children: [_jsxs(Text, { id: `toggle-all-${server.id}`, sx: {
|
|
1479
|
+
fontSize: 0,
|
|
1480
|
+
fontWeight: 'semibold',
|
|
1481
|
+
color: 'fg.muted',
|
|
1482
|
+
}, 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 &&
|
|
1483
|
+
server.tools.length > 0 ? (server.tools.map(tool => {
|
|
1484
|
+
const isEnabled = serverTools?.has(tool.name) ?? false;
|
|
1485
|
+
return (_jsxs(Box, { sx: {
|
|
1486
|
+
display: 'flex',
|
|
1487
|
+
alignItems: 'center',
|
|
1488
|
+
justifyContent: 'space-between',
|
|
1489
|
+
px: 3,
|
|
1490
|
+
py: 2,
|
|
1491
|
+
'&:hover': {
|
|
1492
|
+
backgroundColor: 'canvas.subtle',
|
|
1493
|
+
},
|
|
1494
|
+
}, 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: {
|
|
1495
|
+
display: 'block',
|
|
1496
|
+
fontSize: 0,
|
|
1497
|
+
color: 'fg.muted',
|
|
1498
|
+
overflow: 'hidden',
|
|
1499
|
+
textOverflow: 'ellipsis',
|
|
1500
|
+
whiteSpace: 'nowrap',
|
|
1501
|
+
}, 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}`));
|
|
1502
|
+
})) : server.isAvailable ? (_jsx(ActionList.Item, { disabled: true, children: _jsx(Text, { sx: {
|
|
1503
|
+
color: 'fg.muted',
|
|
1504
|
+
fontStyle: 'italic',
|
|
1505
|
+
}, children: "No tools discovered" }) })) : (_jsx(ActionList.Item, { disabled: true, children: _jsx(Text, { sx: {
|
|
1506
|
+
color: 'fg.muted',
|
|
1507
|
+
fontStyle: 'italic',
|
|
1508
|
+
}, children: "Server unavailable" }) }))] }, server.id));
|
|
1509
|
+
})) : (_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: {
|
|
1510
|
+
width: 8,
|
|
1511
|
+
height: 8,
|
|
1512
|
+
borderRadius: '50%',
|
|
1513
|
+
backgroundColor: 'success.emphasis',
|
|
1514
|
+
} }) }), tool.name] }, tool.id)))) : (_jsx(ActionList.Item, { disabled: true, children: _jsx(Text, { sx: {
|
|
1515
|
+
color: 'fg.muted',
|
|
1516
|
+
fontStyle: 'italic',
|
|
1517
|
+
}, children: "No tools available" }) })) }))] }) }) })] })), showSkillsMenu && (_jsxs(ActionMenu, { children: [_jsx(ActionMenu.Anchor, { children: _jsx(Button, { type: "button", variant: "invisible", size: "small", leadingVisual: BriefcaseIcon, children: _jsxs(Text, { sx: { fontSize: 0 }, children: ["Skills", enabledSkills.size > 0 && ` (${enabledSkills.size})`] }) }) }), _jsx(ActionMenu.Overlay, { side: "outside-top", align: "start", width: "large", children: _jsx(Box, { sx: {
|
|
1518
|
+
maxHeight: '60vh',
|
|
1519
|
+
overflowY: 'auto',
|
|
1520
|
+
}, children: _jsx(ActionList, { children: skillsQuery.isLoading ? (_jsx(ActionList.Item, { disabled: true, children: _jsx(Text, { sx: { color: 'fg.muted' }, children: "Loading skills..." }) })) : skillsQuery.data?.skills &&
|
|
1521
|
+
skillsQuery.data.skills.length > 0 ? (_jsxs(_Fragment, { children: [_jsxs(Box, { sx: {
|
|
1522
|
+
display: 'flex',
|
|
1523
|
+
alignItems: 'center',
|
|
1524
|
+
justifyContent: 'space-between',
|
|
1525
|
+
px: 3,
|
|
1526
|
+
py: 2,
|
|
1527
|
+
borderBottom: '1px solid',
|
|
1528
|
+
borderColor: 'border.muted',
|
|
1529
|
+
}, children: [_jsxs(Text, { id: "toggle-all-skills", sx: {
|
|
1530
|
+
fontSize: 0,
|
|
1531
|
+
fontWeight: 'semibold',
|
|
1339
1532
|
color: 'fg.muted',
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1533
|
+
}, children: ["Enable all (", enabledSkills.size, "/", skillsQuery.data.skills.length, ")"] }), _jsx(ToggleSwitch, { size: "small", checked: enabledSkills.size ===
|
|
1534
|
+
skillsQuery.data.skills.length, onClick: () => toggleAllSkills(skillsQuery.data.skills.map(s => s.id), enabledSkills.size !==
|
|
1535
|
+
skillsQuery.data.skills.length), "aria-labelledby": "toggle-all-skills" })] }), skillsQuery.data.skills.map(skill => (_jsxs(Box, { sx: {
|
|
1536
|
+
display: 'flex',
|
|
1537
|
+
alignItems: 'center',
|
|
1538
|
+
justifyContent: 'space-between',
|
|
1539
|
+
px: 3,
|
|
1540
|
+
py: 2,
|
|
1541
|
+
'&:hover': {
|
|
1542
|
+
backgroundColor: 'canvas.subtle',
|
|
1543
|
+
},
|
|
1544
|
+
}, children: [_jsxs(Box, { sx: { flex: 1, minWidth: 0 }, children: [_jsx(Text, { id: `toggle-skill-${skill.id}`, sx: { fontWeight: 'semibold' }, children: skill.name }), skill.description && (_jsx(Text, { sx: {
|
|
1545
|
+
display: 'block',
|
|
1546
|
+
fontSize: 0,
|
|
1547
|
+
color: 'fg.muted',
|
|
1548
|
+
overflow: 'hidden',
|
|
1549
|
+
textOverflow: 'ellipsis',
|
|
1550
|
+
whiteSpace: 'nowrap',
|
|
1551
|
+
}, children: skill.description }))] }), _jsx(ToggleSwitch, { size: "small", checked: enabledSkills.has(skill.id), onClick: () => toggleSkill(skill.id), "aria-labelledby": `toggle-skill-${skill.id}` })] }, skill.id)))] })) : (_jsx(ActionList.Item, { disabled: true, children: _jsx(Text, { sx: { color: 'fg.muted', fontStyle: 'italic' }, children: "No skills available" }) })) }) }) })] })), showModelSelector && models.length > 0 && selectedModel && (_jsxs(Box, { sx: {
|
|
1348
1552
|
display: 'flex',
|
|
1349
1553
|
flexDirection: 'column',
|
|
1350
1554
|
alignItems: 'flex-end',
|
|
@@ -1372,7 +1576,7 @@ brandIcon, avatarConfig, headerButtons, showPoweredBy = false, poweredByProps, e
|
|
|
1372
1576
|
bg: 'danger.subtle',
|
|
1373
1577
|
borderBottom: '1px solid',
|
|
1374
1578
|
borderColor: 'danger.muted',
|
|
1375
|
-
}, children: [_jsx(AlertIcon, { size: 16 }), _jsx(Text, { sx: { color: 'danger.fg', fontSize: 1 }, children: error.message })] })), _jsx(Box, { sx: { flex: 1, overflow: 'auto', bg: 'canvas.default' }, children: children ? (children) : (_jsx(Box, { sx: {
|
|
1579
|
+
}, children: [_jsx(AlertIcon, { size: 16 }), _jsx(Text, { sx: { color: 'danger.fg', fontSize: 1 }, children: error.message })] })), _jsx(Box, { sx: { flex: 1, flexGrow: 1, overflow: 'auto', bg: 'canvas.default' }, children: children ? (children) : (_jsx(Box, { sx: {
|
|
1376
1580
|
display: 'flex',
|
|
1377
1581
|
flexDirection: 'column',
|
|
1378
1582
|
minHeight: '100%',
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import type { ToolCallStatus } from '../base/ChatBase';
|
|
2
|
+
import type { CodeError, ExecutionResult } from '../../types/execution';
|
|
3
|
+
/**
|
|
4
|
+
* Error type classification for display purposes
|
|
5
|
+
*/
|
|
6
|
+
export type ErrorType = 'execution' | 'code' | 'exit' | 'unknown';
|
|
2
7
|
export interface ToolCallDisplayProps {
|
|
3
8
|
/** Tool call ID */
|
|
4
9
|
toolCallId: string;
|
|
@@ -10,8 +15,16 @@ export interface ToolCallDisplayProps {
|
|
|
10
15
|
result?: unknown;
|
|
11
16
|
/** Current status */
|
|
12
17
|
status: ToolCallStatus;
|
|
13
|
-
/** Error message if failed */
|
|
18
|
+
/** Error message if failed (backwards compatible) */
|
|
14
19
|
error?: string;
|
|
20
|
+
/** Rich execution result with detailed error information */
|
|
21
|
+
executionResult?: ExecutionResult;
|
|
22
|
+
/** Code error details (Python exception) */
|
|
23
|
+
codeError?: CodeError;
|
|
24
|
+
/** Exit code when code called sys.exit() */
|
|
25
|
+
exitCode?: number | null;
|
|
26
|
+
/** Execution/infrastructure error message */
|
|
27
|
+
executionError?: string;
|
|
15
28
|
}
|
|
16
29
|
/**
|
|
17
30
|
* ToolCallDisplay component - Default display for tool calls in chat
|
|
@@ -21,6 +34,7 @@ export interface ToolCallDisplayProps {
|
|
|
21
34
|
* - Shows tool name, status icon, and brief summary when collapsed
|
|
22
35
|
* - Expands to show full parameters and results
|
|
23
36
|
* - Color-coded status indicators
|
|
37
|
+
* - Rich error display distinguishing execution errors from code errors
|
|
24
38
|
*/
|
|
25
|
-
export declare function ToolCallDisplay({ toolCallId, toolName, args, result, status, error, }: ToolCallDisplayProps): import("react/jsx-runtime").JSX.Element;
|
|
39
|
+
export declare function ToolCallDisplay({ toolCallId, toolName, args, result, status, error, executionResult, codeError, exitCode, executionError, }: ToolCallDisplayProps): import("react/jsx-runtime").JSX.Element;
|
|
26
40
|
export default ToolCallDisplay;
|