@datalayer/agent-runtimes 1.0.4 → 1.0.6
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 +182 -1
- package/lib/AgentNode.d.ts +3 -0
- package/lib/AgentNode.js +676 -0
- package/lib/App.js +1 -1
- package/lib/agent-node/themeStore.d.ts +3 -0
- package/lib/agent-node/themeStore.js +156 -0
- package/lib/agent-node-main.d.ts +1 -0
- package/lib/agent-node-main.js +14 -0
- package/lib/agents/AgentDetails.d.ts +22 -1
- package/lib/agents/AgentDetails.js +34 -47
- package/lib/api/index.d.ts +0 -1
- package/lib/api/index.js +4 -2
- package/lib/chat/Chat.d.ts +5 -106
- package/lib/chat/Chat.js +20 -14
- package/lib/chat/ChatFloating.d.ts +7 -140
- package/lib/chat/ChatFloating.js +3 -3
- package/lib/chat/ChatPopupStandalone.d.ts +8 -47
- package/lib/chat/ChatPopupStandalone.js +3 -3
- package/lib/chat/ChatSidebar.d.ts +4 -69
- package/lib/chat/ChatSidebar.js +83 -51
- package/lib/chat/ChatStandalone.d.ts +4 -54
- package/lib/chat/ChatStandalone.js +3 -3
- package/lib/chat/base/ChatBase.js +1414 -174
- package/lib/chat/display/FloatingBrandButton.js +8 -1
- package/lib/chat/header/ChatHeader.d.ts +3 -1
- package/lib/chat/header/ChatHeader.js +15 -12
- package/lib/chat/header/ChatHeaderBase.d.ts +30 -5
- package/lib/chat/header/ChatHeaderBase.js +41 -16
- package/lib/chat/indicators/McpStatusIndicator.d.ts +7 -4
- package/lib/chat/indicators/McpStatusIndicator.js +7 -32
- package/lib/chat/indicators/SandboxStatusIndicator.d.ts +4 -1
- package/lib/chat/indicators/SandboxStatusIndicator.js +91 -56
- package/lib/chat/indicators/SkillsStatusIndicator.d.ts +7 -0
- package/lib/chat/indicators/SkillsStatusIndicator.js +88 -0
- package/lib/chat/indicators/index.d.ts +1 -0
- package/lib/chat/indicators/index.js +1 -0
- package/lib/chat/messages/ChatMessageList.d.ts +1 -1
- package/lib/chat/messages/ChatMessageList.js +154 -114
- package/lib/chat/messages/ChatMessages.js +6 -2
- package/lib/chat/prompt/InputFooter.d.ts +21 -6
- package/lib/chat/prompt/InputFooter.js +76 -20
- package/lib/chat/prompt/InputPrompt.d.ts +5 -1
- package/lib/chat/prompt/InputPrompt.js +4 -4
- package/lib/chat/prompt/InputPromptFooter.d.ts +3 -1
- package/lib/chat/prompt/InputPromptFooter.js +3 -3
- package/lib/chat/prompt/InputPromptLexical.d.ts +3 -1
- package/lib/chat/prompt/InputPromptLexical.js +12 -5
- package/lib/chat/prompt/InputPromptText.d.ts +3 -1
- package/lib/chat/prompt/InputPromptText.js +2 -2
- package/lib/chat/tools/ToolApprovalBanner.js +1 -1
- package/lib/chat/tools/ToolCallDisplay.d.ts +3 -1
- package/lib/chat/tools/ToolCallDisplay.js +2 -2
- package/lib/chat/usage/TokenUsageBar.js +20 -2
- package/lib/client/AgentRuntimesClientContext.d.ts +53 -0
- package/lib/client/AgentRuntimesClientContext.js +55 -0
- package/lib/client/AgentsMixin.d.ts +0 -18
- package/lib/client/AgentsMixin.js +20 -30
- package/lib/client/IAgentRuntimesClient.d.ts +215 -0
- package/lib/client/IAgentRuntimesClient.js +5 -0
- package/lib/client/SdkAgentRuntimesClient.d.ts +151 -0
- package/lib/client/SdkAgentRuntimesClient.js +134 -0
- package/lib/client/index.d.ts +4 -1
- package/lib/client/index.js +3 -1
- package/lib/components/NotificationEventCard.js +5 -1
- package/lib/config/AgentConfiguration.d.ts +22 -0
- package/lib/config/AgentConfiguration.js +319 -64
- package/lib/context/ContextDistribution.d.ts +3 -1
- package/lib/context/ContextDistribution.js +8 -27
- package/lib/context/ContextInspector.d.ts +3 -1
- package/lib/context/ContextInspector.js +19 -67
- package/lib/context/ContextPanel.d.ts +3 -1
- package/lib/context/ContextPanel.js +104 -64
- package/lib/context/ContextUsage.d.ts +3 -1
- package/lib/context/ContextUsage.js +3 -3
- package/lib/context/CostTracker.d.ts +9 -3
- package/lib/context/CostTracker.js +26 -47
- package/lib/context/CostUsageChart.d.ts +12 -0
- package/lib/context/CostUsageChart.js +378 -0
- package/lib/context/GraphFlowChart.d.ts +16 -0
- package/lib/context/GraphFlowChart.js +182 -0
- package/lib/context/TokenUsageChart.d.ts +8 -1
- package/lib/context/TokenUsageChart.js +349 -211
- package/lib/context/TurnGraphChart.d.ts +39 -0
- package/lib/context/TurnGraphChart.js +538 -0
- package/lib/context/otelWsPool.d.ts +20 -0
- package/lib/context/otelWsPool.js +69 -0
- package/lib/examples/A2UiComponentGalleryExample.d.ts +0 -17
- package/lib/examples/A2UiComponentGalleryExample.js +315 -522
- package/lib/examples/A2UiContactCardExample.d.ts +0 -18
- package/lib/examples/A2UiContactCardExample.js +154 -411
- package/lib/examples/A2UiRestaurantExample.d.ts +0 -30
- package/lib/examples/A2UiRestaurantExample.js +114 -212
- package/lib/examples/A2UiViewerExample.d.ts +0 -18
- package/lib/examples/A2UiViewerExample.js +283 -532
- package/lib/examples/AgUiBackendToolRenderingExample.js +1 -1
- package/lib/examples/AgUiHaikuGenUiExample.d.ts +1 -1
- package/lib/examples/AgUiHaikuGenUiExample.js +1 -1
- package/lib/examples/AgUiSharedStateExample.js +2 -1
- package/lib/examples/AgentCheckpointsExample.js +14 -28
- package/lib/examples/AgentCodemodeExample.d.ts +4 -6
- package/lib/examples/AgentCodemodeExample.js +603 -169
- package/lib/examples/AgentEvalsExample.js +339 -53
- package/lib/examples/AgentGuardrailsExample.js +383 -66
- package/lib/examples/AgentHooksExample.d.ts +3 -0
- package/lib/examples/AgentHooksExample.js +122 -0
- package/lib/examples/AgentInferenceProviderExample.d.ts +3 -0
- package/lib/examples/AgentInferenceProviderExample.js +329 -0
- package/lib/examples/AgentMCPExample.d.ts +3 -0
- package/lib/examples/AgentMCPExample.js +481 -0
- package/lib/examples/AgentMemoryExample.d.ts +1 -2
- package/lib/examples/AgentMemoryExample.js +78 -33
- package/lib/examples/AgentMonitoringExample.js +261 -200
- package/lib/examples/AgentNotificationsExample.d.ts +1 -2
- package/lib/examples/AgentNotificationsExample.js +114 -33
- package/lib/examples/AgentOtelExample.js +32 -42
- package/lib/examples/AgentOutputsExample.d.ts +11 -6
- package/lib/examples/AgentOutputsExample.js +433 -81
- package/lib/examples/AgentParametersExample.d.ts +3 -0
- package/lib/examples/AgentParametersExample.js +248 -0
- package/lib/examples/AgentSandboxExample.d.ts +3 -3
- package/lib/examples/AgentSandboxExample.js +74 -45
- package/lib/examples/AgentSkillsExample.js +95 -103
- package/lib/examples/AgentSubagentsExample.d.ts +14 -0
- package/lib/examples/AgentSubagentsExample.js +228 -0
- package/lib/examples/AgentToolApprovalsExample.js +49 -561
- package/lib/examples/AgentTriggersExample.js +823 -569
- package/lib/examples/{AgentspecExample.d.ts → AgentspecsExample.d.ts} +2 -2
- package/lib/examples/AgentspecsExample.js +1096 -0
- package/lib/examples/ChatCustomExample.js +16 -28
- package/lib/examples/ChatExample.js +13 -29
- package/lib/examples/CopilotKitLexicalExample.js +2 -1
- package/lib/examples/CopilotKitNotebookExample.js +2 -1
- package/lib/examples/HomeExample.d.ts +15 -0
- package/lib/examples/HomeExample.js +77 -0
- package/lib/examples/Lexical2Example.js +4 -2
- package/lib/examples/{LexicalExample.d.ts → LexicalAgentExample.d.ts} +4 -4
- package/lib/examples/{LexicalExample.js → LexicalAgentExample.js} +66 -17
- package/lib/examples/{LexicalSidebarExample.d.ts → LexicalAgentSidebarExample.d.ts} +5 -5
- package/lib/examples/LexicalAgentSidebarExample.js +261 -0
- package/lib/examples/NotebookAgentExample.d.ts +9 -0
- package/lib/examples/NotebookAgentExample.js +192 -0
- package/lib/examples/{NotebookSidebarExample.d.ts → NotebookAgentSidebarExample.d.ts} +2 -2
- package/lib/examples/NotebookAgentSidebarExample.js +221 -0
- package/lib/examples/{DatalayerNotebookExample.d.ts → NotebookCollaborationExample.d.ts} +4 -4
- package/lib/examples/{DatalayerNotebookExample.js → NotebookCollaborationExample.js} +3 -3
- package/lib/examples/NotebookExample.d.ts +4 -7
- package/lib/examples/NotebookExample.js +14 -146
- package/lib/examples/components/AuthRequiredView.d.ts +6 -0
- package/lib/examples/components/AuthRequiredView.js +33 -0
- package/lib/examples/components/ExampleWrapper.d.ts +9 -3
- package/lib/examples/components/ExampleWrapper.js +45 -9
- package/lib/examples/{ag-ui → components}/haiku/HaikuDisplay.js +1 -1
- package/lib/examples/{ag-ui → components}/haiku/InlineHaikuCard.js +1 -1
- package/lib/examples/{ag-ui → components}/haiku/index.d.ts +1 -1
- package/lib/examples/{ag-ui → components}/haiku/index.js +1 -1
- package/lib/examples/components/index.d.ts +3 -0
- package/lib/examples/components/index.js +4 -0
- package/lib/examples/{ag-ui → components}/weather/index.d.ts +1 -1
- package/lib/examples/{ag-ui → components}/weather/index.js +1 -1
- package/lib/examples/example-selector.d.ts +17 -4
- package/lib/examples/example-selector.js +108 -41
- package/lib/examples/index.d.ts +10 -6
- package/lib/examples/index.js +10 -6
- package/lib/examples/lexical/initial-content.json +6 -6
- package/lib/examples/main.js +257 -27
- package/lib/examples/utils/a2ui.d.ts +18 -0
- package/lib/examples/utils/a2ui.js +69 -0
- package/lib/examples/utils/a2uiMarkdownProvider.d.ts +7 -0
- package/lib/examples/utils/a2uiMarkdownProvider.js +9 -0
- package/lib/examples/utils/agentId.d.ts +18 -0
- package/lib/examples/utils/agentId.js +54 -0
- package/lib/examples/utils/agents/earthquake-detector.json +11 -11
- package/lib/examples/utils/agents/sales-forecaster.json +11 -11
- package/lib/examples/utils/agents/social-post-generator.json +11 -11
- package/lib/examples/utils/agents/stock-market.json +11 -11
- package/lib/examples/utils/examplesStore.js +82 -27
- package/lib/examples/utils/useExampleAgentRuntimesUrl.d.ts +5 -0
- package/lib/examples/utils/useExampleAgentRuntimesUrl.js +19 -0
- package/lib/hooks/index.d.ts +8 -8
- package/lib/hooks/index.js +7 -7
- package/lib/hooks/useA2A.d.ts +2 -3
- package/lib/hooks/useAIAgentsWebSocket.d.ts +43 -4
- package/lib/hooks/useAIAgentsWebSocket.js +153 -12
- package/lib/hooks/useAcp.d.ts +1 -2
- package/lib/hooks/useAgUi.d.ts +1 -1
- package/lib/hooks/{useAgents.d.ts → useAgentRuntimes.d.ts} +70 -4
- package/lib/hooks/{useAgents.js → useAgentRuntimes.js} +237 -32
- package/lib/hooks/useAgentsCatalog.js +1 -1
- package/lib/hooks/useAgentsService.d.ts +2 -2
- package/lib/hooks/useAgentsService.js +7 -7
- package/lib/hooks/useCheckpoints.js +1 -1
- package/lib/hooks/useConfig.d.ts +4 -1
- package/lib/hooks/useConfig.js +10 -3
- package/lib/hooks/useContextSnapshot.d.ts +9 -4
- package/lib/hooks/useContextSnapshot.js +9 -37
- package/lib/hooks/useMonitoring.js +3 -0
- package/lib/hooks/useSandbox.d.ts +20 -8
- package/lib/hooks/useSandbox.js +105 -40
- package/lib/hooks/useSkills.d.ts +23 -5
- package/lib/hooks/useSkills.js +94 -39
- package/lib/hooks/useToolApprovals.d.ts +60 -36
- package/lib/hooks/useToolApprovals.js +318 -69
- package/lib/hooks/useVercelAI.d.ts +1 -1
- package/lib/index.d.ts +2 -1
- package/lib/index.js +1 -0
- package/lib/inference/index.d.ts +0 -1
- package/lib/middleware/index.d.ts +0 -1
- package/lib/protocols/AGUIAdapter.js +6 -0
- package/lib/protocols/VercelAIAdapter.d.ts +7 -0
- package/lib/protocols/VercelAIAdapter.js +59 -7
- package/lib/specs/agents/agents.d.ts +21 -4
- package/lib/specs/agents/agents.js +2879 -316
- package/lib/specs/agents/index.js +3 -1
- package/lib/specs/benchmarks.d.ts +20 -0
- package/lib/specs/benchmarks.js +205 -0
- package/lib/specs/envvars.js +27 -20
- package/lib/specs/evals.d.ts +10 -9
- package/lib/specs/evals.js +128 -88
- package/lib/specs/events.d.ts +3 -10
- package/lib/specs/events.js +127 -84
- package/lib/specs/frontendTools.js +2 -2
- package/lib/specs/guardrails.d.ts +0 -7
- package/lib/specs/guardrails.js +240 -159
- package/lib/specs/mcpServers.js +35 -6
- package/lib/specs/memory.d.ts +0 -2
- package/lib/specs/memory.js +4 -17
- package/lib/specs/models.d.ts +0 -2
- package/lib/specs/models.js +20 -15
- package/lib/specs/notifications.js +102 -18
- package/lib/specs/outputs.js +15 -9
- package/lib/specs/personas.d.ts +41 -0
- package/lib/specs/personas.js +168 -0
- package/lib/specs/skills.d.ts +1 -1
- package/lib/specs/skills.js +23 -23
- package/lib/specs/teams/index.js +3 -1
- package/lib/specs/teams/teams.js +468 -348
- package/lib/specs/tools.js +4 -4
- package/lib/specs/triggers.js +61 -11
- package/lib/stores/agentRuntimeStore.d.ts +208 -0
- package/lib/stores/agentRuntimeStore.js +650 -0
- package/lib/stores/conversationStore.js +2 -2
- package/lib/stores/index.d.ts +1 -1
- package/lib/stores/index.js +1 -1
- package/lib/tools/adapters/copilotkit/lexicalHooks.d.ts +1 -2
- package/lib/tools/adapters/copilotkit/lexicalHooks.js +1 -3
- package/lib/tools/adapters/copilotkit/notebookHooks.d.ts +1 -2
- package/lib/tools/adapters/copilotkit/notebookHooks.js +1 -3
- package/lib/tools/index.d.ts +0 -2
- package/lib/tools/index.js +0 -1
- package/lib/types/agents-lifecycle.d.ts +18 -0
- package/lib/types/agents.d.ts +6 -0
- package/lib/types/agentspecs.d.ts +54 -1
- package/lib/types/benchmarks.d.ts +43 -0
- package/lib/types/benchmarks.js +5 -0
- package/lib/types/chat.d.ts +325 -8
- package/lib/types/context.d.ts +27 -0
- package/lib/types/cost.d.ts +2 -2
- package/lib/types/evals.d.ts +26 -17
- package/lib/types/index.d.ts +3 -0
- package/lib/types/index.js +3 -0
- package/lib/types/mcp.d.ts +8 -0
- package/lib/types/models.d.ts +2 -2
- package/lib/types/personas.d.ts +25 -0
- package/lib/types/personas.js +5 -0
- package/lib/types/skills.d.ts +43 -1
- package/lib/types/stream.d.ts +110 -0
- package/lib/types/stream.js +36 -0
- package/lib/utils/utils.d.ts +9 -5
- package/lib/utils/utils.js +9 -5
- package/package.json +19 -11
- package/scripts/codegen/__pycache__/generate_agents.cpython-313.pyc +0 -0
- package/scripts/codegen/__pycache__/generate_benchmarks.cpython-313.pyc +0 -0
- package/scripts/codegen/__pycache__/generate_evals.cpython-313.pyc +0 -0
- package/scripts/codegen/__pycache__/generate_events.cpython-313.pyc +0 -0
- package/scripts/codegen/__pycache__/versioning.cpython-313.pyc +0 -0
- package/scripts/codegen/generate_agents.py +187 -45
- package/scripts/codegen/generate_benchmarks.py +441 -0
- package/scripts/codegen/generate_evals.py +94 -16
- package/scripts/codegen/generate_events.py +35 -14
- package/scripts/codegen/generate_personas.py +319 -0
- package/scripts/codegen/generate_skills.py +9 -9
- package/scripts/sync-jupyter.sh +26 -7
- package/lib/api/tool-approvals.d.ts +0 -62
- package/lib/api/tool-approvals.js +0 -145
- package/lib/examples/AgentspecExample.js +0 -705
- package/lib/examples/LexicalSidebarExample.js +0 -163
- package/lib/examples/NotebookSidebarExample.js +0 -119
- package/lib/examples/NotebookSimpleExample.d.ts +0 -6
- package/lib/examples/NotebookSimpleExample.js +0 -22
- package/lib/examples/ag-ui/index.d.ts +0 -10
- package/lib/examples/ag-ui/index.js +0 -16
- package/lib/hooks/useAgentsRegistry.d.ts +0 -10
- package/lib/hooks/useAgentsRegistry.js +0 -20
- package/lib/stores/agentsStore.d.ts +0 -123
- package/lib/stores/agentsStore.js +0 -270
- /package/lib/examples/{ag-ui → components}/haiku/HaikuDisplay.d.ts +0 -0
- /package/lib/examples/{ag-ui → components}/haiku/InlineHaikuCard.d.ts +0 -0
- /package/lib/examples/{ag-ui → components}/weather/InlineWeatherCard.d.ts +0 -0
- /package/lib/examples/{ag-ui → components}/weather/InlineWeatherCard.js +0 -0
|
@@ -0,0 +1,1096 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
4
|
+
* Distributed under the terms of the Modified BSD License.
|
|
5
|
+
*/
|
|
6
|
+
/// <reference types="vite/client" />
|
|
7
|
+
import React, { useState, useEffect, useCallback, useMemo, useRef, } from 'react';
|
|
8
|
+
import { PageLayout, IconButton, Button, Text } from '@primer/react';
|
|
9
|
+
import { SidebarCollapseIcon, SidebarExpandIcon, XIcon, AgentIcon, } from '@primer/octicons-react';
|
|
10
|
+
import { AiAgentIcon } from '@datalayer/icons-react';
|
|
11
|
+
import { Blankslate } from '@primer/react/experimental';
|
|
12
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
13
|
+
import { Box } from '@datalayer/primer-addons';
|
|
14
|
+
import { useCoreStore } from '@datalayer/core';
|
|
15
|
+
import { useSimpleAuthStore } from '@datalayer/core/lib/views/otel';
|
|
16
|
+
import { AgentConfiguration } from '../config';
|
|
17
|
+
import { Chat } from '../chat';
|
|
18
|
+
import { DEFAULT_MODEL } from '../specs';
|
|
19
|
+
import { useIdentity } from '../identity';
|
|
20
|
+
import { useAgentsStore } from './utils/examplesStore';
|
|
21
|
+
import { ThemedProvider } from './utils/themedProvider';
|
|
22
|
+
import { isSpecSelection, getSpecId, isCloudSpecSelection, getCloudSpecId, } from '../config/AgentConfiguration';
|
|
23
|
+
import { MockFileBrowser, MainContent, Header } from './components';
|
|
24
|
+
import { useChatStore } from '../stores';
|
|
25
|
+
import { useAgentRuntimes } from '../hooks/useAgentRuntimes';
|
|
26
|
+
// Create a query client for React Query
|
|
27
|
+
const queryClient = new QueryClient({
|
|
28
|
+
defaultOptions: {
|
|
29
|
+
queries: {
|
|
30
|
+
staleTime: 1000 * 60 * 5, // 5 minutes
|
|
31
|
+
gcTime: 1000 * 60 * 10, // 10 minutes
|
|
32
|
+
retry: 1,
|
|
33
|
+
refetchOnWindowFocus: false,
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
/**
|
|
38
|
+
* Hook to fetch codemode status and compute Jupyter error banner.
|
|
39
|
+
* Must be used inside QueryClientProvider.
|
|
40
|
+
*/
|
|
41
|
+
function useJupyterSandboxStatus(baseUrl, isConfigured, enableCodemode, useJupyterSandbox, codemodeStatusData) {
|
|
42
|
+
// REST polling removed — data comes exclusively via WS `agent.snapshot`.
|
|
43
|
+
const codemodeStatus = codemodeStatusData;
|
|
44
|
+
return React.useMemo(() => {
|
|
45
|
+
if (!isConfigured || !enableCodemode || !useJupyterSandbox) {
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
const sandbox = codemodeStatus?.sandbox;
|
|
49
|
+
if (!sandbox) {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
// Check if Jupyter variant is selected but not connected
|
|
53
|
+
if (sandbox.variant === 'jupyter' && !sandbox.jupyter_connected) {
|
|
54
|
+
return {
|
|
55
|
+
message: sandbox.jupyter_error
|
|
56
|
+
? `Jupyter Sandbox Error: ${sandbox.jupyter_error}`
|
|
57
|
+
: 'Jupyter Sandbox not connected. Code execution may fail.',
|
|
58
|
+
variant: 'danger',
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
return undefined;
|
|
62
|
+
}, [isConfigured, enableCodemode, useJupyterSandbox, codemodeStatus]);
|
|
63
|
+
}
|
|
64
|
+
function ChatWithJupyterStatus({ baseUrl, isConfigured, enableCodemode, useJupyterSandbox, chatProps, }) {
|
|
65
|
+
const jupyterErrorBanner = useJupyterSandboxStatus(baseUrl, isConfigured, enableCodemode, useJupyterSandbox);
|
|
66
|
+
return _jsx(Chat, { ...chatProps, errorBanner: jupyterErrorBanner });
|
|
67
|
+
}
|
|
68
|
+
// Default configuration - use environment variable if available
|
|
69
|
+
// Note: Vercel AI connects to Jupyter server (8888), other protocols connect to agent-runtimes server (8765)
|
|
70
|
+
const DEFAULT_WS_URL = import.meta.env.VITE_ACP_WS_URL || 'ws://localhost:8765/api/v1/acp/ws';
|
|
71
|
+
const DEFAULT_BASE_URL = import.meta.env.VITE_BASE_URL || 'http://localhost:8765';
|
|
72
|
+
const DEFAULT_AGENT_ID = 'example-agent';
|
|
73
|
+
const DEFAULT_SYSTEM_PROMPT = 'You are a helpful AI assistant.';
|
|
74
|
+
const RIGHT_PANE_WIDTH = {
|
|
75
|
+
min: '520px',
|
|
76
|
+
default: '520px',
|
|
77
|
+
max: '520px',
|
|
78
|
+
};
|
|
79
|
+
// GitHub OAuth client ID - set via environment variable for security
|
|
80
|
+
// For development, you can create a GitHub OAuth App at:
|
|
81
|
+
// https://github.com/settings/developers
|
|
82
|
+
const GITHUB_CLIENT_ID = import.meta.env.VITE_GITHUB_CLIENT_ID || 'example-client-id';
|
|
83
|
+
// Kaggle API token - set via environment variable
|
|
84
|
+
// Get your token at: https://www.kaggle.com/settings/account (API section)
|
|
85
|
+
// Download kaggle.json and use the "key" value
|
|
86
|
+
const KAGGLE_TOKEN = import.meta.env.VITE_KAGGLE_TOKEN || '';
|
|
87
|
+
const isPlainObject = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
88
|
+
const yamlScalar = (value) => {
|
|
89
|
+
if (value === null || value === undefined) {
|
|
90
|
+
return 'null';
|
|
91
|
+
}
|
|
92
|
+
if (typeof value === 'number' || typeof value === 'boolean') {
|
|
93
|
+
return String(value);
|
|
94
|
+
}
|
|
95
|
+
const str = String(value);
|
|
96
|
+
if (str === '') {
|
|
97
|
+
return "''";
|
|
98
|
+
}
|
|
99
|
+
if (/^[a-zA-Z0-9._/-]+$/.test(str)) {
|
|
100
|
+
return str;
|
|
101
|
+
}
|
|
102
|
+
return JSON.stringify(str);
|
|
103
|
+
};
|
|
104
|
+
const toYaml = (value, indent = 0) => {
|
|
105
|
+
const pad = ' '.repeat(indent);
|
|
106
|
+
if (Array.isArray(value)) {
|
|
107
|
+
if (value.length === 0) {
|
|
108
|
+
return '[]';
|
|
109
|
+
}
|
|
110
|
+
return value
|
|
111
|
+
.map(item => {
|
|
112
|
+
if (isPlainObject(item) || Array.isArray(item)) {
|
|
113
|
+
return `${pad}-\n${toYaml(item, indent + 1)}`;
|
|
114
|
+
}
|
|
115
|
+
return `${pad}- ${yamlScalar(item)}`;
|
|
116
|
+
})
|
|
117
|
+
.join('\n');
|
|
118
|
+
}
|
|
119
|
+
if (isPlainObject(value)) {
|
|
120
|
+
const entries = Object.entries(value).filter(([, v]) => v !== undefined);
|
|
121
|
+
if (entries.length === 0) {
|
|
122
|
+
return '{}';
|
|
123
|
+
}
|
|
124
|
+
return entries
|
|
125
|
+
.map(([key, val]) => {
|
|
126
|
+
if (isPlainObject(val) || Array.isArray(val)) {
|
|
127
|
+
return `${pad}${key}:\n${toYaml(val, indent + 1)}`;
|
|
128
|
+
}
|
|
129
|
+
return `${pad}${key}: ${yamlScalar(val)}`;
|
|
130
|
+
})
|
|
131
|
+
.join('\n');
|
|
132
|
+
}
|
|
133
|
+
return `${pad}${yamlScalar(value)}`;
|
|
134
|
+
};
|
|
135
|
+
const normalizeHttpUrl = (value) => {
|
|
136
|
+
if (typeof value !== 'string') {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
const trimmed = value.trim();
|
|
140
|
+
if (!trimmed) {
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
if (!/^https?:\/\//i.test(trimmed)) {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
const url = new URL(trimmed);
|
|
148
|
+
url.pathname = url.pathname.replace(/\/$/, '');
|
|
149
|
+
return url.toString().replace(/\/$/, '');
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
const isLocalhostUrl = (value) => {
|
|
156
|
+
if (!value) {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
try {
|
|
160
|
+
const url = new URL(value);
|
|
161
|
+
return (url.hostname === 'localhost' ||
|
|
162
|
+
url.hostname === '127.0.0.1' ||
|
|
163
|
+
url.hostname === '0.0.0.0');
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
const collectUrlCandidates = (value, out = [], visited = new Set()) => {
|
|
170
|
+
if (value == null || visited.has(value)) {
|
|
171
|
+
return out;
|
|
172
|
+
}
|
|
173
|
+
if (typeof value === 'string') {
|
|
174
|
+
const normalized = normalizeHttpUrl(value);
|
|
175
|
+
if (normalized) {
|
|
176
|
+
out.push(normalized);
|
|
177
|
+
}
|
|
178
|
+
return out;
|
|
179
|
+
}
|
|
180
|
+
if (typeof value !== 'object') {
|
|
181
|
+
return out;
|
|
182
|
+
}
|
|
183
|
+
visited.add(value);
|
|
184
|
+
if (Array.isArray(value)) {
|
|
185
|
+
for (const item of value) {
|
|
186
|
+
collectUrlCandidates(item, out, visited);
|
|
187
|
+
}
|
|
188
|
+
return out;
|
|
189
|
+
}
|
|
190
|
+
const record = value;
|
|
191
|
+
for (const [key, nested] of Object.entries(record)) {
|
|
192
|
+
const lower = key.toLowerCase();
|
|
193
|
+
if (lower.includes('url') ||
|
|
194
|
+
lower.includes('endpoint') ||
|
|
195
|
+
lower.includes('host')) {
|
|
196
|
+
collectUrlCandidates(nested, out, visited);
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
if (lower.includes('service') ||
|
|
200
|
+
lower.includes('run') ||
|
|
201
|
+
lower.includes('cloud') ||
|
|
202
|
+
lower.includes('runtime') ||
|
|
203
|
+
lower.includes('agent')) {
|
|
204
|
+
collectUrlCandidates(nested, out, visited);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return out;
|
|
208
|
+
};
|
|
209
|
+
const resolveCloudRuntimeBaseUrlFromSpec = (spec) => {
|
|
210
|
+
if (!spec) {
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
const preferredKeys = [
|
|
214
|
+
'runtimesRunUrl',
|
|
215
|
+
'runtimeRunUrl',
|
|
216
|
+
'runtimes_url',
|
|
217
|
+
'runtime_url',
|
|
218
|
+
'runUrl',
|
|
219
|
+
'baseUrl',
|
|
220
|
+
'endpoint',
|
|
221
|
+
];
|
|
222
|
+
for (const key of preferredKeys) {
|
|
223
|
+
const candidate = normalizeHttpUrl(spec[key]);
|
|
224
|
+
if (candidate && !isLocalhostUrl(candidate)) {
|
|
225
|
+
return candidate;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
const serviceRoots = [
|
|
229
|
+
spec.services,
|
|
230
|
+
spec.cloud,
|
|
231
|
+
spec.runtime,
|
|
232
|
+
spec.agent,
|
|
233
|
+
spec.metadata,
|
|
234
|
+
spec,
|
|
235
|
+
];
|
|
236
|
+
const candidates = serviceRoots.flatMap(root => collectUrlCandidates(root));
|
|
237
|
+
const nonLocal = candidates.find(url => !isLocalhostUrl(url));
|
|
238
|
+
return nonLocal || null;
|
|
239
|
+
};
|
|
240
|
+
const MOCK_SKILLS = [];
|
|
241
|
+
// Skills are now fetched dynamically from the backend API (/api/v1/skills)
|
|
242
|
+
// when Codemode is enabled. The AgentConfiguration component handles this.
|
|
243
|
+
// Build default identity providers from env vars (backward compatibility)
|
|
244
|
+
const DEFAULT_IDENTITY_PROVIDERS = {
|
|
245
|
+
...(GITHUB_CLIENT_ID
|
|
246
|
+
? {
|
|
247
|
+
github: {
|
|
248
|
+
type: 'oauth',
|
|
249
|
+
clientId: GITHUB_CLIENT_ID,
|
|
250
|
+
scopes: ['read:user', 'user:email', 'repo'],
|
|
251
|
+
},
|
|
252
|
+
}
|
|
253
|
+
: {}),
|
|
254
|
+
...(KAGGLE_TOKEN
|
|
255
|
+
? {
|
|
256
|
+
kaggle: {
|
|
257
|
+
type: 'token',
|
|
258
|
+
token: KAGGLE_TOKEN,
|
|
259
|
+
displayName: 'Kaggle',
|
|
260
|
+
iconUrl: 'https://www.kaggle.com/static/images/favicon.ico',
|
|
261
|
+
},
|
|
262
|
+
}
|
|
263
|
+
: {}),
|
|
264
|
+
};
|
|
265
|
+
const AgentspecsExample = ({ initialWsUrl = DEFAULT_WS_URL, initialBaseUrl = DEFAULT_BASE_URL, initialAgentName = DEFAULT_AGENT_ID, initialAgentLibrary = 'pydantic-ai', initialTransport = 'vercel-ai', initialModel = DEFAULT_MODEL, initialEnableCodemode = false, initialAllowDirectToolCalls = false, initialEnableToolReranker = false, initialSelectedMcpServers = [], autoSelectMcpServers = false, identityProviders = DEFAULT_IDENTITY_PROVIDERS,
|
|
266
|
+
// Deprecated props - merged into identityProviders for backward compat
|
|
267
|
+
githubClientId, kaggleToken, }) => {
|
|
268
|
+
const [wsUrl, setWsUrl] = useState(initialWsUrl);
|
|
269
|
+
const [baseUrl, setBaseUrl] = useState(initialBaseUrl);
|
|
270
|
+
const [agentName, setAgentName] = useState(initialAgentName);
|
|
271
|
+
const [selectedAgentId, setSelectedAgentId] = useState('new-agent');
|
|
272
|
+
const [agentLibrary, setAgentLibrary] = useState(initialAgentLibrary);
|
|
273
|
+
const [transport, setTransport] = useState(initialTransport);
|
|
274
|
+
const [extensions, setExtensions] = useState([]);
|
|
275
|
+
const [model, setModel] = useState(initialModel);
|
|
276
|
+
const [description, setDescription] = useState('');
|
|
277
|
+
const [goal, setGoal] = useState('');
|
|
278
|
+
const [systemPrompt, setSystemPrompt] = useState(DEFAULT_SYSTEM_PROMPT);
|
|
279
|
+
const [systemPromptCodemodeAddons, setSystemPromptCodemodeAddons] = useState('');
|
|
280
|
+
const [tools, setTools] = useState([]);
|
|
281
|
+
const [sandboxVariant, setSandboxVariant] = useState('');
|
|
282
|
+
const [selectedLibrarySpec, setSelectedLibrarySpec] = useState(null);
|
|
283
|
+
const [selectedCloudSpec, setSelectedCloudSpec] = useState(null);
|
|
284
|
+
const [cloudLibrarySpecs, setCloudLibrarySpecs] = useState([]);
|
|
285
|
+
const [cloudLibraryLoading, setCloudLibraryLoading] = useState(false);
|
|
286
|
+
const [cloudLibraryError, setCloudLibraryError] = useState(null);
|
|
287
|
+
const [showSpecOverlay, setShowSpecOverlay] = useState(false);
|
|
288
|
+
const [isConfigured, setIsConfigured] = useState(false);
|
|
289
|
+
// Agent capabilities state (moved from Header toggles)
|
|
290
|
+
const [selectedSkills, setSelectedSkills] = useState([]);
|
|
291
|
+
const [enableCodemode, setEnableCodemode] = useState(initialEnableCodemode);
|
|
292
|
+
const [useJupyterSandbox, setUseJupyterSandbox] = useState(false);
|
|
293
|
+
const [allowDirectToolCalls, setAllowDirectToolCalls] = useState(initialAllowDirectToolCalls);
|
|
294
|
+
const [enableToolReranker, setEnableToolReranker] = useState(initialEnableToolReranker);
|
|
295
|
+
const [selectedMcpServers, setSelectedMcpServers] = useState(initialSelectedMcpServers);
|
|
296
|
+
const autoSelectRef = useRef(false);
|
|
297
|
+
const enableSkills = selectedSkills.length > 0;
|
|
298
|
+
const { configuration } = useCoreStore();
|
|
299
|
+
const { token } = useSimpleAuthStore();
|
|
300
|
+
const cloudCatalogBaseUrl = useMemo(() => {
|
|
301
|
+
const configured = normalizeHttpUrl(configuration?.runtimesRunUrl);
|
|
302
|
+
const envConfigured = normalizeHttpUrl(import.meta.env.VITE_DATALAYER_AGENT_RUNTIMES_URL);
|
|
303
|
+
if (configured && !isLocalhostUrl(configured)) {
|
|
304
|
+
return configured;
|
|
305
|
+
}
|
|
306
|
+
return envConfigured || 'https://r1.datalayer.run';
|
|
307
|
+
}, [configuration?.runtimesRunUrl]);
|
|
308
|
+
const isCloudMode = isCloudSpecSelection(selectedAgentId);
|
|
309
|
+
const selectedSpec = selectedCloudSpec || selectedLibrarySpec;
|
|
310
|
+
const cloudRuntimeCreationBaseUrl = useMemo(() => {
|
|
311
|
+
if (!isCloudMode) {
|
|
312
|
+
return cloudCatalogBaseUrl;
|
|
313
|
+
}
|
|
314
|
+
return (resolveCloudRuntimeBaseUrlFromSpec(selectedCloudSpec) ||
|
|
315
|
+
cloudCatalogBaseUrl);
|
|
316
|
+
}, [isCloudMode, selectedCloudSpec, cloudCatalogBaseUrl]);
|
|
317
|
+
const serviceBaseUrlForSelection = isCloudMode
|
|
318
|
+
? cloudRuntimeCreationBaseUrl
|
|
319
|
+
: baseUrl;
|
|
320
|
+
// =====================================================================
|
|
321
|
+
// Two-Container Codemode Architecture
|
|
322
|
+
// =====================================================================
|
|
323
|
+
//
|
|
324
|
+
// When Jupyter sandbox is enabled, the architecture uses two containers:
|
|
325
|
+
//
|
|
326
|
+
// ┌─────────────────────────────────────┐ ┌─────────────────────────────────┐
|
|
327
|
+
// │ agent-runtimes (port 8765) │ │ jupyter server (port 8888) │
|
|
328
|
+
// │ ┌─────────────────────────────┐ │ │ ┌─────────────────────────┐ │
|
|
329
|
+
// │ │ MCP Servers (stdio) │ │ │ │ Jupyter Kernel │ │
|
|
330
|
+
// │ │ - github, filesystem, etc │◀───┼──┼──│ executes generated │ │
|
|
331
|
+
// │ └─────────────────────────────┘ │ │ │ Python code │ │
|
|
332
|
+
// │ ┌─────────────────────────────┐ │ │ └─────────────────────────┘ │
|
|
333
|
+
// │ │ /api/v1/mcp/proxy/* │ │ │ │
|
|
334
|
+
// │ │ HTTP proxy for tool calls │ │ │ Tool calls go via HTTP to │
|
|
335
|
+
// │ └─────────────────────────────┘ │ │ agent-runtimes MCP proxy │
|
|
336
|
+
// └─────────────────────────────────────┘ └─────────────────────────────────┘
|
|
337
|
+
//
|
|
338
|
+
// The backend automatically configures mcp_proxy_url when jupyter_sandbox
|
|
339
|
+
// is provided, defaulting to http://0.0.0.0:8765/api/v1/mcp/proxy
|
|
340
|
+
//
|
|
341
|
+
// =====================================================================
|
|
342
|
+
// Jupyter sandbox URL (used when useJupyterSandbox is true)
|
|
343
|
+
// Can be configured via VITE_JUPYTER_SANDBOX_URL environment variable
|
|
344
|
+
const jupyterSandboxUrl = import.meta.env.VITE_JUPYTER_SANDBOX_URL ||
|
|
345
|
+
'http://localhost:8888/api/jupyter-server?token=60c1661cc408f978c309d04157af55c9588ff9557c9380e4fb50785750703da6';
|
|
346
|
+
const handleSelectedServersChange = React.useCallback((newServers) => {
|
|
347
|
+
const oldServers = selectedMcpServers;
|
|
348
|
+
// Find added and removed servers
|
|
349
|
+
const oldIds = new Set(oldServers.map(s => `${s.id}:${s.origin}`));
|
|
350
|
+
const newIds = new Set(newServers.map(s => `${s.id}:${s.origin}`));
|
|
351
|
+
const added = newServers.filter(s => !oldIds.has(`${s.id}:${s.origin}`));
|
|
352
|
+
const removed = oldServers.filter(s => !newIds.has(`${s.id}:${s.origin}`));
|
|
353
|
+
// Add system message about tool changes if there are any
|
|
354
|
+
if ((added.length > 0 || removed.length > 0) && isConfigured) {
|
|
355
|
+
let messageContent = '';
|
|
356
|
+
if (added.length > 0) {
|
|
357
|
+
const addedNames = added.map(s => `${s.id} (${s.origin})`).join(', ');
|
|
358
|
+
messageContent += `🔧 Tools added: ${addedNames}. `;
|
|
359
|
+
}
|
|
360
|
+
if (removed.length > 0) {
|
|
361
|
+
const removedNames = removed
|
|
362
|
+
.map(s => `${s.id} (${s.origin})`)
|
|
363
|
+
.join(', ');
|
|
364
|
+
messageContent += `🔧 Tools removed: ${removedNames}. You no longer have access to these tools.`;
|
|
365
|
+
}
|
|
366
|
+
if (messageContent) {
|
|
367
|
+
const systemMessage = {
|
|
368
|
+
id: `system-mcp-${Date.now()}`,
|
|
369
|
+
role: 'system',
|
|
370
|
+
content: messageContent.trim(),
|
|
371
|
+
createdAt: new Date(),
|
|
372
|
+
};
|
|
373
|
+
useChatStore.getState().addMessage(systemMessage);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
setSelectedMcpServers(newServers);
|
|
377
|
+
}, [selectedMcpServers, isConfigured]);
|
|
378
|
+
// Merge deprecated props into identityProviders for backward compatibility
|
|
379
|
+
const mergedIdentityProviders = React.useMemo(() => {
|
|
380
|
+
const merged = { ...identityProviders };
|
|
381
|
+
// Add deprecated githubClientId if provided and not already in config
|
|
382
|
+
if (githubClientId && !merged.github) {
|
|
383
|
+
merged.github = {
|
|
384
|
+
type: 'oauth',
|
|
385
|
+
clientId: githubClientId,
|
|
386
|
+
scopes: ['read:user', 'user:email', 'repo'],
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
// Add deprecated kaggleToken if provided and not already in config
|
|
390
|
+
if (kaggleToken && !merged.kaggle) {
|
|
391
|
+
merged.kaggle = {
|
|
392
|
+
type: 'token',
|
|
393
|
+
token: kaggleToken,
|
|
394
|
+
displayName: 'Kaggle',
|
|
395
|
+
iconUrl: 'https://www.kaggle.com/static/images/favicon.ico',
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
return merged;
|
|
399
|
+
}, [identityProviders, githubClientId, kaggleToken]);
|
|
400
|
+
// Extract OAuth providers for useIdentity hook (token providers are handled separately)
|
|
401
|
+
const oauthProvidersConfig = React.useMemo(() => {
|
|
402
|
+
const providers = {};
|
|
403
|
+
for (const [provider, config] of Object.entries(mergedIdentityProviders)) {
|
|
404
|
+
if (config.type === 'oauth') {
|
|
405
|
+
providers[provider] = {
|
|
406
|
+
clientId: config.clientId,
|
|
407
|
+
scopes: config.scopes,
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
return Object.keys(providers).length > 0 ? providers : undefined;
|
|
412
|
+
}, [mergedIdentityProviders]);
|
|
413
|
+
// Extract token-based providers for auto-connection
|
|
414
|
+
const tokenProviders = React.useMemo(() => {
|
|
415
|
+
const providers = [];
|
|
416
|
+
for (const [provider, config] of Object.entries(mergedIdentityProviders)) {
|
|
417
|
+
if (config.type === 'token') {
|
|
418
|
+
providers.push({
|
|
419
|
+
provider,
|
|
420
|
+
token: config.token,
|
|
421
|
+
displayName: config.displayName,
|
|
422
|
+
iconUrl: config.iconUrl,
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
return providers;
|
|
427
|
+
}, [mergedIdentityProviders]);
|
|
428
|
+
// Identity state - pass OAuth providers to configure them before callback is processed
|
|
429
|
+
const { connectWithToken, isConnected: isIdentityConnected } = useIdentity({
|
|
430
|
+
providers: oauthProvidersConfig,
|
|
431
|
+
autoHandleCallback: true,
|
|
432
|
+
});
|
|
433
|
+
// Track which token providers we've attempted to connect
|
|
434
|
+
const connectedTokenProvidersRef = useRef(new Set());
|
|
435
|
+
// Auto-connect all token-based providers if available and not already connected
|
|
436
|
+
useEffect(() => {
|
|
437
|
+
for (const { provider, token, displayName, iconUrl } of tokenProviders) {
|
|
438
|
+
// Skip if we've already attempted to connect this provider
|
|
439
|
+
if (connectedTokenProvidersRef.current.has(provider)) {
|
|
440
|
+
continue;
|
|
441
|
+
}
|
|
442
|
+
// Skip if already connected
|
|
443
|
+
if (isIdentityConnected(provider)) {
|
|
444
|
+
connectedTokenProvidersRef.current.add(provider);
|
|
445
|
+
continue;
|
|
446
|
+
}
|
|
447
|
+
// Mark as attempted
|
|
448
|
+
connectedTokenProvidersRef.current.add(provider);
|
|
449
|
+
connectWithToken(provider, token, { displayName, iconUrl })
|
|
450
|
+
.then(() => {
|
|
451
|
+
console.log(`[AgentRuntimeFormExample] ${provider} connected with token`);
|
|
452
|
+
})
|
|
453
|
+
.catch(err => {
|
|
454
|
+
console.error(`[AgentRuntimeFormExample] Failed to connect ${provider}:`, err);
|
|
455
|
+
// Remove from attempted set so we can retry
|
|
456
|
+
connectedTokenProvidersRef.current.delete(provider);
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
}, [tokenProviders, connectWithToken, isIdentityConnected]);
|
|
460
|
+
// Handle identity connect/disconnect
|
|
461
|
+
const handleIdentityConnect = useCallback((identity) => {
|
|
462
|
+
console.log('[AgentRuntimeFormExample] Identity connected:', identity.provider, identity.userInfo?.name || identity.userInfo?.email);
|
|
463
|
+
}, []);
|
|
464
|
+
const handleIdentityDisconnect = useCallback((provider) => {
|
|
465
|
+
console.log('[AgentRuntimeFormExample] Identity disconnected:', provider);
|
|
466
|
+
}, []);
|
|
467
|
+
// Handle codemode change - keep MCP server selections to scope codemode tools
|
|
468
|
+
const handleEnableCodemodeChange = (enabled) => {
|
|
469
|
+
setEnableCodemode(enabled);
|
|
470
|
+
if (!enabled) {
|
|
471
|
+
setAllowDirectToolCalls(false);
|
|
472
|
+
setEnableToolReranker(false);
|
|
473
|
+
setUseJupyterSandbox(false);
|
|
474
|
+
}
|
|
475
|
+
};
|
|
476
|
+
// UI state
|
|
477
|
+
const [activeSession, setActiveSession] = useState('session-1');
|
|
478
|
+
const [codemode, _] = useState(false);
|
|
479
|
+
const [showContextTree, setShowContextTree] = useState(false);
|
|
480
|
+
const [leftPaneVisible, setLeftPaneVisible] = useState(false);
|
|
481
|
+
const [rightPaneVisible, setRightPaneVisible] = useState(true);
|
|
482
|
+
const [isCreatingAgent, setIsCreatingAgent] = useState(false);
|
|
483
|
+
const [createError, setCreateError] = useState(null);
|
|
484
|
+
// Get agents and current agent from store
|
|
485
|
+
const agents = useAgentsStore(state => state.agents);
|
|
486
|
+
const currentAgent = useAgentsStore(state => state.getAgentById(selectedAgentId));
|
|
487
|
+
const toggleAgentStatus = useAgentsStore(state => state.toggleAgentStatus);
|
|
488
|
+
// Initialize transport from selected agent on mount
|
|
489
|
+
useEffect(() => {
|
|
490
|
+
if (currentAgent) {
|
|
491
|
+
setTransport(currentAgent.protocol);
|
|
492
|
+
setAgentName(currentAgent.id);
|
|
493
|
+
}
|
|
494
|
+
}, [currentAgent]);
|
|
495
|
+
// Auto-select MCP servers for codemode when requested
|
|
496
|
+
useEffect(() => {
|
|
497
|
+
if (!autoSelectMcpServers || autoSelectRef.current)
|
|
498
|
+
return;
|
|
499
|
+
if (!enableCodemode)
|
|
500
|
+
return;
|
|
501
|
+
if (selectedMcpServers.length > 0)
|
|
502
|
+
return;
|
|
503
|
+
if (!serviceBaseUrlForSelection)
|
|
504
|
+
return;
|
|
505
|
+
const loadServers = async () => {
|
|
506
|
+
try {
|
|
507
|
+
const response = await fetch(`${serviceBaseUrlForSelection}/api/v1/configure`, {
|
|
508
|
+
headers: token ? { Authorization: `Bearer ${token}` } : {},
|
|
509
|
+
});
|
|
510
|
+
if (!response.ok)
|
|
511
|
+
return;
|
|
512
|
+
const data = await response.json();
|
|
513
|
+
const servers = data?.mcpServers || [];
|
|
514
|
+
const available = servers.filter((s) => s.isAvailable);
|
|
515
|
+
if (available.length > 0) {
|
|
516
|
+
setSelectedMcpServers([{ id: available[0].id, origin: 'config' }]);
|
|
517
|
+
autoSelectRef.current = true;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
catch {
|
|
521
|
+
// no-op
|
|
522
|
+
}
|
|
523
|
+
};
|
|
524
|
+
void loadServers();
|
|
525
|
+
}, [
|
|
526
|
+
autoSelectMcpServers,
|
|
527
|
+
enableCodemode,
|
|
528
|
+
selectedMcpServers,
|
|
529
|
+
serviceBaseUrlForSelection,
|
|
530
|
+
token,
|
|
531
|
+
]);
|
|
532
|
+
// Track previous MCP servers to detect changes
|
|
533
|
+
const prevMcpServersRef = useRef(selectedMcpServers);
|
|
534
|
+
// Cache for library specs (fetched on-demand, outside QueryClientProvider)
|
|
535
|
+
const librarySpecsRef = useRef(null);
|
|
536
|
+
const fetchLibrarySpecs = useCallback(async () => {
|
|
537
|
+
if (librarySpecsRef.current)
|
|
538
|
+
return librarySpecsRef.current;
|
|
539
|
+
try {
|
|
540
|
+
const response = await fetch(`${baseUrl}/api/v1/agents/library`);
|
|
541
|
+
if (!response.ok)
|
|
542
|
+
return [];
|
|
543
|
+
const data = await response.json();
|
|
544
|
+
librarySpecsRef.current = data;
|
|
545
|
+
return data;
|
|
546
|
+
}
|
|
547
|
+
catch {
|
|
548
|
+
return [];
|
|
549
|
+
}
|
|
550
|
+
}, [baseUrl]);
|
|
551
|
+
useEffect(() => {
|
|
552
|
+
let cancelled = false;
|
|
553
|
+
const fetchCloudLibrarySpecs = async () => {
|
|
554
|
+
if (!cloudCatalogBaseUrl) {
|
|
555
|
+
setCloudLibrarySpecs([]);
|
|
556
|
+
setCloudLibraryError(null);
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
setCloudLibraryLoading(true);
|
|
560
|
+
setCloudLibraryError(null);
|
|
561
|
+
try {
|
|
562
|
+
const response = await fetch(`${cloudCatalogBaseUrl}/api/v1/agents/library`, {
|
|
563
|
+
headers: token ? { Authorization: `Bearer ${token}` } : {},
|
|
564
|
+
});
|
|
565
|
+
if (!response.ok) {
|
|
566
|
+
throw new Error(`Cloud library fetch failed (${response.status})`);
|
|
567
|
+
}
|
|
568
|
+
const payload = (await response.json());
|
|
569
|
+
if (!cancelled) {
|
|
570
|
+
setCloudLibrarySpecs(payload || []);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
catch (error) {
|
|
574
|
+
if (!cancelled) {
|
|
575
|
+
setCloudLibrarySpecs([]);
|
|
576
|
+
setCloudLibraryError(error instanceof Error
|
|
577
|
+
? error.message
|
|
578
|
+
: 'Failed to fetch cloud agent specs');
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
finally {
|
|
582
|
+
if (!cancelled) {
|
|
583
|
+
setCloudLibraryLoading(false);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
};
|
|
587
|
+
void fetchCloudLibrarySpecs();
|
|
588
|
+
return () => {
|
|
589
|
+
cancelled = true;
|
|
590
|
+
};
|
|
591
|
+
}, [cloudCatalogBaseUrl, token]);
|
|
592
|
+
const applySpecToForm = useCallback((spec) => {
|
|
593
|
+
setAgentName(spec.id);
|
|
594
|
+
setDescription(spec.description || '');
|
|
595
|
+
setGoal(spec.goal || '');
|
|
596
|
+
setSystemPrompt(spec.systemPrompt || spec.goal || DEFAULT_SYSTEM_PROMPT);
|
|
597
|
+
setSystemPromptCodemodeAddons(spec.systemPromptCodemodeAddons || '');
|
|
598
|
+
setTools(spec.tools || []);
|
|
599
|
+
setSandboxVariant(spec.sandboxVariant || '');
|
|
600
|
+
if (spec.model) {
|
|
601
|
+
setModel(spec.model);
|
|
602
|
+
}
|
|
603
|
+
if (spec.protocol === 'ag-ui' ||
|
|
604
|
+
spec.protocol === 'acp' ||
|
|
605
|
+
spec.protocol === 'vercel-ai' ||
|
|
606
|
+
spec.protocol === 'a2a') {
|
|
607
|
+
setTransport(spec.protocol);
|
|
608
|
+
}
|
|
609
|
+
setSelectedMcpServers((spec.mcpServers || []).map(server => ({
|
|
610
|
+
id: server.id,
|
|
611
|
+
origin: 'config',
|
|
612
|
+
})));
|
|
613
|
+
setSelectedSkills(spec.skills || []);
|
|
614
|
+
const codemodeConfig = spec.codemode && typeof spec.codemode === 'object'
|
|
615
|
+
? spec.codemode
|
|
616
|
+
: null;
|
|
617
|
+
const codemodeEnabled = !!spec.systemPromptCodemodeAddons || !!codemodeConfig?.enabled;
|
|
618
|
+
setEnableCodemode(codemodeEnabled);
|
|
619
|
+
setAllowDirectToolCalls(Boolean(codemodeConfig?.allowDirectToolCalls ??
|
|
620
|
+
codemodeConfig?.allow_direct_tool_calls));
|
|
621
|
+
setEnableToolReranker(Boolean(codemodeConfig?.enableToolReranker ??
|
|
622
|
+
codemodeConfig?.enable_tool_reranker));
|
|
623
|
+
setUseJupyterSandbox(spec.sandboxVariant === 'jupyter');
|
|
624
|
+
}, []);
|
|
625
|
+
const mergedSpecForLaunch = useMemo(() => {
|
|
626
|
+
const normalizedProtocol = transport === 'vercel-ai-jupyter' ? 'vercel-ai' : transport;
|
|
627
|
+
const baseSpec = selectedSpec
|
|
628
|
+
? { ...selectedSpec }
|
|
629
|
+
: {};
|
|
630
|
+
const codemode = isPlainObject(baseSpec.codemode) && baseSpec.codemode
|
|
631
|
+
? { ...baseSpec.codemode }
|
|
632
|
+
: {};
|
|
633
|
+
codemode.enabled = enableCodemode;
|
|
634
|
+
codemode.allowDirectToolCalls = allowDirectToolCalls;
|
|
635
|
+
codemode.enableToolReranker = enableToolReranker;
|
|
636
|
+
return {
|
|
637
|
+
...baseSpec,
|
|
638
|
+
id: selectedSpec?.id || agentName,
|
|
639
|
+
name: agentName,
|
|
640
|
+
description: description || undefined,
|
|
641
|
+
goal: goal || undefined,
|
|
642
|
+
model: model || undefined,
|
|
643
|
+
protocol: normalizedProtocol,
|
|
644
|
+
systemPrompt: systemPrompt || undefined,
|
|
645
|
+
systemPromptCodemodeAddons: systemPromptCodemodeAddons || undefined,
|
|
646
|
+
tools,
|
|
647
|
+
sandboxVariant: sandboxVariant || undefined,
|
|
648
|
+
skills: selectedSkills,
|
|
649
|
+
mcpServers: selectedMcpServers.map(server => ({
|
|
650
|
+
id: server.id,
|
|
651
|
+
origin: server.origin,
|
|
652
|
+
})),
|
|
653
|
+
codemode,
|
|
654
|
+
};
|
|
655
|
+
}, [
|
|
656
|
+
transport,
|
|
657
|
+
selectedSpec,
|
|
658
|
+
agentName,
|
|
659
|
+
description,
|
|
660
|
+
goal,
|
|
661
|
+
model,
|
|
662
|
+
systemPrompt,
|
|
663
|
+
systemPromptCodemodeAddons,
|
|
664
|
+
tools,
|
|
665
|
+
sandboxVariant,
|
|
666
|
+
selectedSkills,
|
|
667
|
+
selectedMcpServers,
|
|
668
|
+
enableCodemode,
|
|
669
|
+
allowDirectToolCalls,
|
|
670
|
+
enableToolReranker,
|
|
671
|
+
]);
|
|
672
|
+
const specYamlPreview = useMemo(() => toYaml(mergedSpecForLaunch), [mergedSpecForLaunch]);
|
|
673
|
+
useEffect(() => {
|
|
674
|
+
if (!showSpecOverlay) {
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
677
|
+
const onKeyDown = (event) => {
|
|
678
|
+
if (event.key === 'Escape') {
|
|
679
|
+
setShowSpecOverlay(false);
|
|
680
|
+
}
|
|
681
|
+
};
|
|
682
|
+
window.addEventListener('keydown', onKeyDown);
|
|
683
|
+
return () => {
|
|
684
|
+
window.removeEventListener('keydown', onKeyDown);
|
|
685
|
+
};
|
|
686
|
+
}, [showSpecOverlay]);
|
|
687
|
+
const { runtime: cloudRuntime, status: cloudRuntimeStatus, error: cloudRuntimeError, launchRuntime: launchCloudRuntime, disconnect: disconnectCloudRuntime, } = useAgentRuntimes({
|
|
688
|
+
agentSpecId: isCloudMode ? getCloudSpecId(selectedAgentId) : undefined,
|
|
689
|
+
autoStart: false,
|
|
690
|
+
runtimeCreationTarget: 'backend-services',
|
|
691
|
+
runtimeCreationBaseUrl: cloudRuntimeCreationBaseUrl,
|
|
692
|
+
agentSpec: isCloudMode ? mergedSpecForLaunch : undefined,
|
|
693
|
+
agentConfig: {
|
|
694
|
+
name: agentName,
|
|
695
|
+
model,
|
|
696
|
+
protocol: transport === 'vercel-ai-jupyter' ? 'vercel-ai' : transport,
|
|
697
|
+
description: description || `Cloud agent launch for ${agentName}`,
|
|
698
|
+
},
|
|
699
|
+
});
|
|
700
|
+
const handleAgentSelect = async (agentId) => {
|
|
701
|
+
setSelectedAgentId(agentId);
|
|
702
|
+
setCreateError(null);
|
|
703
|
+
if (agentId === 'new-agent') {
|
|
704
|
+
// Reset to defaults for new agent
|
|
705
|
+
setAgentName(DEFAULT_AGENT_ID);
|
|
706
|
+
setDescription('');
|
|
707
|
+
setGoal('');
|
|
708
|
+
setSystemPrompt(DEFAULT_SYSTEM_PROMPT);
|
|
709
|
+
setSystemPromptCodemodeAddons('');
|
|
710
|
+
setTools([]);
|
|
711
|
+
setSandboxVariant('');
|
|
712
|
+
setSelectedSkills([]);
|
|
713
|
+
setSelectedMcpServers([]);
|
|
714
|
+
setSelectedLibrarySpec(null);
|
|
715
|
+
setSelectedCloudSpec(null);
|
|
716
|
+
setEnableCodemode(false);
|
|
717
|
+
setAllowDirectToolCalls(false);
|
|
718
|
+
setEnableToolReranker(false);
|
|
719
|
+
setUseJupyterSandbox(false);
|
|
720
|
+
setTransport('vercel-ai');
|
|
721
|
+
}
|
|
722
|
+
else if (isSpecSelection(agentId)) {
|
|
723
|
+
setSelectedCloudSpec(null);
|
|
724
|
+
const specId = getSpecId(agentId);
|
|
725
|
+
const specs = await fetchLibrarySpecs();
|
|
726
|
+
const spec = specs.find(s => s.id === specId);
|
|
727
|
+
if (spec) {
|
|
728
|
+
setSelectedLibrarySpec(spec);
|
|
729
|
+
applySpecToForm(spec);
|
|
730
|
+
}
|
|
731
|
+
else {
|
|
732
|
+
setSelectedLibrarySpec(null);
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
else if (isCloudSpecSelection(agentId)) {
|
|
736
|
+
setSelectedLibrarySpec(null);
|
|
737
|
+
const specId = getCloudSpecId(agentId);
|
|
738
|
+
const spec = cloudLibrarySpecs.find(s => s.id === specId) || null;
|
|
739
|
+
if (spec) {
|
|
740
|
+
setSelectedCloudSpec(spec);
|
|
741
|
+
applySpecToForm(spec);
|
|
742
|
+
}
|
|
743
|
+
else {
|
|
744
|
+
setSelectedCloudSpec(null);
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
else {
|
|
748
|
+
setSelectedLibrarySpec(null);
|
|
749
|
+
setSelectedCloudSpec(null);
|
|
750
|
+
const agent = agents.find(a => a.id === agentId);
|
|
751
|
+
if (agent) {
|
|
752
|
+
setAgentName(agent.id);
|
|
753
|
+
setTransport(agent.protocol);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
};
|
|
757
|
+
useEffect(() => {
|
|
758
|
+
if (isCloudMode && cloudRuntimeStatus === 'error' && cloudRuntimeError) {
|
|
759
|
+
setCreateError(cloudRuntimeError);
|
|
760
|
+
}
|
|
761
|
+
}, [isCloudMode, cloudRuntimeStatus, cloudRuntimeError]);
|
|
762
|
+
/**
|
|
763
|
+
* Create a new agent via the API
|
|
764
|
+
*/
|
|
765
|
+
const createAgentOnServer = useCallback(async () => {
|
|
766
|
+
setIsCreatingAgent(true);
|
|
767
|
+
setCreateError(null);
|
|
768
|
+
try {
|
|
769
|
+
// Resolve local spec ID when creating from local library specs.
|
|
770
|
+
const specId = isSpecSelection(selectedAgentId)
|
|
771
|
+
? getSpecId(selectedAgentId)
|
|
772
|
+
: undefined;
|
|
773
|
+
const response = await fetch(`${baseUrl}/api/v1/agents`, {
|
|
774
|
+
method: 'POST',
|
|
775
|
+
headers: {
|
|
776
|
+
'Content-Type': 'application/json',
|
|
777
|
+
},
|
|
778
|
+
body: JSON.stringify({
|
|
779
|
+
name: agentName,
|
|
780
|
+
description: description || `Agent created via UI (${agentLibrary})`,
|
|
781
|
+
goal: goal || undefined,
|
|
782
|
+
agent_library: agentLibrary,
|
|
783
|
+
transport: transport,
|
|
784
|
+
model: model,
|
|
785
|
+
system_prompt: systemPrompt || DEFAULT_SYSTEM_PROMPT,
|
|
786
|
+
system_prompt_codemode_addons: systemPromptCodemodeAddons || undefined,
|
|
787
|
+
tools: tools,
|
|
788
|
+
sandbox_variant: sandboxVariant || undefined,
|
|
789
|
+
enable_skills: enableSkills,
|
|
790
|
+
enable_codemode: enableCodemode,
|
|
791
|
+
allow_direct_tool_calls: allowDirectToolCalls,
|
|
792
|
+
enable_tool_reranker: enableToolReranker,
|
|
793
|
+
selected_mcp_servers: selectedMcpServers,
|
|
794
|
+
skills: selectedSkills,
|
|
795
|
+
jupyter_sandbox: useJupyterSandbox ? jupyterSandboxUrl : undefined,
|
|
796
|
+
agent_spec: mergedSpecForLaunch,
|
|
797
|
+
...(specId ? { agent_spec_id: specId } : {}),
|
|
798
|
+
}),
|
|
799
|
+
});
|
|
800
|
+
if (!response.ok) {
|
|
801
|
+
const errorData = await response
|
|
802
|
+
.json()
|
|
803
|
+
.catch(() => ({ detail: 'Unknown error' }));
|
|
804
|
+
throw new Error(errorData.detail || `Failed to create agent: ${response.status}`);
|
|
805
|
+
}
|
|
806
|
+
const data = await response.json();
|
|
807
|
+
console.log('[AgentRuntimeExample] Agent created:', data);
|
|
808
|
+
return data.id;
|
|
809
|
+
}
|
|
810
|
+
catch (error) {
|
|
811
|
+
const errorMessage = error instanceof Error ? error.message : 'Failed to create agent';
|
|
812
|
+
console.error('[AgentRuntimeExample] Error creating agent:', errorMessage);
|
|
813
|
+
setCreateError(errorMessage);
|
|
814
|
+
return null;
|
|
815
|
+
}
|
|
816
|
+
finally {
|
|
817
|
+
setIsCreatingAgent(false);
|
|
818
|
+
}
|
|
819
|
+
}, [
|
|
820
|
+
baseUrl,
|
|
821
|
+
agentName,
|
|
822
|
+
agentLibrary,
|
|
823
|
+
description,
|
|
824
|
+
goal,
|
|
825
|
+
transport,
|
|
826
|
+
model,
|
|
827
|
+
systemPrompt,
|
|
828
|
+
systemPromptCodemodeAddons,
|
|
829
|
+
tools,
|
|
830
|
+
sandboxVariant,
|
|
831
|
+
enableSkills,
|
|
832
|
+
enableCodemode,
|
|
833
|
+
allowDirectToolCalls,
|
|
834
|
+
enableToolReranker,
|
|
835
|
+
selectedMcpServers,
|
|
836
|
+
selectedSkills,
|
|
837
|
+
useJupyterSandbox,
|
|
838
|
+
jupyterSandboxUrl,
|
|
839
|
+
selectedAgentId,
|
|
840
|
+
mergedSpecForLaunch,
|
|
841
|
+
]);
|
|
842
|
+
/**
|
|
843
|
+
* Delete an agent via the API
|
|
844
|
+
*/
|
|
845
|
+
const deleteAgentOnServer = useCallback(async (agentId) => {
|
|
846
|
+
try {
|
|
847
|
+
const response = await fetch(`${baseUrl}/api/v1/agents/${agentId}`, {
|
|
848
|
+
method: 'DELETE',
|
|
849
|
+
});
|
|
850
|
+
if (!response.ok) {
|
|
851
|
+
console.warn(`[AgentRuntimeExample] Failed to delete agent: ${response.status}`);
|
|
852
|
+
return false;
|
|
853
|
+
}
|
|
854
|
+
console.log('[AgentRuntimeExample] Agent deleted:', agentId);
|
|
855
|
+
return true;
|
|
856
|
+
}
|
|
857
|
+
catch (error) {
|
|
858
|
+
console.warn('[AgentRuntimeExample] Error deleting agent:', error);
|
|
859
|
+
return false;
|
|
860
|
+
}
|
|
861
|
+
}, [baseUrl]);
|
|
862
|
+
// Track MCP servers for reference (no longer triggers recreation)
|
|
863
|
+
// MCP server updates are now handled via PATCH endpoint by McpServerManager
|
|
864
|
+
useEffect(() => {
|
|
865
|
+
prevMcpServersRef.current = selectedMcpServers;
|
|
866
|
+
}, [selectedMcpServers]);
|
|
867
|
+
// True when creating a new agent (blank or from a library spec)
|
|
868
|
+
const isNewMode = selectedAgentId === 'new-agent' ||
|
|
869
|
+
isSpecSelection(selectedAgentId) ||
|
|
870
|
+
isCloudSpecSelection(selectedAgentId);
|
|
871
|
+
const effectiveBaseUrl = isCloudMode && cloudRuntime?.agentBaseUrl
|
|
872
|
+
? cloudRuntime.agentBaseUrl
|
|
873
|
+
: baseUrl;
|
|
874
|
+
const effectiveAgentId = isCloudMode && cloudRuntime?.agentId
|
|
875
|
+
? cloudRuntime.agentId
|
|
876
|
+
: currentAgent?.id || agentName;
|
|
877
|
+
const effectiveProtocol = currentAgent?.protocol || transport;
|
|
878
|
+
const launchStatus = useMemo(() => {
|
|
879
|
+
if (createError) {
|
|
880
|
+
return 'error';
|
|
881
|
+
}
|
|
882
|
+
if (isCloudMode) {
|
|
883
|
+
return cloudRuntimeStatus || 'idle';
|
|
884
|
+
}
|
|
885
|
+
if (isCreatingAgent) {
|
|
886
|
+
return 'launching';
|
|
887
|
+
}
|
|
888
|
+
return isConfigured ? 'ready' : 'idle';
|
|
889
|
+
}, [
|
|
890
|
+
createError,
|
|
891
|
+
isCloudMode,
|
|
892
|
+
cloudRuntimeStatus,
|
|
893
|
+
isCreatingAgent,
|
|
894
|
+
isConfigured,
|
|
895
|
+
]);
|
|
896
|
+
const handleConnect = async () => {
|
|
897
|
+
// For existing agents (not new-agent or spec), ensure transport and agentName are set
|
|
898
|
+
if (!isNewMode) {
|
|
899
|
+
const agent = agents.find(a => a.id === selectedAgentId);
|
|
900
|
+
if (agent) {
|
|
901
|
+
setTransport(agent.protocol);
|
|
902
|
+
setAgentName(agent.id);
|
|
903
|
+
}
|
|
904
|
+
setIsConfigured(true);
|
|
905
|
+
return;
|
|
906
|
+
}
|
|
907
|
+
if (isCloudMode) {
|
|
908
|
+
try {
|
|
909
|
+
const connection = await launchCloudRuntime();
|
|
910
|
+
setAgentName(connection.agentId || agentName);
|
|
911
|
+
if (connection.agentBaseUrl) {
|
|
912
|
+
setBaseUrl(connection.agentBaseUrl);
|
|
913
|
+
}
|
|
914
|
+
setIsConfigured(true);
|
|
915
|
+
}
|
|
916
|
+
catch (error) {
|
|
917
|
+
setCreateError(error instanceof Error
|
|
918
|
+
? error.message
|
|
919
|
+
: 'Failed to launch cloud agent');
|
|
920
|
+
}
|
|
921
|
+
return;
|
|
922
|
+
}
|
|
923
|
+
// For vercel-ai-jupyter, no server-side agent creation needed
|
|
924
|
+
// It uses Jupyter server's built-in agent endpoint
|
|
925
|
+
if (transport === 'vercel-ai-jupyter') {
|
|
926
|
+
setIsConfigured(true);
|
|
927
|
+
return;
|
|
928
|
+
}
|
|
929
|
+
// For new agents, first create the agent on the server
|
|
930
|
+
if (transport === 'acp' && wsUrl && agentName) {
|
|
931
|
+
const createdAgentId = await createAgentOnServer();
|
|
932
|
+
if (createdAgentId) {
|
|
933
|
+
setAgentName(createdAgentId);
|
|
934
|
+
setIsConfigured(true);
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
else if ((transport === 'ag-ui' ||
|
|
938
|
+
transport === 'vercel-ai' ||
|
|
939
|
+
transport === 'a2a') &&
|
|
940
|
+
baseUrl &&
|
|
941
|
+
agentName) {
|
|
942
|
+
const createdAgentId = await createAgentOnServer();
|
|
943
|
+
if (createdAgentId) {
|
|
944
|
+
setAgentName(createdAgentId);
|
|
945
|
+
setIsConfigured(true);
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
};
|
|
949
|
+
const handleReset = async () => {
|
|
950
|
+
if (isCloudMode) {
|
|
951
|
+
disconnectCloudRuntime();
|
|
952
|
+
setIsConfigured(false);
|
|
953
|
+
return;
|
|
954
|
+
}
|
|
955
|
+
// Delete the agent from the server if we created it
|
|
956
|
+
if ((selectedAgentId === 'new-agent' || isSpecSelection(selectedAgentId)) &&
|
|
957
|
+
agentName) {
|
|
958
|
+
await deleteAgentOnServer(agentName);
|
|
959
|
+
}
|
|
960
|
+
setIsConfigured(false);
|
|
961
|
+
};
|
|
962
|
+
return (_jsx(QueryClientProvider, { client: queryClient, children: _jsxs(ThemedProvider, { children: [_jsxs(PageLayout, { containerWidth: "full", children: [_jsx(Header, { activeSession: activeSession, agentName: isNewMode ? undefined : currentAgent?.name, agentDescription: isNewMode ? undefined : currentAgent?.description, agentStatus: currentAgent?.status, showContextTree: showContextTree, isNewAgent: isNewMode, isConfigured: isConfigured, onSessionChange: setActiveSession, onToggleContextTree: () => setShowContextTree(!showContextTree), onToggleStatus: currentAgent
|
|
963
|
+
? () => toggleAgentStatus(currentAgent.id)
|
|
964
|
+
: undefined }), leftPaneVisible ? (_jsxs(_Fragment, { children: [_jsx(Box, { sx: {
|
|
965
|
+
position: 'fixed',
|
|
966
|
+
left: 0,
|
|
967
|
+
top: '50%',
|
|
968
|
+
transform: 'translateY(-50%)',
|
|
969
|
+
zIndex: 100,
|
|
970
|
+
}, children: _jsx(IconButton, { icon: SidebarCollapseIcon, "aria-label": "Collapse left pane", size: "small", onClick: () => setLeftPaneVisible(false), sx: {
|
|
971
|
+
borderRadius: '0 6px 6px 0',
|
|
972
|
+
bg: 'canvas.default',
|
|
973
|
+
border: '1px solid',
|
|
974
|
+
borderLeft: 'none',
|
|
975
|
+
borderColor: 'border.default',
|
|
976
|
+
} }) }), _jsx(PageLayout.Pane, { position: "start", "aria-label": "File browser pane", resizable: true, sticky: true, width: { min: '250px', default: '300px', max: '1200px' }, children: isNewMode ? (_jsxs(Blankslate, { border: true, spacious: true, narrow: true, children: [_jsx(Blankslate.Visual, { children: _jsx(AiAgentIcon, { colored: true, size: 48 }) }), _jsx(Blankslate.Heading, { children: "Agent Runtimes" }), _jsx(Box, { sx: { textAlign: 'center' }, children: _jsx(Blankslate.Description, { children: "Expose AI Agents through multiple protocols." }) })] })) : (_jsx(MockFileBrowser, { codemode: codemode })) })] })) : (_jsx(Box, { sx: {
|
|
977
|
+
position: 'fixed',
|
|
978
|
+
left: 0,
|
|
979
|
+
top: '50%',
|
|
980
|
+
transform: 'translateY(-50%)',
|
|
981
|
+
zIndex: 100,
|
|
982
|
+
}, children: _jsx(IconButton, { icon: SidebarExpandIcon, "aria-label": "Expand left pane", size: "small", onClick: () => setLeftPaneVisible(true), sx: {
|
|
983
|
+
borderRadius: '0 6px 6px 0',
|
|
984
|
+
bg: 'canvas.default',
|
|
985
|
+
border: '1px solid',
|
|
986
|
+
borderLeft: 'none',
|
|
987
|
+
borderColor: 'border.default',
|
|
988
|
+
} }) })), _jsx(PageLayout.Content, { children: _jsx(MainContent, { showWelcomeMessage: true, isConfigured: isConfigured, baseUrl: effectiveBaseUrl, agentId: effectiveAgentId, enableCodemode: enableCodemode, selectedMcpServers: selectedMcpServers, onSelectedMcpServersChange: handleSelectedServersChange, onMcpServersChange: () => {
|
|
989
|
+
// Trigger codemode tool regeneration when MCP servers change at runtime
|
|
990
|
+
console.log('[AgentRuntimeFormExample] MCP servers changed, regenerating codemode tools...');
|
|
991
|
+
// The Chat component will pick up the new selectedMcpServers via props
|
|
992
|
+
} }) }), rightPaneVisible ? (_jsx(_Fragment, { children: _jsx(PageLayout.Pane, { position: "end", "aria-label": "Agent configuration and chat pane", width: RIGHT_PANE_WIDTH, sticky: true, children: _jsxs(Box, { sx: {
|
|
993
|
+
height: '100%',
|
|
994
|
+
display: 'flex',
|
|
995
|
+
flexDirection: 'column',
|
|
996
|
+
p: 2,
|
|
997
|
+
}, children: [_jsxs(Box, { sx: {
|
|
998
|
+
display: 'flex',
|
|
999
|
+
justifyContent: 'space-between',
|
|
1000
|
+
alignItems: 'center',
|
|
1001
|
+
mb: 2,
|
|
1002
|
+
gap: 2,
|
|
1003
|
+
}, children: [_jsx(IconButton, { icon: SidebarCollapseIcon, "aria-label": "Collapse right pane", size: "small", onClick: () => setRightPaneVisible(false), variant: "invisible" }), _jsx(Button, { size: "small", onClick: () => setShowSpecOverlay(true), children: "View Full Spec (YAML)" })] }), !isConfigured ? (_jsx(AgentConfiguration, { agentLibrary: agentLibrary, protocol: currentAgent?.protocol || transport, extensions: extensions, wsUrl: wsUrl, baseUrl: serviceBaseUrlForSelection, agentName: agentName, description: description, goal: goal, model: model, systemPrompt: systemPrompt, systemPromptCodemodeAddons: systemPromptCodemodeAddons, tools: tools, sandboxVariant: sandboxVariant, agents: agents, selectedAgentId: selectedAgentId, isCreatingAgent: isCreatingAgent, createError: createError, enableCodemode: enableCodemode, useJupyterSandbox: useJupyterSandbox, allowDirectToolCalls: allowDirectToolCalls, enableToolReranker: enableToolReranker, availableSkills: MOCK_SKILLS, selectedSkills: selectedSkills, selectedMcpServers: selectedMcpServers, cloudLibrarySpecs: cloudLibrarySpecs, cloudLibraryLoading: cloudLibraryLoading, cloudLibraryError: cloudLibraryError, launchTarget: isCloudMode ? 'cloud' : 'local', launchStatus: launchStatus, launchBaseUrl: serviceBaseUrlForSelection, identityProviders: oauthProvidersConfig, onIdentityConnect: handleIdentityConnect, onIdentityDisconnect: handleIdentityDisconnect, onAgentLibraryChange: setAgentLibrary, onTransportChange: setTransport, onExtensionsChange: setExtensions, onWsUrlChange: setWsUrl, onBaseUrlChange: isCloudMode
|
|
1004
|
+
? (_) => {
|
|
1005
|
+
/* Cloud mode uses cloud service URLs from spec/config. */
|
|
1006
|
+
}
|
|
1007
|
+
: setBaseUrl, onAgentNameChange: setAgentName, onDescriptionChange: setDescription, onGoalChange: setGoal, onModelChange: setModel, onSystemPromptChange: setSystemPrompt, onSystemPromptCodemodeAddonsChange: setSystemPromptCodemodeAddons, onToolsChange: setTools, onSandboxVariantChange: setSandboxVariant, onAgentSelect: handleAgentSelect, onConnect: handleConnect, onEnableCodemodeChange: handleEnableCodemodeChange, onUseJupyterSandboxChange: setUseJupyterSandbox, onAllowDirectToolCallsChange: setAllowDirectToolCalls, onEnableToolRerankerChange: setEnableToolReranker, onSelectedSkillsChange: setSelectedSkills, onSelectedMcpServersChange: setSelectedMcpServers })) : (
|
|
1008
|
+
/* Chat Interface */
|
|
1009
|
+
_jsx(Box, { sx: { flex: 1, minHeight: 0 }, children: _jsx(ChatWithJupyterStatus, { baseUrl: effectiveBaseUrl, isConfigured: isConfigured, enableCodemode: enableCodemode, useJupyterSandbox: useJupyterSandbox, chatProps: {
|
|
1010
|
+
protocol: effectiveProtocol,
|
|
1011
|
+
extensions: extensions,
|
|
1012
|
+
wsUrl: wsUrl,
|
|
1013
|
+
baseUrl: effectiveBaseUrl,
|
|
1014
|
+
agentId: effectiveAgentId,
|
|
1015
|
+
title: currentAgent?.name || agentName || 'AI Assistant',
|
|
1016
|
+
brandIcon: _jsx(AgentIcon, { size: 16 }),
|
|
1017
|
+
autoConnect: true,
|
|
1018
|
+
autoFocus: true,
|
|
1019
|
+
placeholder: 'Type your message to the agent...',
|
|
1020
|
+
height: 'calc(100vh - 150px)',
|
|
1021
|
+
showModelSelector: true,
|
|
1022
|
+
showToolsMenu: true,
|
|
1023
|
+
showSkillsMenu: true,
|
|
1024
|
+
showInformation: false,
|
|
1025
|
+
codemodeEnabled: enableCodemode,
|
|
1026
|
+
initialModel: model,
|
|
1027
|
+
mcpServers: selectedMcpServers,
|
|
1028
|
+
initialSkills: selectedSkills,
|
|
1029
|
+
identityProviders: oauthProvidersConfig,
|
|
1030
|
+
onIdentityConnect: handleIdentityConnect,
|
|
1031
|
+
onIdentityDisconnect: handleIdentityDisconnect,
|
|
1032
|
+
suggestions: [
|
|
1033
|
+
{
|
|
1034
|
+
title: '👋 Say hello',
|
|
1035
|
+
message: 'Hello! What can you help me with today?',
|
|
1036
|
+
},
|
|
1037
|
+
{
|
|
1038
|
+
title: '💡 Get ideas',
|
|
1039
|
+
message: 'Can you suggest some creative project ideas?',
|
|
1040
|
+
},
|
|
1041
|
+
{
|
|
1042
|
+
title: '📝 Explain concepts',
|
|
1043
|
+
message: 'Can you explain how AI agents work?',
|
|
1044
|
+
},
|
|
1045
|
+
{
|
|
1046
|
+
title: '🔧 Help with code',
|
|
1047
|
+
message: 'Can you help me write some Python code?',
|
|
1048
|
+
},
|
|
1049
|
+
],
|
|
1050
|
+
onDisconnect: handleReset,
|
|
1051
|
+
onMessageSent: (_content) => {
|
|
1052
|
+
// Message sent
|
|
1053
|
+
},
|
|
1054
|
+
onMessageReceived: (_message) => {
|
|
1055
|
+
// Message received
|
|
1056
|
+
},
|
|
1057
|
+
} }) }))] }) }) })) : (_jsx(Box, { sx: {
|
|
1058
|
+
position: 'fixed',
|
|
1059
|
+
right: 0,
|
|
1060
|
+
top: '50%',
|
|
1061
|
+
transform: 'translateY(-50%)',
|
|
1062
|
+
zIndex: 100,
|
|
1063
|
+
}, children: _jsx(IconButton, { icon: SidebarExpandIcon, "aria-label": "Expand right pane", size: "small", onClick: () => setRightPaneVisible(true), sx: {
|
|
1064
|
+
borderRadius: '6px 0 0 6px',
|
|
1065
|
+
bg: 'canvas.default',
|
|
1066
|
+
border: '1px solid',
|
|
1067
|
+
borderRight: 'none',
|
|
1068
|
+
borderColor: 'border.default',
|
|
1069
|
+
} }) }))] }), showSpecOverlay && (_jsxs(Box, { sx: {
|
|
1070
|
+
position: 'fixed',
|
|
1071
|
+
inset: 24,
|
|
1072
|
+
zIndex: 300,
|
|
1073
|
+
bg: 'canvas.default',
|
|
1074
|
+
border: '1px solid',
|
|
1075
|
+
borderColor: 'border.default',
|
|
1076
|
+
borderRadius: 1,
|
|
1077
|
+
boxShadow: 'shadow.large',
|
|
1078
|
+
display: 'flex',
|
|
1079
|
+
flexDirection: 'column',
|
|
1080
|
+
}, children: [_jsxs(Box, { sx: {
|
|
1081
|
+
display: 'flex',
|
|
1082
|
+
alignItems: 'center',
|
|
1083
|
+
justifyContent: 'space-between',
|
|
1084
|
+
px: 3,
|
|
1085
|
+
py: 2,
|
|
1086
|
+
borderBottom: '1px solid',
|
|
1087
|
+
borderColor: 'border.default',
|
|
1088
|
+
}, children: [_jsx(Text, { sx: { fontWeight: 'bold' }, children: "Spec Payload Preview (YAML)" }), _jsx(IconButton, { icon: XIcon, "aria-label": "Close spec preview", size: "small", variant: "invisible", onClick: () => setShowSpecOverlay(false) })] }), _jsx(Box, { sx: { p: 3, overflow: 'auto', flex: 1 }, children: _jsx(Box, { as: "pre", sx: {
|
|
1089
|
+
m: 0,
|
|
1090
|
+
whiteSpace: 'pre',
|
|
1091
|
+
fontFamily: 'monospace',
|
|
1092
|
+
fontSize: 0,
|
|
1093
|
+
lineHeight: '20px',
|
|
1094
|
+
}, children: specYamlPreview }) })] }))] }) }));
|
|
1095
|
+
};
|
|
1096
|
+
export default AgentspecsExample;
|