@datalayer/agent-runtimes 1.0.4 → 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 +34 -0
- 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 -106
- 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 +1083 -157
- 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 +108 -113
- 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 +0 -18
- package/lib/client/AgentsMixin.js +6 -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.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 +13 -27
- package/lib/examples/AgentCodemodeExample.d.ts +4 -6
- package/lib/examples/AgentCodemodeExample.js +591 -169
- package/lib/examples/AgentEvalsExample.js +12 -16
- package/lib/examples/AgentGuardrailsExample.js +370 -64
- 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 +13 -17
- package/lib/examples/AgentMonitoringExample.js +260 -199
- package/lib/examples/AgentNotificationsExample.js +49 -17
- package/lib/examples/AgentOtelExample.js +2 -3
- package/lib/examples/AgentOutputsExample.d.ts +11 -6
- package/lib/examples/AgentOutputsExample.js +382 -81
- 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 +68 -40
- package/lib/examples/AgentSkillsExample.js +91 -99
- 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 +29 -557
- package/lib/examples/AgentTriggersExample.js +819 -565
- package/lib/examples/ChatCustomExample.js +11 -24
- package/lib/examples/ChatExample.js +7 -24
- 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/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 +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 +107 -41
- package/lib/examples/index.d.ts +9 -6
- package/lib/examples/index.js +9 -6
- package/lib/examples/main.js +217 -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 +7 -0
- package/lib/protocols/VercelAIAdapter.js +59 -7
- package/lib/specs/agents/agents.d.ts +10 -0
- package/lib/specs/agents/agents.js +2139 -262
- package/lib/specs/agents/index.js +3 -1
- package/lib/specs/envvars.d.ts +1 -0
- package/lib/specs/envvars.js +38 -20
- package/lib/specs/evals.js +6 -6
- 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/index.d.ts +1 -0
- package/lib/specs/index.js +1 -0
- 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.js +25 -5
- 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 +2 -1
- package/lib/specs/skills.js +41 -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 +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/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 +102 -6
- package/scripts/codegen/generate_events.py +35 -13
- 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/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/{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,46 +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 { ErrorView } from './components';
|
|
11
|
-
import { Button, Heading, Label, Spinner, Text, Token as PrimerToken, } from '@primer/react';
|
|
12
|
-
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';
|
|
13
13
|
import { useSimpleAuthStore } from '@datalayer/core/lib/views/otel';
|
|
14
|
-
import { SignInSimple } from '@datalayer/core/lib/views/iam';
|
|
15
|
-
import { UserBadge } from '@datalayer/core/lib/views/profile';
|
|
16
14
|
import { ThemedProvider } from './utils/themedProvider';
|
|
15
|
+
import { uniqueAgentId } from './utils/agentId';
|
|
17
16
|
import { Chat } from '../chat';
|
|
17
|
+
import { useSkills, useSkillActions } from '../hooks';
|
|
18
18
|
const queryClient = new QueryClient();
|
|
19
19
|
const AGENT_NAME = 'skills-demo-agent';
|
|
20
20
|
const AGENT_SPEC_ID = 'demo-full';
|
|
21
21
|
const DEFAULT_LOCAL_BASE_URL = import.meta.env.VITE_BASE_URL || 'http://localhost:8765';
|
|
22
|
-
const SkillCard = ({ skill }) =>
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
+
};
|
|
34
63
|
const AgentSkillsInner = ({ onLogout }) => {
|
|
35
64
|
const { token } = useSimpleAuthStore();
|
|
65
|
+
const agentName = useRef(uniqueAgentId(AGENT_NAME)).current;
|
|
36
66
|
const [runtimeStatus, setRuntimeStatus] = useState('launching');
|
|
37
67
|
const [isReady, setIsReady] = useState(false);
|
|
38
68
|
const [hookError, setHookError] = useState(null);
|
|
39
|
-
const [agentId, setAgentId] = useState(
|
|
69
|
+
const [agentId, setAgentId] = useState(agentName);
|
|
40
70
|
const [isReconnectedAgent, setIsReconnectedAgent] = useState(false);
|
|
41
|
-
const [skills, setSkills] = useState([]);
|
|
42
71
|
const agentBaseUrl = DEFAULT_LOCAL_BASE_URL;
|
|
43
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');
|
|
44
98
|
const authFetch = useCallback((url, opts = {}) => fetch(url, {
|
|
45
99
|
...opts,
|
|
46
100
|
headers: {
|
|
@@ -58,12 +112,12 @@ const AgentSkillsInner = ({ onLogout }) => {
|
|
|
58
112
|
setIsReconnectedAgent(false);
|
|
59
113
|
try {
|
|
60
114
|
// Create local agent runtime using the demo-full spec.
|
|
61
|
-
// The spec contains
|
|
115
|
+
// The spec contains module-based, package-based and file-based skills.
|
|
62
116
|
const response = await authFetch(`${agentBaseUrl}/api/v1/agents`, {
|
|
63
117
|
method: 'POST',
|
|
64
118
|
body: JSON.stringify({
|
|
65
|
-
name:
|
|
66
|
-
description: 'Agent with skills demo -
|
|
119
|
+
name: agentName,
|
|
120
|
+
description: 'Agent with skills demo - module, package and file based skills',
|
|
67
121
|
agent_library: 'pydantic-ai',
|
|
68
122
|
transport: 'vercel-ai',
|
|
69
123
|
agent_spec_id: AGENT_SPEC_ID,
|
|
@@ -71,11 +125,11 @@ const AgentSkillsInner = ({ onLogout }) => {
|
|
|
71
125
|
tools: [],
|
|
72
126
|
}),
|
|
73
127
|
});
|
|
74
|
-
let resolvedAgentId =
|
|
128
|
+
let resolvedAgentId = agentName;
|
|
75
129
|
let isAlreadyRunning = false;
|
|
76
130
|
if (response.ok) {
|
|
77
131
|
const data = await response.json();
|
|
78
|
-
resolvedAgentId = data?.id ||
|
|
132
|
+
resolvedAgentId = data?.id || agentName;
|
|
79
133
|
}
|
|
80
134
|
else {
|
|
81
135
|
const contentType = response.headers.get('content-type') || '';
|
|
@@ -115,68 +169,7 @@ const AgentSkillsInner = ({ onLogout }) => {
|
|
|
115
169
|
return () => {
|
|
116
170
|
isCancelled = true;
|
|
117
171
|
};
|
|
118
|
-
}, [agentBaseUrl, authFetch]);
|
|
119
|
-
// Fetch skill information from the agent's spec endpoint
|
|
120
|
-
useEffect(() => {
|
|
121
|
-
if (!isReady)
|
|
122
|
-
return;
|
|
123
|
-
const fetchSkills = async () => {
|
|
124
|
-
try {
|
|
125
|
-
const res = await authFetch(`${agentBaseUrl}/api/v1/agents/${agentId}/spec`);
|
|
126
|
-
if (!res.ok)
|
|
127
|
-
return;
|
|
128
|
-
const spec = await res.json();
|
|
129
|
-
const skillNames = spec?.skills ?? [];
|
|
130
|
-
// For each skill name, build a SkillInfo from the catalog when possible.
|
|
131
|
-
const { getSkillSpec } = await import('../specs/skills');
|
|
132
|
-
const infos = skillNames.map((name) => {
|
|
133
|
-
const baseName = name.includes(':') ? name.split(':')[0] : name;
|
|
134
|
-
const catalogSpec = getSkillSpec(baseName);
|
|
135
|
-
if (catalogSpec?.path) {
|
|
136
|
-
// Variant 3: path-based skill
|
|
137
|
-
return {
|
|
138
|
-
name: catalogSpec.name,
|
|
139
|
-
description: catalogSpec.description || `Skill: ${baseName}`,
|
|
140
|
-
variant: 'path',
|
|
141
|
-
path: catalogSpec.path,
|
|
142
|
-
tags: catalogSpec.tags ? [...catalogSpec.tags] : [],
|
|
143
|
-
emoji: catalogSpec.emoji,
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
if (catalogSpec?.package && catalogSpec?.method) {
|
|
147
|
-
// Variant 2: package-based skill
|
|
148
|
-
return {
|
|
149
|
-
name: catalogSpec.name,
|
|
150
|
-
description: catalogSpec.description || `Skill: ${baseName}`,
|
|
151
|
-
variant: 'package',
|
|
152
|
-
package: catalogSpec.package,
|
|
153
|
-
method: catalogSpec.method,
|
|
154
|
-
license: catalogSpec.license,
|
|
155
|
-
compatibility: catalogSpec.compatibility,
|
|
156
|
-
allowedTools: catalogSpec.allowedTools,
|
|
157
|
-
skillMetadata: catalogSpec.skillMetadata,
|
|
158
|
-
tags: catalogSpec.tags ? [...catalogSpec.tags] : [],
|
|
159
|
-
emoji: catalogSpec.emoji,
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
// Variant 1: name-based (module discovery)
|
|
163
|
-
return {
|
|
164
|
-
name: catalogSpec?.name ?? baseName,
|
|
165
|
-
description: catalogSpec?.description ?? `Skill: ${baseName}`,
|
|
166
|
-
variant: 'module',
|
|
167
|
-
module: catalogSpec?.module ?? `agent_skills.skills.${baseName}`,
|
|
168
|
-
tags: catalogSpec?.tags ? [...catalogSpec.tags] : [],
|
|
169
|
-
emoji: catalogSpec?.emoji,
|
|
170
|
-
};
|
|
171
|
-
});
|
|
172
|
-
setSkills(infos);
|
|
173
|
-
}
|
|
174
|
-
catch {
|
|
175
|
-
// Non-fatal: skill display is informational
|
|
176
|
-
}
|
|
177
|
-
};
|
|
178
|
-
void fetchSkills();
|
|
179
|
-
}, [isReady, agentId, agentBaseUrl, authFetch]);
|
|
172
|
+
}, [agentBaseUrl, agentName, authFetch]);
|
|
180
173
|
if (!isReady && runtimeStatus !== 'error') {
|
|
181
174
|
return (_jsxs(Box, { sx: {
|
|
182
175
|
display: 'flex',
|
|
@@ -199,11 +192,15 @@ const AgentSkillsInner = ({ onLogout }) => {
|
|
|
199
192
|
py: 1,
|
|
200
193
|
borderBottom: '1px solid',
|
|
201
194
|
borderColor: 'border.default',
|
|
202
|
-
}, 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: [
|
|
203
196
|
{
|
|
204
197
|
title: 'List available skills',
|
|
205
198
|
message: 'List all your available skills and what they can do.',
|
|
206
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
|
+
},
|
|
207
204
|
{
|
|
208
205
|
title: '🌐 Crawl a webpage',
|
|
209
206
|
message: 'Use the crawl skill to fetch the content of https://datalayer.ai and summarize it.',
|
|
@@ -214,7 +211,7 @@ const AgentSkillsInner = ({ onLogout }) => {
|
|
|
214
211
|
},
|
|
215
212
|
{
|
|
216
213
|
title: '🐙 GitHub repos',
|
|
217
|
-
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.',
|
|
218
215
|
},
|
|
219
216
|
{
|
|
220
217
|
title: '📄 Read a PDF',
|
|
@@ -241,14 +238,14 @@ const AgentSkillsInner = ({ onLogout }) => {
|
|
|
241
238
|
p: 2,
|
|
242
239
|
borderBottom: '1px solid',
|
|
243
240
|
borderColor: 'border.default',
|
|
244
|
-
}, 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: {
|
|
245
242
|
mt: 3,
|
|
246
243
|
p: 2,
|
|
247
244
|
borderRadius: 2,
|
|
248
245
|
bg: 'canvas.inset',
|
|
249
246
|
border: '1px solid',
|
|
250
247
|
borderColor: 'border.muted',
|
|
251
|
-
}, 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" })] })] })] })] })] })] })] }));
|
|
252
249
|
};
|
|
253
250
|
const syncTokenToIamStore = (token) => {
|
|
254
251
|
import('@datalayer/core/lib/state').then(({ iamStore }) => {
|
|
@@ -256,7 +253,7 @@ const syncTokenToIamStore = (token) => {
|
|
|
256
253
|
});
|
|
257
254
|
};
|
|
258
255
|
const AgentSkillsExample = () => {
|
|
259
|
-
const { token,
|
|
256
|
+
const { token, clearAuth } = useSimpleAuthStore();
|
|
260
257
|
const hasSynced = useRef(false);
|
|
261
258
|
useEffect(() => {
|
|
262
259
|
if (token && !hasSynced.current) {
|
|
@@ -264,11 +261,6 @@ const AgentSkillsExample = () => {
|
|
|
264
261
|
syncTokenToIamStore(token);
|
|
265
262
|
}
|
|
266
263
|
}, [token]);
|
|
267
|
-
const handleSignIn = useCallback((newToken, handle) => {
|
|
268
|
-
setAuth(newToken, handle);
|
|
269
|
-
hasSynced.current = true;
|
|
270
|
-
syncTokenToIamStore(newToken);
|
|
271
|
-
}, [setAuth]);
|
|
272
264
|
const handleLogout = useCallback(() => {
|
|
273
265
|
clearAuth();
|
|
274
266
|
hasSynced.current = false;
|
|
@@ -277,7 +269,7 @@ const AgentSkillsExample = () => {
|
|
|
277
269
|
});
|
|
278
270
|
}, [clearAuth]);
|
|
279
271
|
if (!token) {
|
|
280
|
-
return (_jsx(ThemedProvider, { children: _jsx(
|
|
272
|
+
return (_jsx(ThemedProvider, { children: _jsx(AuthRequiredView, {}) }));
|
|
281
273
|
}
|
|
282
274
|
return (_jsx(QueryClientProvider, { client: queryClient, children: _jsx(ThemedProvider, { children: _jsx(AgentSkillsInner, { onLogout: handleLogout }) }) }));
|
|
283
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;
|