@datalayer/agent-runtimes 1.0.3 → 1.0.5
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 +35 -119
- package/lib/App.js +1 -1
- 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 -104
- package/lib/chat/Chat.js +4 -4
- package/lib/chat/ChatFloating.d.ts +7 -140
- package/lib/chat/ChatFloating.js +2 -2
- 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 +2 -2
- package/lib/chat/ChatStandalone.d.ts +4 -54
- package/lib/chat/ChatStandalone.js +3 -3
- package/lib/chat/base/ChatBase.js +1118 -141
- package/lib/chat/header/ChatHeaderBase.d.ts +11 -6
- package/lib/chat/header/ChatHeaderBase.js +18 -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 +9 -9
- 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 +110 -102
- package/lib/chat/prompt/InputFooter.d.ts +19 -6
- package/lib/chat/prompt/InputFooter.js +71 -18
- package/lib/chat/prompt/InputPrompt.d.ts +3 -1
- package/lib/chat/prompt/InputPrompt.js +4 -4
- package/lib/chat/prompt/InputPromptFooter.js +1 -1
- 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 +48 -19
- package/lib/client/AgentsMixin.js +115 -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 +55 -26
- package/lib/components/OutputCard.js +21 -7
- package/lib/components/ToolApprovalCard.js +20 -2
- package/lib/config/AgentConfiguration.js +3 -3
- 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/AgentCheckpointsExample.js +14 -34
- package/lib/examples/AgentCodemodeExample.d.ts +4 -6
- package/lib/examples/AgentCodemodeExample.js +591 -175
- package/lib/examples/AgentEvalsExample.js +13 -23
- package/lib/examples/AgentGuardrailsExample.js +371 -71
- package/lib/examples/AgentHooksExample.d.ts +3 -0
- package/lib/examples/AgentHooksExample.js +104 -0
- package/lib/examples/AgentMCPExample.d.ts +3 -0
- package/lib/examples/AgentMCPExample.js +480 -0
- package/lib/examples/AgentMemoryExample.js +14 -24
- package/lib/examples/AgentMonitoringExample.js +261 -206
- package/lib/examples/AgentNotificationsExample.js +50 -24
- package/lib/examples/AgentOtelExample.js +2 -3
- package/lib/examples/AgentOutputsExample.d.ts +11 -6
- package/lib/examples/AgentOutputsExample.js +383 -88
- package/lib/examples/AgentParametersExample.d.ts +3 -0
- package/lib/examples/AgentParametersExample.js +246 -0
- package/lib/examples/AgentSandboxExample.d.ts +2 -2
- package/lib/examples/AgentSandboxExample.js +69 -47
- package/lib/examples/AgentSkillsExample.js +92 -106
- package/lib/examples/{AgentspecExample.js → AgentSpecsExample.js} +10 -21
- package/lib/examples/AgentSubagentsExample.d.ts +14 -0
- package/lib/examples/AgentSubagentsExample.js +228 -0
- package/lib/examples/AgentToolApprovalsExample.js +30 -493
- package/lib/examples/AgentTriggersExample.js +1067 -246
- package/lib/examples/ChatCustomExample.js +11 -24
- package/lib/examples/ChatExample.js +9 -34
- 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} +65 -16
- 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/ErrorView.d.ts +14 -0
- package/lib/examples/components/ErrorView.js +20 -0
- package/lib/examples/components/ExampleWrapper.d.ts +7 -0
- package/lib/examples/components/ExampleWrapper.js +25 -6
- 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 +5 -0
- package/lib/examples/components/index.js +5 -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 +107 -41
- package/lib/examples/index.d.ts +9 -6
- package/lib/examples/index.js +9 -6
- package/lib/examples/main.d.ts +1 -0
- package/lib/examples/main.js +218 -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/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 +118 -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} +39 -2
- package/lib/hooks/{useAgents.js → useAgentRuntimes.js} +125 -15
- 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 +9 -0
- package/lib/protocols/VercelAIAdapter.js +144 -26
- package/lib/shims/json5.d.ts +4 -0
- package/lib/shims/json5.js +8 -0
- package/lib/specs/agents/agents.d.ts +10 -0
- package/lib/specs/agents/agents.js +752 -24
- package/lib/specs/envvars.d.ts +1 -0
- package/lib/specs/envvars.js +11 -0
- package/lib/specs/events.d.ts +1 -0
- package/lib/specs/events.js +1 -0
- package/lib/specs/index.d.ts +1 -0
- package/lib/specs/index.js +1 -0
- package/lib/specs/personas.d.ts +41 -0
- package/lib/specs/personas.js +168 -0
- package/lib/specs/skills.d.ts +2 -1
- package/lib/specs/skills.js +23 -5
- package/lib/specs/tools.js +3 -0
- package/lib/stores/agentRuntimeStore.d.ts +204 -0
- package/lib/stores/agentRuntimeStore.js +636 -0
- 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/agentspecs.d.ts +50 -1
- package/lib/types/chat.d.ts +309 -8
- package/lib/types/context.d.ts +27 -0
- package/lib/types/cost.d.ts +2 -2
- package/lib/types/index.d.ts +2 -0
- package/lib/types/index.js +2 -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/types/tools.d.ts +2 -0
- package/lib/utils/utils.d.ts +9 -5
- package/lib/utils/utils.js +9 -5
- package/package.json +13 -9
- package/scripts/codegen/__pycache__/generate_agents.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 +106 -7
- package/scripts/codegen/generate_events.py +47 -17
- package/scripts/codegen/generate_personas.py +319 -0
- package/scripts/codegen/generate_skills.py +9 -9
- package/scripts/codegen/generate_tools.py +20 -0
- package/scripts/sync-jupyter.sh +26 -7
- package/style/primer-primitives.css +1 -6
- package/lib/api/tool-approvals.d.ts +0 -62
- package/lib/api/tool-approvals.js +0 -145
- 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/scripts/codegen/__pycache__/generate_envvars.cpython-313.pyc +0 -0
- package/scripts/codegen/__pycache__/generate_evals.cpython-313.pyc +0 -0
- package/scripts/codegen/__pycache__/generate_guardrails.cpython-313.pyc +0 -0
- package/scripts/codegen/__pycache__/generate_mcp_servers.cpython-313.pyc +0 -0
- package/scripts/codegen/__pycache__/generate_memory.cpython-313.pyc +0 -0
- package/scripts/codegen/__pycache__/generate_models.cpython-313.pyc +0 -0
- package/scripts/codegen/__pycache__/generate_notifications.cpython-313.pyc +0 -0
- package/scripts/codegen/__pycache__/generate_outputs.cpython-313.pyc +0 -0
- package/scripts/codegen/__pycache__/generate_skills.cpython-313.pyc +0 -0
- package/scripts/codegen/__pycache__/generate_teams.cpython-313.pyc +0 -0
- package/scripts/codegen/__pycache__/generate_tools.cpython-313.pyc +0 -0
- package/scripts/codegen/__pycache__/generate_triggers.cpython-313.pyc +0 -0
- /package/lib/examples/{AgentspecExample.d.ts → AgentSpecsExample.d.ts} +0 -0
- /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
|
@@ -1,45 +1,100 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
/*
|
|
3
3
|
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
4
4
|
* Distributed under the terms of the Modified BSD License.
|
|
5
5
|
*/
|
|
6
6
|
/// <reference types="vite/client" />
|
|
7
|
-
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
7
|
+
import { useCallback, useEffect, useMemo, useRef, useState, } from 'react';
|
|
8
8
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
9
9
|
import { Box } from '@datalayer/primer-addons';
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
10
|
+
import { AuthRequiredView, ErrorView } from './components';
|
|
11
|
+
import { Button, Dialog, Heading, Label, Spinner, Text, Token as PrimerToken, } from '@primer/react';
|
|
12
|
+
import { BriefcaseIcon, FileIcon } from '@primer/octicons-react';
|
|
12
13
|
import { useSimpleAuthStore } from '@datalayer/core/lib/views/otel';
|
|
13
|
-
import { SignInSimple } from '@datalayer/core/lib/views/iam';
|
|
14
|
-
import { UserBadge } from '@datalayer/core/lib/views/profile';
|
|
15
14
|
import { ThemedProvider } from './utils/themedProvider';
|
|
15
|
+
import { uniqueAgentId } from './utils/agentId';
|
|
16
16
|
import { Chat } from '../chat';
|
|
17
|
+
import { useSkills, useSkillActions } from '../hooks';
|
|
17
18
|
const queryClient = new QueryClient();
|
|
18
19
|
const AGENT_NAME = 'skills-demo-agent';
|
|
19
20
|
const AGENT_SPEC_ID = 'demo-full';
|
|
20
21
|
const DEFAULT_LOCAL_BASE_URL = import.meta.env.VITE_BASE_URL || 'http://localhost:8765';
|
|
21
|
-
const SkillCard = ({ skill }) =>
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
22
|
+
const SkillCard = ({ skill, onToggle, onToggleApproval }) => {
|
|
23
|
+
const [showDefinition, setShowDefinition] = useState(false);
|
|
24
|
+
const sourceVariant = skill.source_variant ?? 'unknown';
|
|
25
|
+
const sourceLabel = sourceVariant === 'path'
|
|
26
|
+
? 'file-based'
|
|
27
|
+
: sourceVariant === 'package'
|
|
28
|
+
? 'package-based'
|
|
29
|
+
: sourceVariant === 'module'
|
|
30
|
+
? 'module-based'
|
|
31
|
+
: 'unknown';
|
|
32
|
+
const sourceDetail = sourceVariant === 'package'
|
|
33
|
+
? [skill.package, skill.method].filter(Boolean).join('#')
|
|
34
|
+
: sourceVariant === 'module'
|
|
35
|
+
? skill.module
|
|
36
|
+
: sourceVariant === 'path'
|
|
37
|
+
? skill.path
|
|
38
|
+
: undefined;
|
|
39
|
+
return (_jsxs(_Fragment, { children: [_jsxs(Box, { sx: {
|
|
40
|
+
border: '1px solid',
|
|
41
|
+
borderColor: 'border.default',
|
|
42
|
+
borderRadius: 2,
|
|
43
|
+
p: 2,
|
|
44
|
+
mb: 2,
|
|
45
|
+
bg: 'canvas.default',
|
|
46
|
+
}, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1, mb: 1 }, children: [_jsx(Text, { sx: { fontWeight: 600, fontSize: 1 }, children: skill.name }), skill.status && (_jsx(Label, { size: "small", variant: skill.status === 'loaded'
|
|
47
|
+
? 'success'
|
|
48
|
+
: skill.status === 'enabled'
|
|
49
|
+
? 'attention'
|
|
50
|
+
: 'secondary', children: skill.status })), skill.approved && (_jsx(Label, { size: "small", variant: "success", children: "approved" })), skill.status === 'loaded' && skill.skill_definition && (_jsx(Button, { size: "small", variant: "invisible", onClick: () => setShowDefinition(true), leadingVisual: FileIcon, sx: { fontSize: 0, p: 0, color: 'fg.muted' }, "aria-label": "View SKILL.md", children: "SKILL.md" })), _jsxs(Box, { sx: { ml: 'auto', display: 'flex', alignItems: 'center', gap: 1 }, children: [_jsx(Button, { size: "small", variant: "invisible", onClick: () => onToggleApproval(skill.id), sx: { fontSize: 0 }, children: skill.approved ? 'Unapprove' : 'Approve' }), _jsx(Button, { size: "small", variant: "invisible", onClick: () => onToggle(skill.id), sx: { fontSize: 0 }, children: skill.status === 'available' ? 'Enable' : 'Disable' })] })] }), skill.description && (_jsx(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted', mb: 1, mt: 0 }, children: skill.description })), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1, mb: 1 }, children: [_jsx(Label, { size: "small", variant: "secondary", children: sourceLabel }), sourceDetail && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: sourceDetail }))] }), skill.tags && skill.tags.length > 0 && (_jsx(Box, { sx: { mt: 1, display: 'flex', gap: 1, flexWrap: 'wrap' }, children: skill.tags.map(tag => (_jsx(PrimerToken, { text: tag, size: "small" }, tag))) }))] }), showDefinition && skill.skill_definition && (_jsx(Dialog, { title: `${skill.name} — SKILL.md`, onClose: () => setShowDefinition(false), width: "xlarge", children: _jsx(Box, { sx: { p: 3, maxHeight: '70vh', overflow: 'auto' }, children: _jsx(Box, { as: "pre", sx: {
|
|
51
|
+
fontFamily: 'mono',
|
|
52
|
+
fontSize: 0,
|
|
53
|
+
whiteSpace: 'pre-wrap',
|
|
54
|
+
wordBreak: 'break-word',
|
|
55
|
+
m: 0,
|
|
56
|
+
p: 3,
|
|
57
|
+
bg: 'canvas.inset',
|
|
58
|
+
borderRadius: 2,
|
|
59
|
+
border: '1px solid',
|
|
60
|
+
borderColor: 'border.muted',
|
|
61
|
+
}, children: skill.skill_definition }) }) }))] }));
|
|
62
|
+
};
|
|
33
63
|
const AgentSkillsInner = ({ onLogout }) => {
|
|
34
64
|
const { token } = useSimpleAuthStore();
|
|
65
|
+
const agentName = useRef(uniqueAgentId(AGENT_NAME)).current;
|
|
35
66
|
const [runtimeStatus, setRuntimeStatus] = useState('launching');
|
|
36
67
|
const [isReady, setIsReady] = useState(false);
|
|
37
68
|
const [hookError, setHookError] = useState(null);
|
|
38
|
-
const [agentId, setAgentId] = useState(
|
|
69
|
+
const [agentId, setAgentId] = useState(agentName);
|
|
39
70
|
const [isReconnectedAgent, setIsReconnectedAgent] = useState(false);
|
|
40
|
-
const [skills, setSkills] = useState([]);
|
|
41
71
|
const agentBaseUrl = DEFAULT_LOCAL_BASE_URL;
|
|
42
72
|
const chatAuthToken = token === null ? undefined : token;
|
|
73
|
+
// WS-sourced skills (reads from codemodeStatus pushed via monitoring WS)
|
|
74
|
+
const skillsQuery = useSkills(isReady);
|
|
75
|
+
const skills = useMemo(() => skillsQuery.data?.skills ?? [], [skillsQuery.data]);
|
|
76
|
+
const { enableSkill, disableSkill, approveSkill, unapproveSkill } = useSkillActions(agentId);
|
|
77
|
+
const toggleSkill = useCallback((skillId) => {
|
|
78
|
+
const skill = skills.find(s => s.id === skillId);
|
|
79
|
+
if (skill?.status === 'available') {
|
|
80
|
+
enableSkill(skillId);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
disableSkill(skillId);
|
|
84
|
+
}
|
|
85
|
+
}, [skills, enableSkill, disableSkill]);
|
|
86
|
+
const toggleSkillApproval = useCallback((skillId) => {
|
|
87
|
+
const skill = skills.find(s => s.id === skillId);
|
|
88
|
+
if (skill?.approved) {
|
|
89
|
+
unapproveSkill(skillId);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
approveSkill(skillId);
|
|
93
|
+
}
|
|
94
|
+
}, [skills, approveSkill, unapproveSkill]);
|
|
95
|
+
const fileBasedSkills = skills.filter(s => s.source_variant === 'path');
|
|
96
|
+
const packageBasedSkills = skills.filter(s => s.source_variant === 'package');
|
|
97
|
+
const moduleBasedSkills = skills.filter(s => s.source_variant === 'module');
|
|
43
98
|
const authFetch = useCallback((url, opts = {}) => fetch(url, {
|
|
44
99
|
...opts,
|
|
45
100
|
headers: {
|
|
@@ -57,12 +112,12 @@ const AgentSkillsInner = ({ onLogout }) => {
|
|
|
57
112
|
setIsReconnectedAgent(false);
|
|
58
113
|
try {
|
|
59
114
|
// Create local agent runtime using the demo-full spec.
|
|
60
|
-
// The spec contains
|
|
115
|
+
// The spec contains module-based, package-based and file-based skills.
|
|
61
116
|
const response = await authFetch(`${agentBaseUrl}/api/v1/agents`, {
|
|
62
117
|
method: 'POST',
|
|
63
118
|
body: JSON.stringify({
|
|
64
|
-
name:
|
|
65
|
-
description: 'Agent with skills demo -
|
|
119
|
+
name: agentName,
|
|
120
|
+
description: 'Agent with skills demo - module, package and file based skills',
|
|
66
121
|
agent_library: 'pydantic-ai',
|
|
67
122
|
transport: 'vercel-ai',
|
|
68
123
|
agent_spec_id: AGENT_SPEC_ID,
|
|
@@ -70,11 +125,11 @@ const AgentSkillsInner = ({ onLogout }) => {
|
|
|
70
125
|
tools: [],
|
|
71
126
|
}),
|
|
72
127
|
});
|
|
73
|
-
let resolvedAgentId =
|
|
128
|
+
let resolvedAgentId = agentName;
|
|
74
129
|
let isAlreadyRunning = false;
|
|
75
130
|
if (response.ok) {
|
|
76
131
|
const data = await response.json();
|
|
77
|
-
resolvedAgentId = data?.id ||
|
|
132
|
+
resolvedAgentId = data?.id || agentName;
|
|
78
133
|
}
|
|
79
134
|
else {
|
|
80
135
|
const contentType = response.headers.get('content-type') || '';
|
|
@@ -114,68 +169,7 @@ const AgentSkillsInner = ({ onLogout }) => {
|
|
|
114
169
|
return () => {
|
|
115
170
|
isCancelled = true;
|
|
116
171
|
};
|
|
117
|
-
}, [agentBaseUrl, authFetch]);
|
|
118
|
-
// Fetch skill information from the agent's spec endpoint
|
|
119
|
-
useEffect(() => {
|
|
120
|
-
if (!isReady)
|
|
121
|
-
return;
|
|
122
|
-
const fetchSkills = async () => {
|
|
123
|
-
try {
|
|
124
|
-
const res = await authFetch(`${agentBaseUrl}/api/v1/agents/${agentId}/spec`);
|
|
125
|
-
if (!res.ok)
|
|
126
|
-
return;
|
|
127
|
-
const spec = await res.json();
|
|
128
|
-
const skillNames = spec?.skills ?? [];
|
|
129
|
-
// For each skill name, build a SkillInfo from the catalog when possible.
|
|
130
|
-
const { getSkillSpec } = await import('../specs/skills');
|
|
131
|
-
const infos = skillNames.map((name) => {
|
|
132
|
-
const baseName = name.includes(':') ? name.split(':')[0] : name;
|
|
133
|
-
const catalogSpec = getSkillSpec(baseName);
|
|
134
|
-
if (catalogSpec?.path) {
|
|
135
|
-
// Variant 3: path-based skill
|
|
136
|
-
return {
|
|
137
|
-
name: catalogSpec.name,
|
|
138
|
-
description: catalogSpec.description || `Skill: ${baseName}`,
|
|
139
|
-
variant: 'path',
|
|
140
|
-
path: catalogSpec.path,
|
|
141
|
-
tags: catalogSpec.tags ? [...catalogSpec.tags] : [],
|
|
142
|
-
emoji: catalogSpec.emoji,
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
if (catalogSpec?.package && catalogSpec?.method) {
|
|
146
|
-
// Variant 2: package-based skill
|
|
147
|
-
return {
|
|
148
|
-
name: catalogSpec.name,
|
|
149
|
-
description: catalogSpec.description || `Skill: ${baseName}`,
|
|
150
|
-
variant: 'package',
|
|
151
|
-
package: catalogSpec.package,
|
|
152
|
-
method: catalogSpec.method,
|
|
153
|
-
license: catalogSpec.license,
|
|
154
|
-
compatibility: catalogSpec.compatibility,
|
|
155
|
-
allowedTools: catalogSpec.allowedTools,
|
|
156
|
-
skillMetadata: catalogSpec.skillMetadata,
|
|
157
|
-
tags: catalogSpec.tags ? [...catalogSpec.tags] : [],
|
|
158
|
-
emoji: catalogSpec.emoji,
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
// Variant 1: name-based (module discovery)
|
|
162
|
-
return {
|
|
163
|
-
name: catalogSpec?.name ?? baseName,
|
|
164
|
-
description: catalogSpec?.description ?? `Skill: ${baseName}`,
|
|
165
|
-
variant: 'module',
|
|
166
|
-
module: catalogSpec?.module ?? `agent_skills.skills.${baseName}`,
|
|
167
|
-
tags: catalogSpec?.tags ? [...catalogSpec.tags] : [],
|
|
168
|
-
emoji: catalogSpec?.emoji,
|
|
169
|
-
};
|
|
170
|
-
});
|
|
171
|
-
setSkills(infos);
|
|
172
|
-
}
|
|
173
|
-
catch {
|
|
174
|
-
// Non-fatal: skill display is informational
|
|
175
|
-
}
|
|
176
|
-
};
|
|
177
|
-
void fetchSkills();
|
|
178
|
-
}, [isReady, agentId, agentBaseUrl, authFetch]);
|
|
172
|
+
}, [agentBaseUrl, agentName, authFetch]);
|
|
179
173
|
if (!isReady && runtimeStatus !== 'error') {
|
|
180
174
|
return (_jsxs(Box, { sx: {
|
|
181
175
|
display: 'flex',
|
|
@@ -187,14 +181,7 @@ const AgentSkillsInner = ({ onLogout }) => {
|
|
|
187
181
|
}, children: [_jsx(Spinner, { size: "large" }), _jsx(Text, { sx: { color: 'fg.muted' }, children: "Launching skills demo agent..." })] }));
|
|
188
182
|
}
|
|
189
183
|
if (runtimeStatus === 'error' || hookError) {
|
|
190
|
-
return (
|
|
191
|
-
display: 'flex',
|
|
192
|
-
flexDirection: 'column',
|
|
193
|
-
alignItems: 'center',
|
|
194
|
-
justifyContent: 'center',
|
|
195
|
-
height: '100vh',
|
|
196
|
-
gap: 3,
|
|
197
|
-
}, children: [_jsx(AlertIcon, { size: 48 }), _jsx(Text, { sx: { color: 'danger.fg' }, children: hookError || 'Agent failed to start' })] }));
|
|
184
|
+
return _jsx(ErrorView, { error: hookError, onLogout: onLogout });
|
|
198
185
|
}
|
|
199
186
|
return (_jsxs(Box, { sx: {
|
|
200
187
|
height: 'calc(100vh - 60px)',
|
|
@@ -205,11 +192,15 @@ const AgentSkillsInner = ({ onLogout }) => {
|
|
|
205
192
|
py: 1,
|
|
206
193
|
borderBottom: '1px solid',
|
|
207
194
|
borderColor: 'border.default',
|
|
208
|
-
}, children: _jsx(Text, { sx: { color: 'fg.muted', fontSize: 0 }, children: "Agent already running - reconnected." }) })), _jsxs(Box, { sx: { flex: 1, minHeight: 0, display: 'flex' }, children: [_jsx(Box, { sx: { flex: 1, minWidth: 0 }, children: _jsx(Chat, { protocol: "vercel-ai", baseUrl: agentBaseUrl, agentId: agentId, authToken: chatAuthToken, title: `Skills Demo Agent`, placeholder: "Ask the agent to use its skills...", showHeader: true, showNewChatButton: true, showClearButton: false, showTokenUsage: true, autoFocus: true, height: "100%", runtimeId: agentId, historyEndpoint: `${agentBaseUrl}/api/v1/history`, headerActions:
|
|
195
|
+
}, children: _jsx(Text, { sx: { color: 'fg.muted', fontSize: 0 }, children: "Agent already running - reconnected." }) })), _jsxs(Box, { sx: { flex: 1, minHeight: 0, display: 'flex' }, children: [_jsx(Box, { sx: { flex: 1, minWidth: 0 }, children: _jsx(Chat, { protocol: "vercel-ai", baseUrl: agentBaseUrl, agentId: agentId, authToken: chatAuthToken, title: `Skills Demo Agent`, placeholder: "Ask the agent to use its skills...", showHeader: true, showNewChatButton: true, showClearButton: false, showTokenUsage: true, showSkillsMenu: true, autoFocus: true, height: "100%", runtimeId: agentId, historyEndpoint: `${agentBaseUrl}/api/v1/history`, headerActions: _jsx(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: _jsxs(Text, { sx: { color: 'fg.muted', fontSize: 1 }, children: ["Skills: ", skills.length] }) }), suggestions: [
|
|
209
196
|
{
|
|
210
197
|
title: 'List available skills',
|
|
211
198
|
message: 'List all your available skills and what they can do.',
|
|
212
199
|
},
|
|
200
|
+
{
|
|
201
|
+
title: '👤 Who am I',
|
|
202
|
+
message: 'Use the datalayer-whoami skill to tell me who I am, including my user identity and available context.',
|
|
203
|
+
},
|
|
213
204
|
{
|
|
214
205
|
title: '🌐 Crawl a webpage',
|
|
215
206
|
message: 'Use the crawl skill to fetch the content of https://datalayer.ai and summarize it.',
|
|
@@ -220,7 +211,7 @@ const AgentSkillsInner = ({ onLogout }) => {
|
|
|
220
211
|
},
|
|
221
212
|
{
|
|
222
213
|
title: '🐙 GitHub repos',
|
|
223
|
-
message: 'Use the GitHub skill to
|
|
214
|
+
message: 'Use the GitHub skill to show two sections: first, the top 3 recently updated public repositories from the datalayer organization; second, my top 3 recently updated private repositories. Keep the output clear and concise.',
|
|
224
215
|
},
|
|
225
216
|
{
|
|
226
217
|
title: '📄 Read a PDF',
|
|
@@ -247,14 +238,14 @@ const AgentSkillsInner = ({ onLogout }) => {
|
|
|
247
238
|
p: 2,
|
|
248
239
|
borderBottom: '1px solid',
|
|
249
240
|
borderColor: 'border.default',
|
|
250
|
-
}, children: [_jsx(Heading, { as: "h4", sx: { fontSize: 1, mb: 1 }, children: _jsxs(Box, { sx: { display: 'inline-flex', alignItems: 'center', gap: 1 }, children: [_jsx(BriefcaseIcon, { size: 16 }), "Agent Skills"] }) }), _jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: ["
|
|
241
|
+
}, children: [_jsx(Heading, { as: "h4", sx: { fontSize: 1, mb: 1 }, children: _jsxs(Box, { sx: { display: 'inline-flex', alignItems: 'center', gap: 1 }, children: [_jsx(BriefcaseIcon, { size: 16 }), "Agent Skills"] }) }), _jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: [skills.length, " skill", skills.length !== 1 ? 's' : '', " \u00B7", ' ', skills.filter(s => s.status === 'loaded').length, " loaded \u00B7", ' ', skills.filter(s => s.approved).length, " approved"] }), _jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted', mt: 1, display: 'block' }, children: [fileBasedSkills.length, " file-based \u00B7", ' ', packageBasedSkills.length, " package-based \u00B7", ' ', moduleBasedSkills.length, " module-based"] })] }), _jsxs(Box, { sx: { p: 2, overflow: 'auto', flex: 1 }, children: [skills.length === 0 ? (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Waiting for skills snapshot..." })) : (skills.map(skill => (_jsx(SkillCard, { skill: skill, onToggle: toggleSkill, onToggleApproval: toggleSkillApproval }, skill.id)))), _jsxs(Box, { sx: {
|
|
251
242
|
mt: 3,
|
|
252
243
|
p: 2,
|
|
253
244
|
borderRadius: 2,
|
|
254
245
|
bg: 'canvas.inset',
|
|
255
246
|
border: '1px solid',
|
|
256
247
|
borderColor: 'border.muted',
|
|
257
|
-
}, children: [_jsx(Heading, { as: "h5", sx: { fontSize: 0, mb: 1 }, children: "Skill
|
|
248
|
+
}, children: [_jsx(Heading, { as: "h5", sx: { fontSize: 0, mb: 1 }, children: "Skill Statuses" }), _jsxs(Box, { sx: { fontSize: 0, color: 'fg.muted' }, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1, mb: 1 }, children: [_jsx(Label, { size: "small", variant: "secondary", children: "available" }), _jsx(Text, { children: "In catalog, not yet enabled" })] }), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1, mb: 1 }, children: [_jsx(Label, { size: "small", variant: "attention", children: "enabled" }), _jsx(Text, { children: "Enabled, loading pending" })] }), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1 }, children: [_jsx(Label, { size: "small", variant: "success", children: "loaded" }), _jsx(Text, { children: "SKILL.md loaded, in system prompt" })] })] })] })] })] })] })] }));
|
|
258
249
|
};
|
|
259
250
|
const syncTokenToIamStore = (token) => {
|
|
260
251
|
import('@datalayer/core/lib/state').then(({ iamStore }) => {
|
|
@@ -262,7 +253,7 @@ const syncTokenToIamStore = (token) => {
|
|
|
262
253
|
});
|
|
263
254
|
};
|
|
264
255
|
const AgentSkillsExample = () => {
|
|
265
|
-
const { token,
|
|
256
|
+
const { token, clearAuth } = useSimpleAuthStore();
|
|
266
257
|
const hasSynced = useRef(false);
|
|
267
258
|
useEffect(() => {
|
|
268
259
|
if (token && !hasSynced.current) {
|
|
@@ -270,11 +261,6 @@ const AgentSkillsExample = () => {
|
|
|
270
261
|
syncTokenToIamStore(token);
|
|
271
262
|
}
|
|
272
263
|
}, [token]);
|
|
273
|
-
const handleSignIn = useCallback((newToken, handle) => {
|
|
274
|
-
setAuth(newToken, handle);
|
|
275
|
-
hasSynced.current = true;
|
|
276
|
-
syncTokenToIamStore(newToken);
|
|
277
|
-
}, [setAuth]);
|
|
278
264
|
const handleLogout = useCallback(() => {
|
|
279
265
|
clearAuth();
|
|
280
266
|
hasSynced.current = false;
|
|
@@ -283,7 +269,7 @@ const AgentSkillsExample = () => {
|
|
|
283
269
|
});
|
|
284
270
|
}, [clearAuth]);
|
|
285
271
|
if (!token) {
|
|
286
|
-
return (_jsx(ThemedProvider, { children: _jsx(
|
|
272
|
+
return (_jsx(ThemedProvider, { children: _jsx(AuthRequiredView, {}) }));
|
|
287
273
|
}
|
|
288
274
|
return (_jsx(QueryClientProvider, { client: queryClient, children: _jsx(ThemedProvider, { children: _jsx(AgentSkillsInner, { onLogout: handleLogout }) }) }));
|
|
289
275
|
};
|
|
@@ -9,16 +9,16 @@ import { PageLayout, IconButton } from '@primer/react';
|
|
|
9
9
|
import { SidebarCollapseIcon, SidebarExpandIcon } from '@primer/octicons-react';
|
|
10
10
|
import { AiAgentIcon } from '@datalayer/icons-react';
|
|
11
11
|
import { Blankslate } from '@primer/react/experimental';
|
|
12
|
-
import { QueryClient, QueryClientProvider
|
|
12
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
13
13
|
import { Box } from '@datalayer/primer-addons';
|
|
14
|
-
import {
|
|
14
|
+
import { AgentConfiguration } from '../config';
|
|
15
15
|
import { Chat } from '../chat';
|
|
16
16
|
import { DEFAULT_MODEL } from '../specs';
|
|
17
|
-
import { useAgentsStore } from './utils/examplesStore';
|
|
18
17
|
import { useIdentity } from '../identity';
|
|
18
|
+
import { useAgentsStore } from './utils/examplesStore';
|
|
19
|
+
import { ThemedProvider } from './utils/themedProvider';
|
|
19
20
|
import { isSpecSelection, getSpecId } from '../config/AgentConfiguration';
|
|
20
21
|
import { MockFileBrowser, MainContent, Header } from './components';
|
|
21
|
-
import { AgentConfiguration } from '../config';
|
|
22
22
|
import { useChatStore } from '../stores';
|
|
23
23
|
// Create a query client for React Query
|
|
24
24
|
const queryClient = new QueryClient({
|
|
@@ -35,19 +35,9 @@ const queryClient = new QueryClient({
|
|
|
35
35
|
* Hook to fetch codemode status and compute Jupyter error banner.
|
|
36
36
|
* Must be used inside QueryClientProvider.
|
|
37
37
|
*/
|
|
38
|
-
function useJupyterSandboxStatus(baseUrl, isConfigured, enableCodemode, useJupyterSandbox) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
queryFn: async () => {
|
|
42
|
-
const response = await fetch(`${baseUrl}/api/v1/configure/codemode-status`);
|
|
43
|
-
if (!response.ok) {
|
|
44
|
-
throw new Error('Failed to fetch codemode status');
|
|
45
|
-
}
|
|
46
|
-
return response.json();
|
|
47
|
-
},
|
|
48
|
-
enabled: isConfigured && enableCodemode && useJupyterSandbox,
|
|
49
|
-
refetchInterval: 10000, // Refresh every 10 seconds
|
|
50
|
-
});
|
|
38
|
+
function useJupyterSandboxStatus(baseUrl, isConfigured, enableCodemode, useJupyterSandbox, codemodeStatusData) {
|
|
39
|
+
// REST polling removed — data comes exclusively via WS `agent.snapshot`.
|
|
40
|
+
const codemodeStatus = codemodeStatusData;
|
|
51
41
|
return React.useMemo(() => {
|
|
52
42
|
if (!isConfigured || !enableCodemode || !useJupyterSandbox) {
|
|
53
43
|
return undefined;
|
|
@@ -57,7 +47,7 @@ function useJupyterSandboxStatus(baseUrl, isConfigured, enableCodemode, useJupyt
|
|
|
57
47
|
return undefined;
|
|
58
48
|
}
|
|
59
49
|
// Check if Jupyter variant is selected but not connected
|
|
60
|
-
if (sandbox.variant === '
|
|
50
|
+
if (sandbox.variant === 'jupyter' && !sandbox.jupyter_connected) {
|
|
61
51
|
return {
|
|
62
52
|
message: sandbox.jupyter_error
|
|
63
53
|
? `Jupyter Sandbox Error: ${sandbox.jupyter_error}`
|
|
@@ -386,7 +376,7 @@ githubClientId, kaggleToken, }) => {
|
|
|
386
376
|
setAllowDirectToolCalls(false);
|
|
387
377
|
setEnableToolReranker(false);
|
|
388
378
|
setUseJupyterSandbox(false);
|
|
389
|
-
setTransport('
|
|
379
|
+
setTransport('vercel-ai');
|
|
390
380
|
}
|
|
391
381
|
else if (isSpecSelection(agentId)) {
|
|
392
382
|
// Populate form fields from the selected library spec
|
|
@@ -425,8 +415,7 @@ githubClientId, kaggleToken, }) => {
|
|
|
425
415
|
codemodeConfig?.allow_direct_tool_calls));
|
|
426
416
|
setEnableToolReranker(Boolean(codemodeConfig?.enableToolReranker ??
|
|
427
417
|
codemodeConfig?.enable_tool_reranker));
|
|
428
|
-
setUseJupyterSandbox(spec.sandboxVariant === '
|
|
429
|
-
spec.sandboxVariant === 'jupyter');
|
|
418
|
+
setUseJupyterSandbox(spec.sandboxVariant === 'jupyter');
|
|
430
419
|
}
|
|
431
420
|
else {
|
|
432
421
|
setSelectedLibrarySpec(null);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgentSubagentsExample
|
|
3
|
+
*
|
|
4
|
+
* Demonstrates multi-agent delegation using subagents-pydantic-ai.
|
|
5
|
+
* The parent agent orchestrates a researcher and a writer subagent,
|
|
6
|
+
* delegating tasks and combining results for the user.
|
|
7
|
+
*
|
|
8
|
+
* - Creates a local agent from the 'demo-subagents' spec
|
|
9
|
+
* - Shows a Chat component for interacting with the orchestrator
|
|
10
|
+
* - Sidebar displays subagent info and active task status
|
|
11
|
+
*/
|
|
12
|
+
import React from 'react';
|
|
13
|
+
declare const AgentSubagentsExample: React.FC;
|
|
14
|
+
export default AgentSubagentsExample;
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
4
|
+
* Distributed under the terms of the Modified BSD License.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* AgentSubagentsExample
|
|
8
|
+
*
|
|
9
|
+
* Demonstrates multi-agent delegation using subagents-pydantic-ai.
|
|
10
|
+
* The parent agent orchestrates a researcher and a writer subagent,
|
|
11
|
+
* delegating tasks and combining results for the user.
|
|
12
|
+
*
|
|
13
|
+
* - Creates a local agent from the 'demo-subagents' spec
|
|
14
|
+
* - Shows a Chat component for interacting with the orchestrator
|
|
15
|
+
* - Sidebar displays subagent info and active task status
|
|
16
|
+
*/
|
|
17
|
+
/// <reference types="vite/client" />
|
|
18
|
+
import { useEffect, useState, useCallback, useRef } from 'react';
|
|
19
|
+
import { Text, Spinner, Heading, Label, Timeline } from '@primer/react';
|
|
20
|
+
import { PeopleIcon, PersonIcon, CheckCircleFillIcon, ClockIcon, XCircleFillIcon, } from '@primer/octicons-react';
|
|
21
|
+
import { Box } from '@datalayer/primer-addons';
|
|
22
|
+
import { AuthRequiredView, ErrorView } from './components';
|
|
23
|
+
import { ThemedProvider } from './utils/themedProvider';
|
|
24
|
+
import { uniqueAgentId } from './utils/agentId';
|
|
25
|
+
import { useSimpleAuthStore } from '@datalayer/core/lib/views/otel';
|
|
26
|
+
import { Chat } from '../chat';
|
|
27
|
+
const AGENT_NAME = 'subagents-demo-agent';
|
|
28
|
+
const AGENT_SPEC_ID = 'demo-subagents';
|
|
29
|
+
const DEFAULT_LOCAL_BASE_URL = import.meta.env.VITE_BASE_URL || 'http://localhost:8765';
|
|
30
|
+
const SUBAGENTS = [
|
|
31
|
+
{
|
|
32
|
+
name: 'researcher',
|
|
33
|
+
description: 'Researches topics, gathers facts, and provides detailed analysis',
|
|
34
|
+
preferredMode: 'sync',
|
|
35
|
+
typicalComplexity: 'moderate',
|
|
36
|
+
canAskQuestions: true,
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: 'writer',
|
|
40
|
+
description: 'Writes clear, structured content based on research or instructions',
|
|
41
|
+
preferredMode: 'sync',
|
|
42
|
+
typicalComplexity: 'moderate',
|
|
43
|
+
canAskQuestions: false,
|
|
44
|
+
},
|
|
45
|
+
];
|
|
46
|
+
const AgentSubagentsInner = ({ onLogout, }) => {
|
|
47
|
+
const { token } = useSimpleAuthStore();
|
|
48
|
+
const agentName = useRef(uniqueAgentId(AGENT_NAME)).current;
|
|
49
|
+
const [runtimeStatus, setRuntimeStatus] = useState('launching');
|
|
50
|
+
const [isReady, setIsReady] = useState(false);
|
|
51
|
+
const [hookError, setHookError] = useState(null);
|
|
52
|
+
const [agentId, setAgentId] = useState(agentName);
|
|
53
|
+
const [isReconnectedAgent, setIsReconnectedAgent] = useState(false);
|
|
54
|
+
const agentBaseUrl = DEFAULT_LOCAL_BASE_URL;
|
|
55
|
+
const chatAuthToken = token === null ? undefined : token;
|
|
56
|
+
const authFetch = useCallback((url, opts = {}) => fetch(url, {
|
|
57
|
+
...opts,
|
|
58
|
+
headers: {
|
|
59
|
+
'Content-Type': 'application/json',
|
|
60
|
+
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
|
61
|
+
...(opts.headers ?? {}),
|
|
62
|
+
},
|
|
63
|
+
}), [token]);
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
let isCancelled = false;
|
|
66
|
+
const createLocalAgent = async () => {
|
|
67
|
+
setRuntimeStatus('launching');
|
|
68
|
+
setIsReady(false);
|
|
69
|
+
setHookError(null);
|
|
70
|
+
setIsReconnectedAgent(false);
|
|
71
|
+
try {
|
|
72
|
+
const response = await authFetch(`${agentBaseUrl}/api/v1/agents`, {
|
|
73
|
+
method: 'POST',
|
|
74
|
+
body: JSON.stringify({
|
|
75
|
+
name: agentName,
|
|
76
|
+
description: 'Subagents demo – multi-agent delegation with researcher and writer',
|
|
77
|
+
agent_library: 'pydantic-ai',
|
|
78
|
+
transport: 'vercel-ai',
|
|
79
|
+
agent_spec_id: AGENT_SPEC_ID,
|
|
80
|
+
enable_skills: true,
|
|
81
|
+
tools: [],
|
|
82
|
+
}),
|
|
83
|
+
});
|
|
84
|
+
let resolvedAgentId = agentName;
|
|
85
|
+
let isAlreadyRunning = false;
|
|
86
|
+
if (response.ok) {
|
|
87
|
+
const data = await response.json();
|
|
88
|
+
resolvedAgentId = data?.id || agentName;
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
const contentType = response.headers.get('content-type') || '';
|
|
92
|
+
let detail = '';
|
|
93
|
+
if (contentType.includes('application/json')) {
|
|
94
|
+
const data = await response.json().catch(() => null);
|
|
95
|
+
detail =
|
|
96
|
+
(typeof data?.detail === 'string' && data.detail) ||
|
|
97
|
+
(typeof data?.message === 'string' && data.message) ||
|
|
98
|
+
'';
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
detail = await response.text();
|
|
102
|
+
}
|
|
103
|
+
if (response.status === 409 || /already exists/i.test(detail || '')) {
|
|
104
|
+
isAlreadyRunning = true;
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
throw new Error(detail || `Failed to create local agent: ${response.status}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (!isCancelled) {
|
|
111
|
+
setAgentId(resolvedAgentId);
|
|
112
|
+
setIsReconnectedAgent(isAlreadyRunning);
|
|
113
|
+
setIsReady(true);
|
|
114
|
+
setRuntimeStatus('ready');
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
if (!isCancelled) {
|
|
119
|
+
setHookError(error instanceof Error ? error.message : 'Agent failed to start');
|
|
120
|
+
setRuntimeStatus('error');
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
void createLocalAgent();
|
|
125
|
+
return () => {
|
|
126
|
+
isCancelled = true;
|
|
127
|
+
};
|
|
128
|
+
}, [agentBaseUrl, authFetch]);
|
|
129
|
+
if (!isReady && runtimeStatus !== 'error') {
|
|
130
|
+
return (_jsxs(Box, { sx: {
|
|
131
|
+
display: 'flex',
|
|
132
|
+
flexDirection: 'column',
|
|
133
|
+
alignItems: 'center',
|
|
134
|
+
justifyContent: 'center',
|
|
135
|
+
height: '100vh',
|
|
136
|
+
gap: 3,
|
|
137
|
+
}, children: [_jsx(Spinner, { size: "large" }), _jsx(Text, { sx: { color: 'fg.muted' }, children: "Launching subagents demo agent..." })] }));
|
|
138
|
+
}
|
|
139
|
+
if (runtimeStatus === 'error' || hookError) {
|
|
140
|
+
return _jsx(ErrorView, { error: hookError, onLogout: onLogout });
|
|
141
|
+
}
|
|
142
|
+
return (_jsxs(Box, { sx: {
|
|
143
|
+
height: 'calc(100vh - 60px)',
|
|
144
|
+
display: 'flex',
|
|
145
|
+
flexDirection: 'column',
|
|
146
|
+
}, children: [_jsxs(Box, { sx: {
|
|
147
|
+
display: 'flex',
|
|
148
|
+
alignItems: 'center',
|
|
149
|
+
gap: 2,
|
|
150
|
+
px: 3,
|
|
151
|
+
py: 2,
|
|
152
|
+
borderBottom: '1px solid',
|
|
153
|
+
borderColor: 'border.default',
|
|
154
|
+
flexShrink: 0,
|
|
155
|
+
}, children: [_jsx(PeopleIcon, { size: 16 }), _jsx(Heading, { as: "h3", sx: { fontSize: 2, flex: 1 }, children: "Subagents Demo" }), isReconnectedAgent && (_jsx(Label, { variant: "secondary", size: "small", children: "Reconnected" })), _jsxs(Label, { variant: "accent", children: [SUBAGENTS.length, " subagents"] })] }), _jsxs(Box, { sx: { flex: 1, minHeight: 0, display: 'flex' }, children: [_jsx(Box, { sx: { flex: 1, minWidth: 0 }, children: _jsx(Chat, { protocol: "vercel-ai", baseUrl: agentBaseUrl, agentId: agentId, authToken: chatAuthToken, title: "Subagents Orchestrator", placeholder: "Ask me to research a topic, write content, or both...", description: "Multi-agent delegation with researcher & writer", showHeader: true, autoFocus: true, height: "100%", runtimeId: agentId, historyEndpoint: `${agentBaseUrl}/api/v1/history`, suggestions: [
|
|
156
|
+
{
|
|
157
|
+
title: 'Research & write',
|
|
158
|
+
message: 'Research the pros and cons of Python async patterns and write a summary.',
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
title: 'Research only',
|
|
162
|
+
message: 'Find recent advances in LLM fine-tuning and provide a detailed analysis.',
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
title: 'Write only',
|
|
166
|
+
message: 'Write a concise guide on REST API design best practices.',
|
|
167
|
+
},
|
|
168
|
+
], submitOnSuggestionClick: true }) }), _jsxs(Box, { sx: {
|
|
169
|
+
width: 320,
|
|
170
|
+
borderLeft: '1px solid',
|
|
171
|
+
borderColor: 'border.default',
|
|
172
|
+
display: 'flex',
|
|
173
|
+
flexDirection: 'column',
|
|
174
|
+
overflow: 'auto',
|
|
175
|
+
}, children: [_jsxs(Box, { sx: {
|
|
176
|
+
p: 3,
|
|
177
|
+
borderBottom: '1px solid',
|
|
178
|
+
borderColor: 'border.default',
|
|
179
|
+
}, children: [_jsx(Heading, { as: "h4", sx: { fontSize: 1, mb: 2 }, children: "Available Subagents" }), _jsx(Timeline, { children: SUBAGENTS.map(sa => (_jsxs(Timeline.Item, { children: [_jsx(Timeline.Badge, { children: _jsx(PersonIcon, {}) }), _jsxs(Timeline.Body, { children: [_jsx(Box, { sx: { mb: 1 }, children: _jsx(Text, { sx: { fontWeight: 'bold', fontSize: 1 }, children: sa.name }) }), _jsx(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted', mt: 0, mb: 1 }, children: sa.description }), _jsxs(Box, { sx: { display: 'flex', gap: 1, flexWrap: 'wrap' }, children: [_jsx(Label, { size: "small", variant: "secondary", children: sa.preferredMode }), _jsx(Label, { size: "small", variant: "secondary", children: sa.typicalComplexity }), sa.canAskQuestions && (_jsx(Label, { size: "small", variant: "accent", children: "can ask questions" }))] })] })] }, sa.name))) })] }), _jsxs(Box, { sx: {
|
|
180
|
+
p: 3,
|
|
181
|
+
borderBottom: '1px solid',
|
|
182
|
+
borderColor: 'border.default',
|
|
183
|
+
}, children: [_jsx(Heading, { as: "h4", sx: { fontSize: 1, mb: 2 }, children: "Delegation Tools" }), _jsx(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 2 }, children: [
|
|
184
|
+
{
|
|
185
|
+
name: 'task',
|
|
186
|
+
desc: 'Assign a task to a subagent',
|
|
187
|
+
icon: ClockIcon,
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
name: 'check_task',
|
|
191
|
+
desc: 'Check status of a running task',
|
|
192
|
+
icon: CheckCircleFillIcon,
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
name: 'list_active_tasks',
|
|
196
|
+
desc: 'View all active delegated tasks',
|
|
197
|
+
icon: PeopleIcon,
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
name: 'soft_cancel_task',
|
|
201
|
+
desc: 'Gracefully cancel a task',
|
|
202
|
+
icon: XCircleFillIcon,
|
|
203
|
+
},
|
|
204
|
+
].map(tool => (_jsxs(Box, { sx: {
|
|
205
|
+
p: 2,
|
|
206
|
+
border: '1px solid',
|
|
207
|
+
borderColor: 'border.default',
|
|
208
|
+
borderRadius: 2,
|
|
209
|
+
display: 'flex',
|
|
210
|
+
alignItems: 'center',
|
|
211
|
+
gap: 2,
|
|
212
|
+
}, children: [_jsx(tool.icon, { size: 14 }), _jsxs(Box, { children: [_jsx(Text, { sx: {
|
|
213
|
+
fontSize: 1,
|
|
214
|
+
fontWeight: 'bold',
|
|
215
|
+
fontFamily: 'mono',
|
|
216
|
+
}, children: tool.name }), _jsx(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted', mt: 0, mb: 0 }, children: tool.desc })] })] }, tool.name))) })] }), _jsxs(Box, { sx: { p: 3 }, children: [_jsx(Heading, { as: "h4", sx: { fontSize: 1, mb: 2 }, children: "How It Works" }), _jsxs(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted', mb: 2 }, children: ["The orchestrator agent delegates tasks to specialised subagents using the ", _jsx("code", { children: "task" }), " tool. Each subagent runs independently with its own model, instructions, and context."] }), _jsx(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted', mb: 0 }, children: "Subagents can be configured with different execution modes (sync, async, auto), complexity hints, and question-asking capabilities for interactive workflows." })] })] })] })] }));
|
|
217
|
+
};
|
|
218
|
+
const AgentSubagentsExample = () => {
|
|
219
|
+
const { token, clearAuth } = useSimpleAuthStore();
|
|
220
|
+
const handleLogout = useCallback(() => {
|
|
221
|
+
clearAuth();
|
|
222
|
+
}, [clearAuth]);
|
|
223
|
+
if (!token) {
|
|
224
|
+
return (_jsx(ThemedProvider, { children: _jsx(AuthRequiredView, {}) }));
|
|
225
|
+
}
|
|
226
|
+
return (_jsx(ThemedProvider, { children: _jsx(AgentSubagentsInner, { onLogout: handleLogout }) }));
|
|
227
|
+
};
|
|
228
|
+
export default AgentSubagentsExample;
|