@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
|
@@ -18,28 +18,29 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
18
18
|
import { useEffect, useState, useCallback, useRef } from 'react';
|
|
19
19
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
20
20
|
import { Text, Button, Spinner, TextInput, Heading, Label, Flash, } from '@primer/react';
|
|
21
|
-
import { SearchIcon, DatabaseIcon
|
|
21
|
+
import { SearchIcon, DatabaseIcon } from '@primer/octicons-react';
|
|
22
22
|
import { Box } from '@datalayer/primer-addons';
|
|
23
|
-
import { ErrorView } from './components';
|
|
23
|
+
import { AuthRequiredView, ErrorView } from './components';
|
|
24
24
|
import { ThemedProvider } from './utils/themedProvider';
|
|
25
|
+
import { uniqueAgentId } from './utils/agentId';
|
|
25
26
|
const queryClient = new QueryClient();
|
|
26
27
|
import { useSimpleAuthStore } from '@datalayer/core/lib/views/otel';
|
|
27
|
-
import { SignInSimple } from '@datalayer/core/lib/views/iam';
|
|
28
|
-
import { UserBadge } from '@datalayer/core/lib/views/profile';
|
|
29
28
|
import { Chat } from '../chat';
|
|
30
|
-
import {
|
|
29
|
+
import { useAgentRuntimes } from '../hooks/useAgentRuntimes';
|
|
31
30
|
// ─── Constants ─────────────────────────────────────────────────────────────
|
|
32
31
|
const AGENT_NAME = 'memory-demo-agent';
|
|
33
32
|
const AGENT_SPEC_ID = 'monitor-sales-kpis'; // uses mem0 memory
|
|
34
33
|
// ─── Inner component (rendered after auth) ─────────────────────────────────
|
|
35
34
|
const AgentMemoryInner = ({ onLogout }) => {
|
|
36
35
|
const { token } = useSimpleAuthStore();
|
|
37
|
-
const
|
|
36
|
+
const agentName = useRef(uniqueAgentId(AGENT_NAME)).current;
|
|
37
|
+
const { runtime, status: runtimeStatus, isReady, error: hookError, } = useAgentRuntimes({
|
|
38
38
|
agentSpecId: AGENT_SPEC_ID,
|
|
39
39
|
autoStart: true,
|
|
40
40
|
agentConfig: {
|
|
41
|
-
name:
|
|
42
|
-
|
|
41
|
+
name: agentName,
|
|
42
|
+
model: 'bedrock:us.anthropic.claude-3-5-haiku-20241022-v1:0',
|
|
43
|
+
protocol: 'vercel-ai',
|
|
43
44
|
description: 'Agent with Mem0 persistent memory',
|
|
44
45
|
},
|
|
45
46
|
});
|
|
@@ -133,12 +134,12 @@ const AgentMemoryInner = ({ onLogout }) => {
|
|
|
133
134
|
borderBottom: '1px solid',
|
|
134
135
|
borderColor: 'border.default',
|
|
135
136
|
flexShrink: 0,
|
|
136
|
-
}, children: [_jsx(DatabaseIcon, { size: 16 }), _jsxs(Heading, { as: "h3", sx: { fontSize: 2, flex: 1 }, children: ["Durable Memory \u2014 ", podName] })
|
|
137
|
+
}, children: [_jsx(DatabaseIcon, { size: 16 }), _jsxs(Heading, { as: "h3", sx: { fontSize: 2, flex: 1 }, children: ["Durable Memory \u2014 ", podName] })] }), _jsxs(Box, { sx: { display: 'flex', flex: 1, minHeight: 0 }, children: [_jsx(Box, { sx: {
|
|
137
138
|
flex: 1,
|
|
138
139
|
minWidth: 0,
|
|
139
140
|
borderRight: '1px solid',
|
|
140
141
|
borderColor: 'border.default',
|
|
141
|
-
}, children: _jsx(Chat, { protocol: "
|
|
142
|
+
}, children: _jsx(Chat, { protocol: "vercel-ai", baseUrl: agentBaseUrl, agentId: agentId, title: "Memory Agent", placeholder: "Chat \u2014 the agent remembers you across sessions\u2026", description: "Agent with Mem0 persistent memory", showHeader: true, showTokenUsage: true, autoFocus: true, height: "100%", runtimeId: podName, historyEndpoint: `${agentBaseUrl}/api/v1/history`, suggestions: [
|
|
142
143
|
{
|
|
143
144
|
title: 'Remember',
|
|
144
145
|
message: 'My favourite colour is midnight blue.',
|
|
@@ -200,7 +201,7 @@ const syncTokenToIamStore = (token) => {
|
|
|
200
201
|
};
|
|
201
202
|
// ─── Main component with auth gate ─────────────────────────────────────────
|
|
202
203
|
const AgentMemoryExample = () => {
|
|
203
|
-
const { token,
|
|
204
|
+
const { token, clearAuth } = useSimpleAuthStore();
|
|
204
205
|
const hasSynced = useRef(false);
|
|
205
206
|
useEffect(() => {
|
|
206
207
|
if (token && !hasSynced.current) {
|
|
@@ -208,11 +209,6 @@ const AgentMemoryExample = () => {
|
|
|
208
209
|
syncTokenToIamStore(token);
|
|
209
210
|
}
|
|
210
211
|
}, [token]);
|
|
211
|
-
const handleSignIn = useCallback((newToken, handle) => {
|
|
212
|
-
setAuth(newToken, handle);
|
|
213
|
-
hasSynced.current = true;
|
|
214
|
-
syncTokenToIamStore(newToken);
|
|
215
|
-
}, [setAuth]);
|
|
216
212
|
const handleLogout = useCallback(() => {
|
|
217
213
|
clearAuth();
|
|
218
214
|
hasSynced.current = false;
|
|
@@ -221,7 +217,7 @@ const AgentMemoryExample = () => {
|
|
|
221
217
|
});
|
|
222
218
|
}, [clearAuth]);
|
|
223
219
|
if (!token) {
|
|
224
|
-
return (_jsx(ThemedProvider, { children: _jsx(
|
|
220
|
+
return (_jsx(ThemedProvider, { children: _jsx(AuthRequiredView, {}) }));
|
|
225
221
|
}
|
|
226
222
|
return (_jsx(QueryClientProvider, { client: queryClient, children: _jsx(ThemedProvider, { children: _jsx(AgentMemoryInner, { onLogout: handleLogout }) }) }));
|
|
227
223
|
};
|
|
@@ -16,142 +16,57 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
16
16
|
/// <reference types="vite/client" />
|
|
17
17
|
import { useEffect, useState, useCallback, useRef } from 'react';
|
|
18
18
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
19
|
-
import { Text,
|
|
20
|
-
import {
|
|
19
|
+
import { Text, Spinner, Heading, Label } from '@primer/react';
|
|
20
|
+
import { GraphIcon } from '@primer/octicons-react';
|
|
21
21
|
import { Box } from '@datalayer/primer-addons';
|
|
22
|
-
import { ErrorView } from './components';
|
|
22
|
+
import { AuthRequiredView, ErrorView } from './components';
|
|
23
23
|
import { ThemedProvider } from './utils/themedProvider';
|
|
24
|
+
import { uniqueAgentId } from './utils/agentId';
|
|
25
|
+
import { ContextPanel, } from '../context/ContextPanel';
|
|
26
|
+
import { CostTracker } from '../context/CostTracker';
|
|
27
|
+
import { CostUsageChart } from '../context/CostUsageChart';
|
|
28
|
+
import { TokenUsageChart } from '../context/TokenUsageChart';
|
|
29
|
+
import { GraphFlowChart } from '../context/GraphFlowChart';
|
|
30
|
+
import { TurnGraphChart } from '../context/TurnGraphChart';
|
|
31
|
+
import { useAIAgentsWebSocket } from '../hooks';
|
|
32
|
+
import { parseAgentStreamMessage } from '../types/stream';
|
|
33
|
+
import { useCoreStore } from '@datalayer/core/lib/state';
|
|
24
34
|
const queryClient = new QueryClient();
|
|
25
35
|
import { useSimpleAuthStore } from '@datalayer/core/lib/views/otel';
|
|
26
|
-
import { SignInSimple } from '@datalayer/core/lib/views/iam';
|
|
27
|
-
import { UserBadge } from '@datalayer/core/lib/views/profile';
|
|
28
36
|
import { Chat } from '../chat';
|
|
29
|
-
import { useAgents } from '../hooks/useAgents';
|
|
30
37
|
const AGENT_NAME = 'monitoring-demo-agent';
|
|
31
|
-
const AGENT_SPEC_ID = '
|
|
32
|
-
const
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
return Number.isFinite(n) ? n : fallback;
|
|
36
|
-
};
|
|
37
|
-
const randomOffset = (range) => (Math.random() - 0.5) * range;
|
|
38
|
-
const createSyntheticSnapshot = (previous) => {
|
|
39
|
-
const baseCpu = previous?.cpuPercent ?? 42;
|
|
40
|
-
const baseMemory = previous?.memoryPercent ?? 57;
|
|
41
|
-
const baseLatency = previous?.latencyMs ?? 320;
|
|
42
|
-
const baseErrorRate = previous?.errorRatePercent ?? 1.6;
|
|
43
|
-
const baseQueueDepth = previous?.queueDepth ?? 12;
|
|
44
|
-
const cpuPercent = clampPercent(baseCpu + randomOffset(10));
|
|
45
|
-
const memoryPercent = clampPercent(baseMemory + randomOffset(8));
|
|
46
|
-
const latencyMs = Math.max(30, baseLatency + randomOffset(120));
|
|
47
|
-
const errorRatePercent = clampPercent(baseErrorRate + randomOffset(0.8));
|
|
48
|
-
const queueDepth = Math.max(0, Math.round(baseQueueDepth + randomOffset(8)));
|
|
49
|
-
let status = 'healthy';
|
|
50
|
-
if (errorRatePercent > 4 || latencyMs > 1200 || cpuPercent > 90) {
|
|
51
|
-
status = 'critical';
|
|
52
|
-
}
|
|
53
|
-
else if (errorRatePercent > 2 || latencyMs > 700 || cpuPercent > 80) {
|
|
54
|
-
status = 'degraded';
|
|
55
|
-
}
|
|
56
|
-
return {
|
|
57
|
-
timestamp: new Date().toISOString(),
|
|
58
|
-
cpuPercent,
|
|
59
|
-
memoryPercent,
|
|
60
|
-
latencyMs,
|
|
61
|
-
errorRatePercent,
|
|
62
|
-
queueDepth,
|
|
63
|
-
status,
|
|
64
|
-
};
|
|
65
|
-
};
|
|
66
|
-
const normalizeSnapshot = (raw, previous) => {
|
|
67
|
-
if (!raw || typeof raw !== 'object') {
|
|
68
|
-
return createSyntheticSnapshot(previous);
|
|
69
|
-
}
|
|
70
|
-
const data = raw;
|
|
71
|
-
const snapshot = createSyntheticSnapshot(previous);
|
|
72
|
-
const statusValue = String(data.status ?? snapshot.status).toLowerCase();
|
|
73
|
-
const status = statusValue === 'healthy' ||
|
|
74
|
-
statusValue === 'degraded' ||
|
|
75
|
-
statusValue === 'critical'
|
|
76
|
-
? statusValue
|
|
77
|
-
: 'unknown';
|
|
78
|
-
return {
|
|
79
|
-
timestamp: String(data.timestamp ?? new Date().toISOString()),
|
|
80
|
-
cpuPercent: clampPercent(toNumber(data.cpuPercent ?? data.cpu, snapshot.cpuPercent)),
|
|
81
|
-
memoryPercent: clampPercent(toNumber(data.memoryPercent ?? data.memory, snapshot.memoryPercent)),
|
|
82
|
-
latencyMs: Math.max(0, toNumber(data.latencyMs ?? data.latency, snapshot.latencyMs)),
|
|
83
|
-
errorRatePercent: clampPercent(toNumber(data.errorRatePercent ?? data.errorRate, snapshot.errorRatePercent)),
|
|
84
|
-
queueDepth: Math.max(0, Math.round(toNumber(data.queueDepth, snapshot.queueDepth))),
|
|
85
|
-
status,
|
|
86
|
-
};
|
|
87
|
-
};
|
|
88
|
-
const normalizeAlert = (raw, index) => {
|
|
89
|
-
if (!raw || typeof raw !== 'object') {
|
|
90
|
-
return null;
|
|
91
|
-
}
|
|
92
|
-
const data = raw;
|
|
93
|
-
const severityValue = String(data.severity ?? 'info').toLowerCase();
|
|
94
|
-
const severity = severityValue === 'warning' || severityValue === 'critical'
|
|
95
|
-
? severityValue
|
|
96
|
-
: 'info';
|
|
97
|
-
return {
|
|
98
|
-
id: String(data.id ?? `alert-${Date.now()}-${index}`),
|
|
99
|
-
title: String(data.title ?? 'Agent alert detected'),
|
|
100
|
-
severity,
|
|
101
|
-
timestamp: String(data.timestamp ?? new Date().toISOString()),
|
|
102
|
-
};
|
|
103
|
-
};
|
|
104
|
-
const statusVariant = (status) => {
|
|
105
|
-
if (status === 'healthy')
|
|
106
|
-
return 'success';
|
|
107
|
-
if (status === 'degraded')
|
|
108
|
-
return 'attention';
|
|
109
|
-
if (status === 'critical')
|
|
110
|
-
return 'danger';
|
|
111
|
-
return 'secondary';
|
|
112
|
-
};
|
|
113
|
-
const alertVariant = (severity) => {
|
|
114
|
-
if (severity === 'critical')
|
|
115
|
-
return 'danger';
|
|
116
|
-
if (severity === 'warning')
|
|
117
|
-
return 'attention';
|
|
118
|
-
return 'secondary';
|
|
119
|
-
};
|
|
120
|
-
const MetricRow = ({ label, value, percent }) => {
|
|
121
|
-
return (_jsxs(Box, { sx: { mb: 2 }, children: [_jsxs(Box, { sx: {
|
|
122
|
-
display: 'flex',
|
|
123
|
-
justifyContent: 'space-between',
|
|
124
|
-
alignItems: 'center',
|
|
125
|
-
mb: 1,
|
|
126
|
-
}, children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: label }), _jsx(Text, { sx: { fontSize: 0, fontWeight: 'bold' }, children: value })] }), _jsx(Box, { sx: {
|
|
127
|
-
width: '100%',
|
|
128
|
-
height: 8,
|
|
129
|
-
bg: 'canvas.subtle',
|
|
130
|
-
borderRadius: 6,
|
|
131
|
-
overflow: 'hidden',
|
|
132
|
-
}, children: _jsx(Box, { sx: {
|
|
133
|
-
width: `${clampPercent(percent)}%`,
|
|
134
|
-
height: '100%',
|
|
135
|
-
bg: percent >= 85 ? 'danger.emphasis' : 'accent.emphasis',
|
|
136
|
-
transition: 'width 300ms ease-out',
|
|
137
|
-
} }) })] }));
|
|
138
|
-
};
|
|
38
|
+
const AGENT_SPEC_ID = 'demo-monitoring';
|
|
39
|
+
const DEFAULT_LOCAL_BASE_URL = import.meta.env.VITE_BASE_URL || 'http://localhost:8765';
|
|
40
|
+
const OTEL_BASE_URL_ENV = import.meta.env.VITE_OTEL_BASE_URL;
|
|
41
|
+
const DATALAYER_RUN_URL_ENV = import.meta.env.DATALAYER_RUN_URL;
|
|
139
42
|
const AgentMonitoringInner = ({ onLogout, }) => {
|
|
140
43
|
const { token } = useSimpleAuthStore();
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
},
|
|
149
|
-
});
|
|
150
|
-
const [snapshots, setSnapshots] = useState([]);
|
|
44
|
+
const agentName = useRef(uniqueAgentId(AGENT_NAME)).current;
|
|
45
|
+
const { configuration } = useCoreStore();
|
|
46
|
+
const [runtimeStatus, setRuntimeStatus] = useState('launching');
|
|
47
|
+
const [isReady, setIsReady] = useState(false);
|
|
48
|
+
const [hookError, setHookError] = useState(null);
|
|
49
|
+
const [agentId, setAgentId] = useState(agentName);
|
|
50
|
+
const [isReconnectedAgent, setIsReconnectedAgent] = useState(false);
|
|
151
51
|
const [alerts, setAlerts] = useState([]);
|
|
152
|
-
const
|
|
153
|
-
const
|
|
154
|
-
const
|
|
52
|
+
const [liveContext, setLiveContext] = useState(undefined);
|
|
53
|
+
const [liveContextSnapshot, setLiveContextSnapshot] = useState(undefined);
|
|
54
|
+
const [liveCost, setLiveCost] = useState(undefined);
|
|
55
|
+
const [liveMcpStatus, setLiveMcpStatus] = useState(undefined);
|
|
56
|
+
const [monitorLastSnapshotAt, setMonitorLastSnapshotAt] = useState(null);
|
|
57
|
+
const [liveGraphTelemetry, setLiveGraphTelemetry] = useState(undefined);
|
|
58
|
+
const agentBaseUrl = DEFAULT_LOCAL_BASE_URL;
|
|
59
|
+
const otelBaseUrl = configuration?.otelRunUrl ||
|
|
60
|
+
configuration?.runUrl ||
|
|
61
|
+
OTEL_BASE_URL_ENV ||
|
|
62
|
+
DATALAYER_RUN_URL_ENV ||
|
|
63
|
+
'https://prod1.datalayer.run';
|
|
64
|
+
const podName = agentId;
|
|
65
|
+
// The OTEL service_name resource attribute is 'agent-runtimes' (the
|
|
66
|
+
// application name), NOT the individual agent ID. Use the correct value
|
|
67
|
+
// so the TokenUsageChart WS filter and HTTP query match actual rows.
|
|
68
|
+
const otelServiceName = 'agent-runtimes';
|
|
69
|
+
const chatAuthToken = token === null ? undefined : token;
|
|
155
70
|
const authFetch = useCallback((url, opts = {}) => fetch(url, {
|
|
156
71
|
...opts,
|
|
157
72
|
headers: {
|
|
@@ -161,46 +76,137 @@ const AgentMonitoringInner = ({ onLogout, }) => {
|
|
|
161
76
|
},
|
|
162
77
|
}), [token]);
|
|
163
78
|
useEffect(() => {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
79
|
+
let isCancelled = false;
|
|
80
|
+
const createLocalAgent = async () => {
|
|
81
|
+
setRuntimeStatus('launching');
|
|
82
|
+
setIsReady(false);
|
|
83
|
+
setHookError(null);
|
|
84
|
+
setIsReconnectedAgent(false);
|
|
169
85
|
try {
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
: []
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
86
|
+
const response = await authFetch(`${agentBaseUrl}/api/v1/agents`, {
|
|
87
|
+
method: 'POST',
|
|
88
|
+
body: JSON.stringify({
|
|
89
|
+
name: agentName,
|
|
90
|
+
description: 'MCP monitoring demo – web crawling via Tavily with live cost/token metrics',
|
|
91
|
+
agent_library: 'pydantic-ai',
|
|
92
|
+
transport: 'vercel-ai',
|
|
93
|
+
agent_spec_id: AGENT_SPEC_ID,
|
|
94
|
+
enable_skills: true,
|
|
95
|
+
tools: [],
|
|
96
|
+
}),
|
|
97
|
+
});
|
|
98
|
+
let resolvedAgentId = agentName;
|
|
99
|
+
let isAlreadyRunning = false;
|
|
100
|
+
if (response.ok) {
|
|
101
|
+
const data = await response.json();
|
|
102
|
+
resolvedAgentId = data?.id || agentName;
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
const contentType = response.headers.get('content-type') || '';
|
|
106
|
+
let detail = '';
|
|
107
|
+
if (contentType.includes('application/json')) {
|
|
108
|
+
const data = await response.json().catch(() => null);
|
|
109
|
+
detail =
|
|
110
|
+
(typeof data?.detail === 'string' && data.detail) ||
|
|
111
|
+
(typeof data?.message === 'string' && data.message) ||
|
|
112
|
+
'';
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
detail = await response.text();
|
|
116
|
+
}
|
|
117
|
+
if (response.status === 409 || /already exists/i.test(detail || '')) {
|
|
118
|
+
isAlreadyRunning = true;
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
throw new Error(detail || `Failed to create local agent: ${response.status}`);
|
|
186
122
|
}
|
|
187
|
-
|
|
123
|
+
}
|
|
124
|
+
if (!isCancelled) {
|
|
125
|
+
setAgentId(resolvedAgentId);
|
|
126
|
+
setIsReconnectedAgent(isAlreadyRunning);
|
|
127
|
+
setIsReady(true);
|
|
128
|
+
setRuntimeStatus('ready');
|
|
188
129
|
}
|
|
189
130
|
}
|
|
190
|
-
catch {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
if (prev.length > 0) {
|
|
195
|
-
return prev;
|
|
131
|
+
catch (error) {
|
|
132
|
+
if (!isCancelled) {
|
|
133
|
+
setHookError(error instanceof Error ? error.message : 'Agent failed to start');
|
|
134
|
+
setRuntimeStatus('error');
|
|
196
135
|
}
|
|
197
|
-
|
|
198
|
-
});
|
|
136
|
+
}
|
|
199
137
|
};
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
138
|
+
void createLocalAgent();
|
|
139
|
+
return () => {
|
|
140
|
+
isCancelled = true;
|
|
141
|
+
};
|
|
142
|
+
}, [agentBaseUrl, authFetch]);
|
|
143
|
+
const handleMonitoringStreamMessage = useCallback((message) => {
|
|
144
|
+
try {
|
|
145
|
+
const stream = parseAgentStreamMessage(message?.raw ?? message);
|
|
146
|
+
if (!stream || stream.type !== 'agent.snapshot') {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
const payload = stream.payload;
|
|
150
|
+
if (payload.contextSnapshot) {
|
|
151
|
+
setLiveContext(payload.contextSnapshot);
|
|
152
|
+
setLiveContextSnapshot(payload.contextSnapshot);
|
|
153
|
+
setMonitorLastSnapshotAt(Date.now());
|
|
154
|
+
}
|
|
155
|
+
if (payload.mcpStatus !== undefined) {
|
|
156
|
+
setLiveMcpStatus(payload.mcpStatus ?? undefined);
|
|
157
|
+
}
|
|
158
|
+
if (payload.graphTelemetry) {
|
|
159
|
+
setLiveGraphTelemetry(payload.graphTelemetry);
|
|
160
|
+
}
|
|
161
|
+
const snapshotCost = payload.contextSnapshot?.costUsage ?? payload.costUsage;
|
|
162
|
+
if (!snapshotCost) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
setLiveCost({
|
|
166
|
+
agentId,
|
|
167
|
+
lastTurnCostUsd: Number(snapshotCost.lastTurnCostUsd ?? 0),
|
|
168
|
+
cumulativeCostUsd: Number(snapshotCost.cumulativeCostUsd ?? 0),
|
|
169
|
+
perRunBudgetUsd: snapshotCost.perRunBudgetUsd == null
|
|
170
|
+
? null
|
|
171
|
+
: Number(snapshotCost.perRunBudgetUsd),
|
|
172
|
+
cumulativeBudgetUsd: snapshotCost.cumulativeBudgetUsd == null
|
|
173
|
+
? null
|
|
174
|
+
: Number(snapshotCost.cumulativeBudgetUsd),
|
|
175
|
+
requestCount: Number(snapshotCost.requestCount ?? 0),
|
|
176
|
+
totalTokensUsed: Number(snapshotCost.totalTokensUsed ?? 0),
|
|
177
|
+
modelBreakdown: Array.isArray(snapshotCost.modelBreakdown)
|
|
178
|
+
? snapshotCost.modelBreakdown.map(item => ({
|
|
179
|
+
model: String(item.model ?? 'unknown'),
|
|
180
|
+
inputTokens: Number(item.inputTokens ?? 0),
|
|
181
|
+
outputTokens: Number(item.outputTokens ?? 0),
|
|
182
|
+
costUsd: Number(item.costUsd ?? 0),
|
|
183
|
+
requests: Number(item.requests ?? 0),
|
|
184
|
+
}))
|
|
185
|
+
: [],
|
|
186
|
+
runs: Array.isArray(snapshotCost.runs)
|
|
187
|
+
? snapshotCost.runs.map(item => ({
|
|
188
|
+
pricingResolved: Boolean(item.pricingResolved),
|
|
189
|
+
}))
|
|
190
|
+
: undefined,
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
// Ignore malformed stream payloads.
|
|
195
|
+
}
|
|
196
|
+
}, [agentId]);
|
|
197
|
+
const monitorSocket = useAIAgentsWebSocket({
|
|
198
|
+
enabled: isReady && Boolean(agentBaseUrl),
|
|
199
|
+
baseUrl: agentBaseUrl,
|
|
200
|
+
path: '/api/v1/tool-approvals/ws',
|
|
201
|
+
queryParams: { agent_id: agentId },
|
|
202
|
+
onMessage: handleMonitoringStreamMessage,
|
|
203
|
+
reconnectDelayMs: attempt => Math.min(1000 * 2 ** Math.max(0, attempt - 1), 10000),
|
|
204
|
+
});
|
|
205
|
+
useEffect(() => {
|
|
206
|
+
// Monitoring alerts endpoint is optional and may return 404 in local mode.
|
|
207
|
+
// Keep the UI quiet and rely on stream snapshots for now.
|
|
208
|
+
setAlerts([]);
|
|
209
|
+
}, [isReady, agentId]);
|
|
204
210
|
if (!isReady && runtimeStatus !== 'error') {
|
|
205
211
|
return (_jsxs(Box, { sx: {
|
|
206
212
|
display: 'flex',
|
|
@@ -209,14 +215,11 @@ const AgentMonitoringInner = ({ onLogout, }) => {
|
|
|
209
215
|
justifyContent: 'center',
|
|
210
216
|
height: '100vh',
|
|
211
217
|
gap: 3,
|
|
212
|
-
}, children: [_jsx(Spinner, { size: "large" }), _jsx(Text, { sx: { color: 'fg.muted' }, children:
|
|
213
|
-
? 'Launching runtime for monitoring agent…'
|
|
214
|
-
: 'Creating monitoring demo agent…' })] }));
|
|
218
|
+
}, children: [_jsx(Spinner, { size: "large" }), _jsx(Text, { sx: { color: 'fg.muted' }, children: "Launching local monitoring demo agent..." })] }));
|
|
215
219
|
}
|
|
216
220
|
if (runtimeStatus === 'error' || hookError) {
|
|
217
221
|
return _jsx(ErrorView, { error: hookError, onLogout: onLogout });
|
|
218
222
|
}
|
|
219
|
-
const latest = snapshots[0] ?? createSyntheticSnapshot();
|
|
220
223
|
return (_jsxs(Box, { sx: {
|
|
221
224
|
height: 'calc(100vh - 60px)',
|
|
222
225
|
display: 'flex',
|
|
@@ -230,46 +233,109 @@ const AgentMonitoringInner = ({ onLogout, }) => {
|
|
|
230
233
|
borderBottom: '1px solid',
|
|
231
234
|
borderColor: 'border.default',
|
|
232
235
|
flexShrink: 0,
|
|
233
|
-
}, children: [_jsx(GraphIcon, { size: 16 }), _jsxs(Heading, { as: "h3", sx: { fontSize: 2, flex: 1 }, children: ["Monitoring \u2014 ", podName] }),
|
|
236
|
+
}, children: [_jsx(GraphIcon, { size: 16 }), _jsxs(Heading, { as: "h3", sx: { fontSize: 2, flex: 1 }, children: ["Monitoring \u2014 ", podName] }), isReconnectedAgent && (_jsx(Label, { variant: "secondary", size: "small", children: "Reconnected" })), _jsxs(Label, { variant: monitorSocket.connectionState === 'connected'
|
|
237
|
+
? 'success'
|
|
238
|
+
: 'secondary', children: ["WS: ", monitorSocket.connectionState] })] }), _jsxs(Box, { sx: { flex: 1, minHeight: 0, display: 'flex' }, children: [_jsxs(Box, { sx: {
|
|
239
|
+
width: 320,
|
|
240
|
+
minWidth: 280,
|
|
241
|
+
borderRight: '1px solid',
|
|
242
|
+
borderColor: 'border.default',
|
|
243
|
+
display: 'flex',
|
|
244
|
+
flexDirection: 'column',
|
|
245
|
+
overflow: 'auto',
|
|
246
|
+
'@media (max-width: 1680px)': {
|
|
247
|
+
width: 300,
|
|
248
|
+
minWidth: 260,
|
|
249
|
+
},
|
|
250
|
+
'@media (max-width: 1400px)': {
|
|
251
|
+
display: 'none',
|
|
252
|
+
},
|
|
253
|
+
}, children: [_jsxs(Box, { sx: {
|
|
254
|
+
p: 3,
|
|
255
|
+
borderBottom: '1px solid',
|
|
256
|
+
borderColor: 'border.default',
|
|
257
|
+
}, children: [_jsx(Heading, { as: "h4", sx: { fontSize: 1, mb: 2 }, children: "Token Usage" }), _jsx(TokenUsageChart, { serviceName: otelServiceName, agentId: agentId, apiKey: token ?? undefined, runUrl: otelBaseUrl, liveSystemPromptTokens: liveContextSnapshot?.systemPromptTokens, liveUserMessageTokens: liveContextSnapshot?.userMessageTokens, liveAgentMessageTokens: liveContextSnapshot?.assistantMessageTokens, liveToolsUsageTokens: liveContextSnapshot?.toolTokens, liveTimestampMs: monitorLastSnapshotAt, height: 180 })] }), _jsxs(Box, { sx: {
|
|
258
|
+
p: 3,
|
|
259
|
+
borderBottom: '1px solid',
|
|
260
|
+
borderColor: 'border.default',
|
|
261
|
+
}, children: [_jsx(Heading, { as: "h4", sx: { fontSize: 1, mb: 2 }, children: "Cost" }), _jsx(CostUsageChart, { serviceName: otelServiceName, agentId: agentId, apiKey: token ?? undefined, runUrl: otelBaseUrl, liveCumulativeUsd: liveCost?.cumulativeCostUsd, liveTimestampMs: monitorLastSnapshotAt, height: 180 })] }), _jsxs(Box, { sx: {
|
|
262
|
+
p: 3,
|
|
263
|
+
borderBottom: '1px solid',
|
|
264
|
+
borderColor: 'border.default',
|
|
265
|
+
}, children: [_jsx(Heading, { as: "h4", sx: { fontSize: 1, mb: 2 }, children: "LLM Cost Monitoring" }), liveCost ? (_jsx(CostTracker, { agentId: agentId, compact: false, liveData: liveCost })) : (_jsxs(Box, { children: [_jsx(Text, { sx: { color: 'fg.muted', fontSize: 1 }, children: "Waiting for first websocket snapshot..." }), monitorSocket.lastClose?.detail && (_jsxs(Text, { sx: {
|
|
266
|
+
color: 'danger.fg',
|
|
267
|
+
fontSize: 0,
|
|
268
|
+
mt: 1,
|
|
269
|
+
display: 'block',
|
|
270
|
+
}, children: ["Last close: ", monitorSocket.lastClose.detail] }))] }))] })] }), _jsx(Box, { sx: { flex: 1, minWidth: 0 }, children: _jsx(Chat, { protocol: "vercel-ai", baseUrl: agentBaseUrl, agentId: agentId, authToken: chatAuthToken, title: "Monitoring Agent", placeholder: "Ask for cost, token usage, and turn-level monitoring insights...", description: `${alerts.length} active alert${alerts.length !== 1 ? 's' : ''}`, showHeader: true, showTokenUsage: true, showToolsMenu: true, showSkillsMenu: true, autoFocus: true, height: "100%", runtimeId: agentId, historyEndpoint: `${agentBaseUrl}/api/v1/history`, suggestions: [
|
|
271
|
+
{
|
|
272
|
+
title: '▶ No-tool turn',
|
|
273
|
+
message: 'Briefly introduce yourself without calling any tool or skill — produces a linear Start → Model → Decision → End graph.',
|
|
274
|
+
},
|
|
234
275
|
{
|
|
235
|
-
title: '
|
|
236
|
-
message: '
|
|
276
|
+
title: '🔍 Single tool call',
|
|
277
|
+
message: 'Use the Tavily web search tool to find the latest news about pydantic-graph. Make a single search call.',
|
|
237
278
|
},
|
|
238
279
|
{
|
|
239
|
-
title: '
|
|
240
|
-
message: '
|
|
280
|
+
title: '🌀 Parallel tool fan-out',
|
|
281
|
+
message: 'Use Tavily to search the web in parallel for these three topics in the same turn: (1) OpenTelemetry traces, (2) agent observability, (3) LLM cost monitoring. Issue all three searches together so the turn graph fans out (Broadcast → Spread → Join).',
|
|
241
282
|
},
|
|
242
|
-
|
|
243
|
-
|
|
283
|
+
{
|
|
284
|
+
title: '🧩 Skill call',
|
|
285
|
+
message: 'Use the datalayer-whoami skill to identify my profile, then summarize it.',
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
title: '😄 Joke skill',
|
|
289
|
+
message: 'Use the jokes skill to tell me a random dad joke, then wrap it in one-sentence commentary.',
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
title: '🧪 Mixed tools + skills',
|
|
293
|
+
message: 'In one turn: (a) use Tavily to search for "OTEL traces best practices", (b) call the datalayer-whoami skill, (c) call the jokes skill. Summarize all three results together. This should produce a Broadcast → three Spread nodes → Join in the Turn Execution Graph.',
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
title: 'Monitoring summary',
|
|
297
|
+
message: 'Summarize my current token usage, cost status, and recent turn activity.',
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
title: 'Turn usage analysis',
|
|
301
|
+
message: 'Analyze the last turn usage and explain which parts drove input and output tokens.',
|
|
302
|
+
},
|
|
303
|
+
], submitOnSuggestionClick: true, contextSnapshot: liveContextSnapshot, mcpStatusData: liveMcpStatus }) }), _jsxs(Box, { sx: {
|
|
304
|
+
width: 360,
|
|
305
|
+
minWidth: 320,
|
|
244
306
|
borderLeft: '1px solid',
|
|
245
307
|
borderColor: 'border.default',
|
|
246
308
|
display: 'flex',
|
|
247
309
|
flexDirection: 'column',
|
|
248
310
|
overflow: 'auto',
|
|
311
|
+
'@media (max-width: 1680px)': {
|
|
312
|
+
width: 340,
|
|
313
|
+
minWidth: 300,
|
|
314
|
+
},
|
|
315
|
+
'@media (max-width: 1100px)': {
|
|
316
|
+
width: 300,
|
|
317
|
+
minWidth: 260,
|
|
318
|
+
},
|
|
249
319
|
}, children: [_jsxs(Box, { sx: {
|
|
250
320
|
p: 3,
|
|
251
321
|
borderBottom: '1px solid',
|
|
252
322
|
borderColor: 'border.default',
|
|
253
|
-
}, children: [_jsx(Heading, { as: "h4", sx: { fontSize: 1, mb: 2 }, children: "
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
justifyContent: 'space-between',
|
|
270
|
-
alignItems: 'center',
|
|
271
|
-
mb: 1,
|
|
272
|
-
}, children: [_jsx(Text, { sx: { fontSize: 1, fontWeight: 'bold' }, children: alert.title }), _jsx(Label, { size: "small", variant: alertVariant(alert.severity), children: alert.severity })] }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: new Date(alert.timestamp).toLocaleString() })] }, alert.id))))] })] })] })] }));
|
|
323
|
+
}, children: [_jsx(Heading, { as: "h4", sx: { fontSize: 1, mb: 2 }, children: "Turn and Session Usage" }), liveContext ? (_jsx(ContextPanel, { agentId: agentId, apiBase: agentBaseUrl, liveData: liveContext, defaultView: "overview", chartHeight: "160px" })) : (_jsx(Text, { sx: { color: 'fg.muted', fontSize: 1 }, children: "Waiting for first websocket snapshot..." })), _jsxs(Text, { sx: { mt: 2, color: 'fg.muted', fontSize: 0 }, children: ["Live monitoring uses websocket snapshots only.", monitorLastSnapshotAt
|
|
324
|
+
? ` Last snapshot ${new Date(monitorLastSnapshotAt).toLocaleTimeString()}.`
|
|
325
|
+
: '', monitorSocket.connectionState !== 'connected' &&
|
|
326
|
+
monitorSocket.reconnectAttempt > 0
|
|
327
|
+
? ` Reconnect attempt ${monitorSocket.reconnectAttempt}.`
|
|
328
|
+
: ''] })] }), liveGraphTelemetry && (_jsxs(Box, { sx: {
|
|
329
|
+
p: 3,
|
|
330
|
+
borderBottom: '1px solid',
|
|
331
|
+
borderColor: 'border.default',
|
|
332
|
+
}, children: [_jsx(Heading, { as: "h4", sx: { fontSize: 1, mb: 2 }, children: "Graph Execution (live)" }), _jsx(GraphFlowChart, { data: liveGraphTelemetry, height: 240 }), _jsxs(Text, { sx: { mt: 1, color: 'fg.muted', fontSize: 0 }, children: [liveGraphTelemetry.totalNodesExecuted, " node(s) executed across", ' ', liveGraphTelemetry.runCount, " run(s)", liveGraphTelemetry.totalDurationMs
|
|
333
|
+
? ` — ${(liveGraphTelemetry.totalDurationMs / 1000).toFixed(2)}s total`
|
|
334
|
+
: ''] })] })), _jsxs(Box, { sx: {
|
|
335
|
+
p: 3,
|
|
336
|
+
borderBottom: '1px solid',
|
|
337
|
+
borderColor: 'border.default',
|
|
338
|
+
}, children: [_jsx(Heading, { as: "h4", sx: { fontSize: 1, mb: 2 }, children: "Turn Execution Graph (OTEL traces)" }), _jsx(TurnGraphChart, { serviceName: otelServiceName, agentId: agentId, runUrl: otelBaseUrl, apiKey: token ?? undefined, autoRefreshMs: 10_000, height: 280 })] })] })] })] }));
|
|
273
339
|
};
|
|
274
340
|
const syncTokenToIamStore = (token) => {
|
|
275
341
|
import('@datalayer/core/lib/state').then(({ iamStore }) => {
|
|
@@ -277,7 +343,7 @@ const syncTokenToIamStore = (token) => {
|
|
|
277
343
|
});
|
|
278
344
|
};
|
|
279
345
|
const AgentMonitoringExample = () => {
|
|
280
|
-
const { token,
|
|
346
|
+
const { token, clearAuth } = useSimpleAuthStore();
|
|
281
347
|
const hasSynced = useRef(false);
|
|
282
348
|
useEffect(() => {
|
|
283
349
|
if (token && !hasSynced.current) {
|
|
@@ -285,11 +351,6 @@ const AgentMonitoringExample = () => {
|
|
|
285
351
|
syncTokenToIamStore(token);
|
|
286
352
|
}
|
|
287
353
|
}, [token]);
|
|
288
|
-
const handleSignIn = useCallback((newToken, handle) => {
|
|
289
|
-
setAuth(newToken, handle);
|
|
290
|
-
hasSynced.current = true;
|
|
291
|
-
syncTokenToIamStore(newToken);
|
|
292
|
-
}, [setAuth]);
|
|
293
354
|
const handleLogout = useCallback(() => {
|
|
294
355
|
clearAuth();
|
|
295
356
|
hasSynced.current = false;
|
|
@@ -298,7 +359,7 @@ const AgentMonitoringExample = () => {
|
|
|
298
359
|
});
|
|
299
360
|
}, [clearAuth]);
|
|
300
361
|
if (!token) {
|
|
301
|
-
return (_jsx(ThemedProvider, { children: _jsx(
|
|
362
|
+
return (_jsx(ThemedProvider, { children: _jsx(AuthRequiredView, {}) }));
|
|
302
363
|
}
|
|
303
364
|
return (_jsx(QueryClientProvider, { client: queryClient, children: _jsx(ThemedProvider, { children: _jsx(AgentMonitoringInner, { onLogout: handleLogout }) }) }));
|
|
304
365
|
};
|