@datalayer/agent-runtimes 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +182 -1
- package/lib/AgentNode.d.ts +3 -0
- package/lib/AgentNode.js +676 -0
- package/lib/App.js +1 -1
- package/lib/agent-node/themeStore.d.ts +3 -0
- package/lib/agent-node/themeStore.js +156 -0
- package/lib/agent-node-main.d.ts +1 -0
- package/lib/agent-node-main.js +14 -0
- package/lib/agents/AgentDetails.d.ts +22 -1
- package/lib/agents/AgentDetails.js +34 -47
- package/lib/api/index.d.ts +0 -1
- package/lib/api/index.js +4 -2
- package/lib/chat/Chat.d.ts +5 -106
- package/lib/chat/Chat.js +20 -14
- package/lib/chat/ChatFloating.d.ts +7 -140
- package/lib/chat/ChatFloating.js +3 -3
- package/lib/chat/ChatPopupStandalone.d.ts +8 -47
- package/lib/chat/ChatPopupStandalone.js +3 -3
- package/lib/chat/ChatSidebar.d.ts +4 -69
- package/lib/chat/ChatSidebar.js +83 -51
- package/lib/chat/ChatStandalone.d.ts +4 -54
- package/lib/chat/ChatStandalone.js +3 -3
- package/lib/chat/base/ChatBase.js +1414 -174
- package/lib/chat/display/FloatingBrandButton.js +8 -1
- package/lib/chat/header/ChatHeader.d.ts +3 -1
- package/lib/chat/header/ChatHeader.js +15 -12
- package/lib/chat/header/ChatHeaderBase.d.ts +30 -5
- package/lib/chat/header/ChatHeaderBase.js +41 -16
- package/lib/chat/indicators/McpStatusIndicator.d.ts +7 -4
- package/lib/chat/indicators/McpStatusIndicator.js +7 -32
- package/lib/chat/indicators/SandboxStatusIndicator.d.ts +4 -1
- package/lib/chat/indicators/SandboxStatusIndicator.js +91 -56
- package/lib/chat/indicators/SkillsStatusIndicator.d.ts +7 -0
- package/lib/chat/indicators/SkillsStatusIndicator.js +88 -0
- package/lib/chat/indicators/index.d.ts +1 -0
- package/lib/chat/indicators/index.js +1 -0
- package/lib/chat/messages/ChatMessageList.d.ts +1 -1
- package/lib/chat/messages/ChatMessageList.js +154 -114
- package/lib/chat/messages/ChatMessages.js +6 -2
- package/lib/chat/prompt/InputFooter.d.ts +21 -6
- package/lib/chat/prompt/InputFooter.js +76 -20
- package/lib/chat/prompt/InputPrompt.d.ts +5 -1
- package/lib/chat/prompt/InputPrompt.js +4 -4
- package/lib/chat/prompt/InputPromptFooter.d.ts +3 -1
- package/lib/chat/prompt/InputPromptFooter.js +3 -3
- package/lib/chat/prompt/InputPromptLexical.d.ts +3 -1
- package/lib/chat/prompt/InputPromptLexical.js +12 -5
- package/lib/chat/prompt/InputPromptText.d.ts +3 -1
- package/lib/chat/prompt/InputPromptText.js +2 -2
- package/lib/chat/tools/ToolApprovalBanner.js +1 -1
- package/lib/chat/tools/ToolCallDisplay.d.ts +3 -1
- package/lib/chat/tools/ToolCallDisplay.js +2 -2
- package/lib/chat/usage/TokenUsageBar.js +20 -2
- package/lib/client/AgentRuntimesClientContext.d.ts +53 -0
- package/lib/client/AgentRuntimesClientContext.js +55 -0
- package/lib/client/AgentsMixin.d.ts +0 -18
- package/lib/client/AgentsMixin.js +20 -30
- package/lib/client/IAgentRuntimesClient.d.ts +215 -0
- package/lib/client/IAgentRuntimesClient.js +5 -0
- package/lib/client/SdkAgentRuntimesClient.d.ts +151 -0
- package/lib/client/SdkAgentRuntimesClient.js +134 -0
- package/lib/client/index.d.ts +4 -1
- package/lib/client/index.js +3 -1
- package/lib/components/NotificationEventCard.js +5 -1
- package/lib/config/AgentConfiguration.d.ts +22 -0
- package/lib/config/AgentConfiguration.js +319 -64
- package/lib/context/ContextDistribution.d.ts +3 -1
- package/lib/context/ContextDistribution.js +8 -27
- package/lib/context/ContextInspector.d.ts +3 -1
- package/lib/context/ContextInspector.js +19 -67
- package/lib/context/ContextPanel.d.ts +3 -1
- package/lib/context/ContextPanel.js +104 -64
- package/lib/context/ContextUsage.d.ts +3 -1
- package/lib/context/ContextUsage.js +3 -3
- package/lib/context/CostTracker.d.ts +9 -3
- package/lib/context/CostTracker.js +26 -47
- package/lib/context/CostUsageChart.d.ts +12 -0
- package/lib/context/CostUsageChart.js +378 -0
- package/lib/context/GraphFlowChart.d.ts +16 -0
- package/lib/context/GraphFlowChart.js +182 -0
- package/lib/context/TokenUsageChart.d.ts +8 -1
- package/lib/context/TokenUsageChart.js +349 -211
- package/lib/context/TurnGraphChart.d.ts +39 -0
- package/lib/context/TurnGraphChart.js +538 -0
- package/lib/context/otelWsPool.d.ts +20 -0
- package/lib/context/otelWsPool.js +69 -0
- package/lib/examples/A2UiComponentGalleryExample.d.ts +0 -17
- package/lib/examples/A2UiComponentGalleryExample.js +315 -522
- package/lib/examples/A2UiContactCardExample.d.ts +0 -18
- package/lib/examples/A2UiContactCardExample.js +154 -411
- package/lib/examples/A2UiRestaurantExample.d.ts +0 -30
- package/lib/examples/A2UiRestaurantExample.js +114 -212
- package/lib/examples/A2UiViewerExample.d.ts +0 -18
- package/lib/examples/A2UiViewerExample.js +283 -532
- package/lib/examples/AgUiBackendToolRenderingExample.js +1 -1
- package/lib/examples/AgUiHaikuGenUiExample.d.ts +1 -1
- package/lib/examples/AgUiHaikuGenUiExample.js +1 -1
- package/lib/examples/AgUiSharedStateExample.js +2 -1
- package/lib/examples/AgentCheckpointsExample.js +14 -28
- package/lib/examples/AgentCodemodeExample.d.ts +4 -6
- package/lib/examples/AgentCodemodeExample.js +603 -169
- package/lib/examples/AgentEvalsExample.js +339 -53
- package/lib/examples/AgentGuardrailsExample.js +383 -66
- package/lib/examples/AgentHooksExample.d.ts +3 -0
- package/lib/examples/AgentHooksExample.js +122 -0
- package/lib/examples/AgentInferenceProviderExample.d.ts +3 -0
- package/lib/examples/AgentInferenceProviderExample.js +329 -0
- package/lib/examples/AgentMCPExample.d.ts +3 -0
- package/lib/examples/AgentMCPExample.js +481 -0
- package/lib/examples/AgentMemoryExample.d.ts +1 -2
- package/lib/examples/AgentMemoryExample.js +78 -33
- package/lib/examples/AgentMonitoringExample.js +261 -200
- package/lib/examples/AgentNotificationsExample.d.ts +1 -2
- package/lib/examples/AgentNotificationsExample.js +114 -33
- package/lib/examples/AgentOtelExample.js +32 -42
- package/lib/examples/AgentOutputsExample.d.ts +11 -6
- package/lib/examples/AgentOutputsExample.js +433 -81
- package/lib/examples/AgentParametersExample.d.ts +3 -0
- package/lib/examples/AgentParametersExample.js +248 -0
- package/lib/examples/AgentSandboxExample.d.ts +3 -3
- package/lib/examples/AgentSandboxExample.js +74 -45
- package/lib/examples/AgentSkillsExample.js +95 -103
- package/lib/examples/AgentSubagentsExample.d.ts +14 -0
- package/lib/examples/AgentSubagentsExample.js +228 -0
- package/lib/examples/AgentToolApprovalsExample.js +49 -561
- package/lib/examples/AgentTriggersExample.js +823 -569
- package/lib/examples/{AgentspecExample.d.ts → AgentspecsExample.d.ts} +2 -2
- package/lib/examples/AgentspecsExample.js +1096 -0
- package/lib/examples/ChatCustomExample.js +16 -28
- package/lib/examples/ChatExample.js +13 -29
- package/lib/examples/CopilotKitLexicalExample.js +2 -1
- package/lib/examples/CopilotKitNotebookExample.js +2 -1
- package/lib/examples/HomeExample.d.ts +15 -0
- package/lib/examples/HomeExample.js +77 -0
- package/lib/examples/Lexical2Example.js +4 -2
- package/lib/examples/{LexicalExample.d.ts → LexicalAgentExample.d.ts} +4 -4
- package/lib/examples/{LexicalExample.js → LexicalAgentExample.js} +66 -17
- package/lib/examples/{LexicalSidebarExample.d.ts → LexicalAgentSidebarExample.d.ts} +5 -5
- package/lib/examples/LexicalAgentSidebarExample.js +261 -0
- package/lib/examples/NotebookAgentExample.d.ts +9 -0
- package/lib/examples/NotebookAgentExample.js +192 -0
- package/lib/examples/{NotebookSidebarExample.d.ts → NotebookAgentSidebarExample.d.ts} +2 -2
- package/lib/examples/NotebookAgentSidebarExample.js +221 -0
- package/lib/examples/{DatalayerNotebookExample.d.ts → NotebookCollaborationExample.d.ts} +4 -4
- package/lib/examples/{DatalayerNotebookExample.js → NotebookCollaborationExample.js} +3 -3
- package/lib/examples/NotebookExample.d.ts +4 -7
- package/lib/examples/NotebookExample.js +14 -146
- package/lib/examples/components/AuthRequiredView.d.ts +6 -0
- package/lib/examples/components/AuthRequiredView.js +33 -0
- package/lib/examples/components/ExampleWrapper.d.ts +9 -3
- package/lib/examples/components/ExampleWrapper.js +45 -9
- package/lib/examples/{ag-ui → components}/haiku/HaikuDisplay.js +1 -1
- package/lib/examples/{ag-ui → components}/haiku/InlineHaikuCard.js +1 -1
- package/lib/examples/{ag-ui → components}/haiku/index.d.ts +1 -1
- package/lib/examples/{ag-ui → components}/haiku/index.js +1 -1
- package/lib/examples/components/index.d.ts +3 -0
- package/lib/examples/components/index.js +4 -0
- package/lib/examples/{ag-ui → components}/weather/index.d.ts +1 -1
- package/lib/examples/{ag-ui → components}/weather/index.js +1 -1
- package/lib/examples/example-selector.d.ts +17 -4
- package/lib/examples/example-selector.js +108 -41
- package/lib/examples/index.d.ts +10 -6
- package/lib/examples/index.js +10 -6
- package/lib/examples/lexical/initial-content.json +6 -6
- package/lib/examples/main.js +257 -27
- package/lib/examples/utils/a2ui.d.ts +18 -0
- package/lib/examples/utils/a2ui.js +69 -0
- package/lib/examples/utils/a2uiMarkdownProvider.d.ts +7 -0
- package/lib/examples/utils/a2uiMarkdownProvider.js +9 -0
- package/lib/examples/utils/agentId.d.ts +18 -0
- package/lib/examples/utils/agentId.js +54 -0
- package/lib/examples/utils/agents/earthquake-detector.json +11 -11
- package/lib/examples/utils/agents/sales-forecaster.json +11 -11
- package/lib/examples/utils/agents/social-post-generator.json +11 -11
- package/lib/examples/utils/agents/stock-market.json +11 -11
- package/lib/examples/utils/examplesStore.js +82 -27
- package/lib/examples/utils/useExampleAgentRuntimesUrl.d.ts +5 -0
- package/lib/examples/utils/useExampleAgentRuntimesUrl.js +19 -0
- package/lib/hooks/index.d.ts +8 -8
- package/lib/hooks/index.js +7 -7
- package/lib/hooks/useA2A.d.ts +2 -3
- package/lib/hooks/useAIAgentsWebSocket.d.ts +43 -4
- package/lib/hooks/useAIAgentsWebSocket.js +153 -12
- package/lib/hooks/useAcp.d.ts +1 -2
- package/lib/hooks/useAgUi.d.ts +1 -1
- package/lib/hooks/{useAgents.d.ts → useAgentRuntimes.d.ts} +70 -4
- package/lib/hooks/{useAgents.js → useAgentRuntimes.js} +237 -32
- package/lib/hooks/useAgentsCatalog.js +1 -1
- package/lib/hooks/useAgentsService.d.ts +2 -2
- package/lib/hooks/useAgentsService.js +7 -7
- package/lib/hooks/useCheckpoints.js +1 -1
- package/lib/hooks/useConfig.d.ts +4 -1
- package/lib/hooks/useConfig.js +10 -3
- package/lib/hooks/useContextSnapshot.d.ts +9 -4
- package/lib/hooks/useContextSnapshot.js +9 -37
- package/lib/hooks/useMonitoring.js +3 -0
- package/lib/hooks/useSandbox.d.ts +20 -8
- package/lib/hooks/useSandbox.js +105 -40
- package/lib/hooks/useSkills.d.ts +23 -5
- package/lib/hooks/useSkills.js +94 -39
- package/lib/hooks/useToolApprovals.d.ts +60 -36
- package/lib/hooks/useToolApprovals.js +318 -69
- package/lib/hooks/useVercelAI.d.ts +1 -1
- package/lib/index.d.ts +2 -1
- package/lib/index.js +1 -0
- package/lib/inference/index.d.ts +0 -1
- package/lib/middleware/index.d.ts +0 -1
- package/lib/protocols/AGUIAdapter.js +6 -0
- package/lib/protocols/VercelAIAdapter.d.ts +7 -0
- package/lib/protocols/VercelAIAdapter.js +59 -7
- package/lib/specs/agents/agents.d.ts +21 -4
- package/lib/specs/agents/agents.js +2879 -316
- package/lib/specs/agents/index.js +3 -1
- package/lib/specs/benchmarks.d.ts +20 -0
- package/lib/specs/benchmarks.js +205 -0
- package/lib/specs/envvars.js +27 -20
- package/lib/specs/evals.d.ts +10 -9
- package/lib/specs/evals.js +128 -88
- package/lib/specs/events.d.ts +3 -10
- package/lib/specs/events.js +127 -84
- package/lib/specs/frontendTools.js +2 -2
- package/lib/specs/guardrails.d.ts +0 -7
- package/lib/specs/guardrails.js +240 -159
- package/lib/specs/mcpServers.js +35 -6
- package/lib/specs/memory.d.ts +0 -2
- package/lib/specs/memory.js +4 -17
- package/lib/specs/models.d.ts +0 -2
- package/lib/specs/models.js +20 -15
- package/lib/specs/notifications.js +102 -18
- package/lib/specs/outputs.js +15 -9
- package/lib/specs/personas.d.ts +41 -0
- package/lib/specs/personas.js +168 -0
- package/lib/specs/skills.d.ts +1 -1
- package/lib/specs/skills.js +23 -23
- package/lib/specs/teams/index.js +3 -1
- package/lib/specs/teams/teams.js +468 -348
- package/lib/specs/tools.js +4 -4
- package/lib/specs/triggers.js +61 -11
- package/lib/stores/agentRuntimeStore.d.ts +208 -0
- package/lib/stores/agentRuntimeStore.js +650 -0
- package/lib/stores/conversationStore.js +2 -2
- package/lib/stores/index.d.ts +1 -1
- package/lib/stores/index.js +1 -1
- package/lib/tools/adapters/copilotkit/lexicalHooks.d.ts +1 -2
- package/lib/tools/adapters/copilotkit/lexicalHooks.js +1 -3
- package/lib/tools/adapters/copilotkit/notebookHooks.d.ts +1 -2
- package/lib/tools/adapters/copilotkit/notebookHooks.js +1 -3
- package/lib/tools/index.d.ts +0 -2
- package/lib/tools/index.js +0 -1
- package/lib/types/agents-lifecycle.d.ts +18 -0
- package/lib/types/agents.d.ts +6 -0
- package/lib/types/agentspecs.d.ts +54 -1
- package/lib/types/benchmarks.d.ts +43 -0
- package/lib/types/benchmarks.js +5 -0
- package/lib/types/chat.d.ts +325 -8
- package/lib/types/context.d.ts +27 -0
- package/lib/types/cost.d.ts +2 -2
- package/lib/types/evals.d.ts +26 -17
- package/lib/types/index.d.ts +3 -0
- package/lib/types/index.js +3 -0
- package/lib/types/mcp.d.ts +8 -0
- package/lib/types/models.d.ts +2 -2
- package/lib/types/personas.d.ts +25 -0
- package/lib/types/personas.js +5 -0
- package/lib/types/skills.d.ts +43 -1
- package/lib/types/stream.d.ts +110 -0
- package/lib/types/stream.js +36 -0
- package/lib/utils/utils.d.ts +9 -5
- package/lib/utils/utils.js +9 -5
- package/package.json +19 -11
- package/scripts/codegen/__pycache__/generate_agents.cpython-313.pyc +0 -0
- package/scripts/codegen/__pycache__/generate_benchmarks.cpython-313.pyc +0 -0
- package/scripts/codegen/__pycache__/generate_evals.cpython-313.pyc +0 -0
- package/scripts/codegen/__pycache__/generate_events.cpython-313.pyc +0 -0
- package/scripts/codegen/__pycache__/versioning.cpython-313.pyc +0 -0
- package/scripts/codegen/generate_agents.py +187 -45
- package/scripts/codegen/generate_benchmarks.py +441 -0
- package/scripts/codegen/generate_evals.py +94 -16
- package/scripts/codegen/generate_events.py +35 -14
- package/scripts/codegen/generate_personas.py +319 -0
- package/scripts/codegen/generate_skills.py +9 -9
- package/scripts/sync-jupyter.sh +26 -7
- package/lib/api/tool-approvals.d.ts +0 -62
- package/lib/api/tool-approvals.js +0 -145
- package/lib/examples/AgentspecExample.js +0 -705
- package/lib/examples/LexicalSidebarExample.js +0 -163
- package/lib/examples/NotebookSidebarExample.js +0 -119
- package/lib/examples/NotebookSimpleExample.d.ts +0 -6
- package/lib/examples/NotebookSimpleExample.js +0 -22
- package/lib/examples/ag-ui/index.d.ts +0 -10
- package/lib/examples/ag-ui/index.js +0 -16
- package/lib/hooks/useAgentsRegistry.d.ts +0 -10
- package/lib/hooks/useAgentsRegistry.js +0 -20
- package/lib/stores/agentsStore.d.ts +0 -123
- package/lib/stores/agentsStore.js +0 -270
- /package/lib/examples/{ag-ui → components}/haiku/HaikuDisplay.d.ts +0 -0
- /package/lib/examples/{ag-ui → components}/haiku/InlineHaikuCard.d.ts +0 -0
- /package/lib/examples/{ag-ui → components}/weather/InlineWeatherCard.d.ts +0 -0
- /package/lib/examples/{ag-ui → components}/weather/InlineWeatherCard.js +0 -0
|
@@ -18,41 +18,213 @@ 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, Heading, Label, Flash, ProgressBar, } from '@primer/react';
|
|
21
|
-
import { ShieldCheckIcon, CheckIcon, XIcon,
|
|
21
|
+
import { ShieldCheckIcon, CheckIcon, XIcon, DotFillIcon, } from '@primer/octicons-react';
|
|
22
22
|
import { Box } from '@datalayer/primer-addons';
|
|
23
|
-
import {
|
|
23
|
+
import { buildOtelWebSocketUrl } from '@datalayer/core/lib/otel';
|
|
24
|
+
import { useCoreStore } from '@datalayer/core/lib/state';
|
|
25
|
+
import { AuthRequiredView, ErrorView } from './components';
|
|
24
26
|
import { ThemedProvider } from './utils/themedProvider';
|
|
27
|
+
import { uniqueAgentId } from './utils/agentId';
|
|
28
|
+
import { parseAgentStreamMessage } from '../types/stream';
|
|
29
|
+
import { getAgentSpecs } from '../specs/agents';
|
|
30
|
+
import { subscribeOtelWs } from '../context/otelWsPool';
|
|
31
|
+
import { toMetricValue } from '../hooks/useMonitoring';
|
|
32
|
+
import { useAIAgentsWebSocket } from '../hooks';
|
|
25
33
|
const queryClient = new QueryClient();
|
|
26
34
|
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
35
|
import { Chat } from '../chat';
|
|
30
|
-
import { useAgents } from '../hooks/useAgents';
|
|
31
36
|
// ─── Constants ─────────────────────────────────────────────────────────────
|
|
32
|
-
const AGENT_NAME = 'guardrails-
|
|
33
|
-
const AGENT_SPEC_ID = '
|
|
34
|
-
const
|
|
37
|
+
const AGENT_NAME = 'guardrails-example-agent';
|
|
38
|
+
const AGENT_SPEC_ID = 'example-guardrails';
|
|
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;
|
|
42
|
+
const OTEL_SERVICE_NAME = 'agent-runtimes';
|
|
43
|
+
const COST_RUN_METRIC = 'agent_runtimes.capability.cost.run.usd';
|
|
44
|
+
const COST_CUMULATIVE_METRIC = 'agent_runtimes.capability.cost.cumulative.usd';
|
|
45
|
+
const toNumberOrNull = (value) => {
|
|
46
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
47
|
+
return value;
|
|
48
|
+
}
|
|
49
|
+
if (typeof value === 'string' && value.trim().length > 0) {
|
|
50
|
+
const parsed = Number(value);
|
|
51
|
+
if (Number.isFinite(parsed)) {
|
|
52
|
+
return parsed;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
};
|
|
57
|
+
const resolvePerRunBudgetFromSpec = (agentSpecId) => {
|
|
58
|
+
const spec = getAgentSpecs(agentSpecId);
|
|
59
|
+
if (!spec?.guardrails?.length) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
for (const guardrail of spec.guardrails) {
|
|
63
|
+
if (!guardrail || typeof guardrail !== 'object') {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const costBudget = guardrail.cost_budget;
|
|
67
|
+
if (!costBudget || typeof costBudget !== 'object') {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
const perRunUsd = toNumberOrNull(costBudget.per_run_usd);
|
|
71
|
+
if (perRunUsd != null) {
|
|
72
|
+
return perRunUsd;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
};
|
|
77
|
+
const DEFAULT_RUN_BUDGET_USD = resolvePerRunBudgetFromSpec(AGENT_SPEC_ID);
|
|
78
|
+
const toApprovalRequest = (payload) => ({
|
|
79
|
+
id: payload.id,
|
|
80
|
+
tool_name: payload.tool_name,
|
|
81
|
+
tool_args: payload.tool_args ?? {},
|
|
82
|
+
created_at: payload.created_at ?? new Date().toISOString(),
|
|
83
|
+
});
|
|
84
|
+
const normalizeBaseUrl = (rawBaseUrl) => {
|
|
85
|
+
if (rawBaseUrl.startsWith('http://') ||
|
|
86
|
+
rawBaseUrl.startsWith('https://') ||
|
|
87
|
+
rawBaseUrl.startsWith('ws://') ||
|
|
88
|
+
rawBaseUrl.startsWith('wss://')) {
|
|
89
|
+
return rawBaseUrl;
|
|
90
|
+
}
|
|
91
|
+
const protocol = typeof window !== 'undefined' && window.location.protocol === 'https:'
|
|
92
|
+
? 'https:'
|
|
93
|
+
: 'http:';
|
|
94
|
+
const host = typeof window !== 'undefined' ? window.location.host : '';
|
|
95
|
+
return `${protocol}//${host}${rawBaseUrl}`;
|
|
96
|
+
};
|
|
97
|
+
const parseAttributes = (attrs) => {
|
|
98
|
+
if (attrs && typeof attrs === 'object' && !Array.isArray(attrs)) {
|
|
99
|
+
return attrs;
|
|
100
|
+
}
|
|
101
|
+
if (typeof attrs === 'string') {
|
|
102
|
+
try {
|
|
103
|
+
return JSON.parse(attrs);
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
return {};
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return {};
|
|
110
|
+
};
|
|
111
|
+
const extractServiceName = (row) => {
|
|
112
|
+
const directCandidates = [row.service_name, row.service, row.serviceName];
|
|
113
|
+
for (const candidate of directCandidates) {
|
|
114
|
+
if (typeof candidate === 'string' && candidate.length > 0) {
|
|
115
|
+
return candidate;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
const resourceAttributes = row.resource_attributes;
|
|
119
|
+
if (resourceAttributes && typeof resourceAttributes === 'object') {
|
|
120
|
+
const nested = resourceAttributes['service.name'];
|
|
121
|
+
if (typeof nested === 'string' && nested.length > 0) {
|
|
122
|
+
return nested;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return undefined;
|
|
126
|
+
};
|
|
127
|
+
const extractAgentId = (row) => {
|
|
128
|
+
const attrs = parseAttributes(row.attributes);
|
|
129
|
+
const aid = attrs['agent.id'];
|
|
130
|
+
return typeof aid === 'string' ? aid : undefined;
|
|
131
|
+
};
|
|
132
|
+
const rowTimestampMs = (row) => {
|
|
133
|
+
const nanoTs = row.timestamp_unix_nano ?? row.observed_timestamp_unix_nano;
|
|
134
|
+
if (typeof nanoTs === 'number' && nanoTs > 0) {
|
|
135
|
+
return nanoTs / 1_000_000;
|
|
136
|
+
}
|
|
137
|
+
if (typeof nanoTs === 'string' && nanoTs.length > 0) {
|
|
138
|
+
const parsed = Number(nanoTs);
|
|
139
|
+
if (Number.isFinite(parsed) && parsed > 0) {
|
|
140
|
+
return parsed / 1_000_000;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
const isoTs = row.timestamp;
|
|
144
|
+
if (typeof isoTs === 'string' && isoTs.length > 0) {
|
|
145
|
+
const ms = new Date(isoTs).getTime();
|
|
146
|
+
if (Number.isFinite(ms) && ms > 0) {
|
|
147
|
+
return ms;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return 0;
|
|
151
|
+
};
|
|
152
|
+
const selectLatestOtelCost = (rows, agentId) => {
|
|
153
|
+
const filtered = rows.filter(row => {
|
|
154
|
+
const metricName = row.metric_name;
|
|
155
|
+
if (metricName !== COST_RUN_METRIC &&
|
|
156
|
+
metricName !== COST_CUMULATIVE_METRIC) {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
if (extractServiceName(row) !== OTEL_SERVICE_NAME) {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
return extractAgentId(row) === agentId;
|
|
163
|
+
});
|
|
164
|
+
if (filtered.length === 0) {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
let latestTimestampMs = 0;
|
|
168
|
+
let runUsd = 0;
|
|
169
|
+
let cumulativeUsd = 0;
|
|
170
|
+
for (const row of filtered) {
|
|
171
|
+
const ts = rowTimestampMs(row);
|
|
172
|
+
if (!Number.isFinite(ts) || ts <= 0) {
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
if (ts > latestTimestampMs) {
|
|
176
|
+
latestTimestampMs = ts;
|
|
177
|
+
runUsd = 0;
|
|
178
|
+
cumulativeUsd = 0;
|
|
179
|
+
}
|
|
180
|
+
if (ts !== latestTimestampMs) {
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
const value = Math.max(0, toMetricValue(row));
|
|
184
|
+
if (row.metric_name === COST_RUN_METRIC) {
|
|
185
|
+
runUsd += value;
|
|
186
|
+
}
|
|
187
|
+
else if (row.metric_name === COST_CUMULATIVE_METRIC) {
|
|
188
|
+
cumulativeUsd = Math.max(cumulativeUsd, value);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
if (latestTimestampMs <= 0) {
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
return {
|
|
195
|
+
timestampMs: latestTimestampMs,
|
|
196
|
+
runUsd,
|
|
197
|
+
cumulativeUsd,
|
|
198
|
+
};
|
|
199
|
+
};
|
|
35
200
|
// ─── Inner component (rendered after auth) ─────────────────────────────────
|
|
36
201
|
const AgentGuardrailsInner = ({ onLogout, }) => {
|
|
37
202
|
const { token } = useSimpleAuthStore();
|
|
38
|
-
const {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
},
|
|
46
|
-
});
|
|
203
|
+
const { configuration } = useCoreStore();
|
|
204
|
+
const agentName = useRef(uniqueAgentId(AGENT_NAME)).current;
|
|
205
|
+
const [runtimeStatus, setRuntimeStatus] = useState('launching');
|
|
206
|
+
const [isReady, setIsReady] = useState(false);
|
|
207
|
+
const [hookError, setHookError] = useState(null);
|
|
208
|
+
const [agentId, setAgentId] = useState(agentName);
|
|
209
|
+
const [isReconnectedAgent, setIsReconnectedAgent] = useState(false);
|
|
47
210
|
// Cost tracking
|
|
48
|
-
const [
|
|
211
|
+
const [snapshotRunCostUsd, setSnapshotRunCostUsd] = useState(0);
|
|
212
|
+
const [runBudgetUsd, setRunBudgetUsd] = useState(DEFAULT_RUN_BUDGET_USD);
|
|
49
213
|
const [totalTokens, setTotalTokens] = useState(0);
|
|
214
|
+
const [otelRunCostUsd, setOtelRunCostUsd] = useState(null);
|
|
215
|
+
const [otelCumulativeCostUsd, setOtelCumulativeCostUsd] = useState(null);
|
|
216
|
+
const [otelSampleTimestamp, setOtelSampleTimestamp] = useState(null);
|
|
50
217
|
// Tool approval queue
|
|
51
218
|
const [approvals, setApprovals] = useState([]);
|
|
52
219
|
const [approvalLoading, setApprovalLoading] = useState(null);
|
|
53
|
-
const agentBaseUrl =
|
|
54
|
-
const
|
|
55
|
-
|
|
220
|
+
const agentBaseUrl = DEFAULT_LOCAL_BASE_URL;
|
|
221
|
+
const otelBaseUrl = configuration?.otelRunUrl ||
|
|
222
|
+
configuration?.runUrl ||
|
|
223
|
+
OTEL_BASE_URL_ENV ||
|
|
224
|
+
DATALAYER_RUN_URL_ENV ||
|
|
225
|
+
'https://prod1.datalayer.run';
|
|
226
|
+
const podName = agentId;
|
|
227
|
+
const chatAuthToken = token === null ? undefined : token;
|
|
56
228
|
// Authenticated fetch helper (for sidecar endpoints)
|
|
57
229
|
const authFetch = useCallback((url, opts = {}) => fetch(url, {
|
|
58
230
|
...opts,
|
|
@@ -62,46 +234,158 @@ const AgentGuardrailsInner = ({ onLogout, }) => {
|
|
|
62
234
|
...(opts.headers ?? {}),
|
|
63
235
|
},
|
|
64
236
|
}), [token]);
|
|
65
|
-
// ── Poll cost + tool approvals ───────────────────────────────────────────
|
|
66
237
|
useEffect(() => {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
238
|
+
let isCancelled = false;
|
|
239
|
+
const createLocalAgent = async () => {
|
|
240
|
+
setRuntimeStatus('launching');
|
|
241
|
+
setIsReady(false);
|
|
242
|
+
setHookError(null);
|
|
243
|
+
setIsReconnectedAgent(false);
|
|
70
244
|
try {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
245
|
+
const response = await authFetch(`${agentBaseUrl}/api/v1/agents`, {
|
|
246
|
+
method: 'POST',
|
|
247
|
+
body: JSON.stringify({
|
|
248
|
+
name: agentName,
|
|
249
|
+
description: 'Agent with cost budget and tool approval guardrails',
|
|
250
|
+
agent_library: 'pydantic-ai',
|
|
251
|
+
transport: 'vercel-ai',
|
|
252
|
+
agent_spec_id: AGENT_SPEC_ID,
|
|
253
|
+
enable_skills: true,
|
|
254
|
+
tools: [],
|
|
255
|
+
}),
|
|
256
|
+
});
|
|
257
|
+
let resolvedAgentId = agentName;
|
|
258
|
+
let isAlreadyRunning = false;
|
|
259
|
+
if (response.ok) {
|
|
260
|
+
const data = await response.json();
|
|
261
|
+
resolvedAgentId = data?.id || agentName;
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
const contentType = response.headers.get('content-type') || '';
|
|
265
|
+
let detail = '';
|
|
266
|
+
if (contentType.includes('application/json')) {
|
|
267
|
+
const data = await response.json().catch(() => null);
|
|
268
|
+
detail =
|
|
269
|
+
(typeof data?.detail === 'string' && data.detail) ||
|
|
270
|
+
(typeof data?.message === 'string' && data.message) ||
|
|
271
|
+
'';
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
detail = await response.text();
|
|
275
|
+
}
|
|
276
|
+
if (response.status === 409 || /already exists/i.test(detail || '')) {
|
|
277
|
+
isAlreadyRunning = true;
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
throw new Error(detail || `Failed to create local agent: ${response.status}`);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
if (!isCancelled) {
|
|
284
|
+
setAgentId(resolvedAgentId);
|
|
285
|
+
setIsReconnectedAgent(isAlreadyRunning);
|
|
286
|
+
setIsReady(true);
|
|
287
|
+
setRuntimeStatus('ready');
|
|
77
288
|
}
|
|
78
289
|
}
|
|
79
|
-
catch {
|
|
80
|
-
|
|
290
|
+
catch (error) {
|
|
291
|
+
if (!isCancelled) {
|
|
292
|
+
setHookError(error instanceof Error ? error.message : 'Agent failed to start');
|
|
293
|
+
setRuntimeStatus('error');
|
|
294
|
+
}
|
|
81
295
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
296
|
+
};
|
|
297
|
+
void createLocalAgent();
|
|
298
|
+
return () => {
|
|
299
|
+
isCancelled = true;
|
|
300
|
+
};
|
|
301
|
+
}, [agentBaseUrl, agentName, authFetch]);
|
|
302
|
+
const handleGuardrailsStreamMessage = useCallback((message) => {
|
|
303
|
+
try {
|
|
304
|
+
const stream = parseAgentStreamMessage(message?.raw ?? message);
|
|
305
|
+
if (!stream) {
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
if (stream.type === 'agent.snapshot') {
|
|
309
|
+
const payload = stream.payload;
|
|
310
|
+
setApprovals((payload.approvals ?? []).map(toApprovalRequest));
|
|
311
|
+
const snapshotCost = payload.contextSnapshot?.costUsage ?? payload.costUsage;
|
|
312
|
+
if (snapshotCost) {
|
|
313
|
+
setSnapshotRunCostUsd(Number(snapshotCost.cumulativeCostUsd ??
|
|
314
|
+
snapshotCost.lastTurnCostUsd ??
|
|
315
|
+
0));
|
|
316
|
+
setRunBudgetUsd(prev => snapshotCost.perRunBudgetUsd == null
|
|
317
|
+
? (prev ?? DEFAULT_RUN_BUDGET_USD)
|
|
318
|
+
: Number(snapshotCost.perRunBudgetUsd));
|
|
319
|
+
setTotalTokens(Number(snapshotCost.totalTokensUsed ?? 0));
|
|
88
320
|
}
|
|
321
|
+
return;
|
|
89
322
|
}
|
|
90
|
-
|
|
91
|
-
|
|
323
|
+
if (stream.type === 'tool_approval_created') {
|
|
324
|
+
const approval = toApprovalRequest(stream.payload);
|
|
325
|
+
setApprovals(prev => {
|
|
326
|
+
const next = prev.filter(item => item.id !== approval.id);
|
|
327
|
+
next.unshift(approval);
|
|
328
|
+
return next;
|
|
329
|
+
});
|
|
330
|
+
return;
|
|
92
331
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
332
|
+
if (stream.type === 'tool_approval_approved' ||
|
|
333
|
+
stream.type === 'tool_approval_rejected') {
|
|
334
|
+
const approval = stream.payload;
|
|
335
|
+
setApprovals(prev => prev.filter(item => item.id !== approval.id));
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
catch {
|
|
339
|
+
// Ignore malformed stream payloads.
|
|
340
|
+
}
|
|
341
|
+
}, []);
|
|
342
|
+
const approvalSocket = useAIAgentsWebSocket({
|
|
343
|
+
enabled: isReady && Boolean(agentBaseUrl),
|
|
344
|
+
baseUrl: agentBaseUrl,
|
|
345
|
+
path: '/api/v1/tool-approvals/ws',
|
|
346
|
+
queryParams: { agent_id: agentId },
|
|
347
|
+
onMessage: handleGuardrailsStreamMessage,
|
|
348
|
+
reconnectDelayMs: attempt => Math.min(1000 * 2 ** Math.max(0, attempt - 1), 10000),
|
|
349
|
+
});
|
|
350
|
+
const wsState = approvalSocket.connectionState;
|
|
351
|
+
useEffect(() => {
|
|
352
|
+
setOtelRunCostUsd(null);
|
|
353
|
+
setOtelCumulativeCostUsd(null);
|
|
354
|
+
setOtelSampleTimestamp(null);
|
|
355
|
+
if (!isReady || !token) {
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
let wsUrl;
|
|
359
|
+
try {
|
|
360
|
+
wsUrl = buildOtelWebSocketUrl({
|
|
361
|
+
baseUrl: normalizeBaseUrl(otelBaseUrl),
|
|
362
|
+
token,
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
catch {
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
const unsubscribe = subscribeOtelWs(wsUrl, msg => {
|
|
369
|
+
if (msg.signal !== 'metrics' || !Array.isArray(msg.data)) {
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
const sample = selectLatestOtelCost(msg.data, agentId);
|
|
373
|
+
if (!sample) {
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
setOtelRunCostUsd(sample.runUsd);
|
|
377
|
+
setOtelCumulativeCostUsd(sample.cumulativeUsd);
|
|
378
|
+
setOtelSampleTimestamp(sample.timestampMs);
|
|
379
|
+
});
|
|
380
|
+
return unsubscribe;
|
|
381
|
+
}, [agentId, isReady, otelBaseUrl, token]);
|
|
98
382
|
// ── Approve / Reject ─────────────────────────────────────────────────────
|
|
99
383
|
const handleApprove = useCallback(async (requestId) => {
|
|
100
384
|
if (!agentBaseUrl)
|
|
101
385
|
return;
|
|
102
386
|
setApprovalLoading(requestId);
|
|
103
387
|
try {
|
|
104
|
-
await authFetch(`${agentBaseUrl}/api/v1/
|
|
388
|
+
await authFetch(`${agentBaseUrl}/api/v1/tool-approvals/${requestId}/approve`, { method: 'POST' });
|
|
105
389
|
setApprovals(prev => prev.filter(a => a.id !== requestId));
|
|
106
390
|
}
|
|
107
391
|
catch {
|
|
@@ -110,13 +394,13 @@ const AgentGuardrailsInner = ({ onLogout, }) => {
|
|
|
110
394
|
finally {
|
|
111
395
|
setApprovalLoading(null);
|
|
112
396
|
}
|
|
113
|
-
}, [agentBaseUrl,
|
|
397
|
+
}, [agentBaseUrl, authFetch]);
|
|
114
398
|
const handleReject = useCallback(async (requestId) => {
|
|
115
399
|
if (!agentBaseUrl)
|
|
116
400
|
return;
|
|
117
401
|
setApprovalLoading(requestId);
|
|
118
402
|
try {
|
|
119
|
-
await authFetch(`${agentBaseUrl}/api/v1/
|
|
403
|
+
await authFetch(`${agentBaseUrl}/api/v1/tool-approvals/${requestId}/reject`, {
|
|
120
404
|
method: 'POST',
|
|
121
405
|
body: JSON.stringify({ reason: 'User rejected' }),
|
|
122
406
|
});
|
|
@@ -128,7 +412,7 @@ const AgentGuardrailsInner = ({ onLogout, }) => {
|
|
|
128
412
|
finally {
|
|
129
413
|
setApprovalLoading(null);
|
|
130
414
|
}
|
|
131
|
-
}, [agentBaseUrl,
|
|
415
|
+
}, [agentBaseUrl, authFetch]);
|
|
132
416
|
// ── Loading / Error ──────────────────────────────────────────────────────
|
|
133
417
|
if (!isReady && runtimeStatus !== 'error') {
|
|
134
418
|
return (_jsxs(Box, { sx: {
|
|
@@ -138,14 +422,31 @@ const AgentGuardrailsInner = ({ onLogout, }) => {
|
|
|
138
422
|
justifyContent: 'center',
|
|
139
423
|
height: '100vh',
|
|
140
424
|
gap: 3,
|
|
141
|
-
}, children: [_jsx(Spinner, { size: "large" }), _jsx(Text, { sx: { color: 'fg.muted' }, children:
|
|
142
|
-
? 'Launching runtime for guardrails agent…'
|
|
143
|
-
: 'Creating guardrails demo agent…' })] }));
|
|
425
|
+
}, children: [_jsx(Spinner, { size: "large" }), _jsx(Text, { sx: { color: 'fg.muted' }, children: "Launching guardrails example agent..." })] }));
|
|
144
426
|
}
|
|
145
427
|
if (runtimeStatus === 'error' || hookError) {
|
|
146
428
|
return _jsx(ErrorView, { error: hookError, onLogout: onLogout });
|
|
147
429
|
}
|
|
148
|
-
const
|
|
430
|
+
const runCostUsd = Math.max(snapshotRunCostUsd, otelRunCostUsd ?? 0);
|
|
431
|
+
const cumulativeCostUsd = otelCumulativeCostUsd;
|
|
432
|
+
const isOverRunBudget = runBudgetUsd != null && runBudgetUsd > 0 && runCostUsd > runBudgetUsd;
|
|
433
|
+
const runBudgetDisplayUsd = runBudgetUsd != null ? runBudgetUsd.toFixed(2) : '0.00';
|
|
434
|
+
const overBudgetBanner = isOverRunBudget
|
|
435
|
+
? {
|
|
436
|
+
variant: 'danger',
|
|
437
|
+
message: `Run budget exceeded: $${runCostUsd.toFixed(4)} / $${runBudgetDisplayUsd}. Start a new run or adjust the budget before sending more messages.`,
|
|
438
|
+
}
|
|
439
|
+
: undefined;
|
|
440
|
+
const budgetForProgress = runBudgetUsd && runBudgetUsd > 0 ? runBudgetUsd : 1;
|
|
441
|
+
const usagePercentRaw = (runCostUsd / budgetForProgress) * 100;
|
|
442
|
+
const costPercent = Math.min(usagePercentRaw, 100);
|
|
443
|
+
const usageSafePercent = Math.min(costPercent, 50);
|
|
444
|
+
const usageWatchPercent = Math.min(Math.max(costPercent - 50, 0), 30);
|
|
445
|
+
const usageDangerPercent = Math.min(Math.max(costPercent - 80, 0), 20);
|
|
446
|
+
const overBudgetPercent = Math.max(usagePercentRaw - 100, 0);
|
|
447
|
+
const overBudgetAmountUsd = runBudgetUsd != null && runBudgetUsd > 0
|
|
448
|
+
? Math.max(runCostUsd - runBudgetUsd, 0)
|
|
449
|
+
: 0;
|
|
149
450
|
const costColor = costPercent > 80
|
|
150
451
|
? 'danger.fg'
|
|
151
452
|
: costPercent > 50
|
|
@@ -164,16 +465,37 @@ const AgentGuardrailsInner = ({ onLogout, }) => {
|
|
|
164
465
|
borderBottom: '1px solid',
|
|
165
466
|
borderColor: 'border.default',
|
|
166
467
|
flexShrink: 0,
|
|
167
|
-
}, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1 }, children: [_jsx(ShieldCheckIcon, { size: 16 }), _jsxs(Heading, { as: "h3", sx: { fontSize: 2 }, children: ["Guardrails Demo \u2014 ", podName] })] }), _jsxs(Box, { sx: { flex: 1, maxWidth: 300 }, children: [_jsxs(Box, { sx: {
|
|
468
|
+
}, children: [isReconnectedAgent && (_jsx(Label, { variant: "secondary", size: "small", children: "Reconnected" })), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1 }, children: [_jsx(ShieldCheckIcon, { size: 16 }), _jsxs(Heading, { as: "h3", sx: { fontSize: 2 }, children: ["Guardrails Demo \u2014 ", podName] })] }), _jsx(Label, { variant: wsState === 'connected' ? 'success' : 'secondary', children: wsState }), _jsxs(Box, { sx: { flex: 1, maxWidth: 300 }, children: [_jsxs(Box, { sx: {
|
|
168
469
|
display: 'flex',
|
|
169
470
|
justifyContent: 'space-between',
|
|
170
471
|
fontSize: 0,
|
|
171
472
|
mb: 1,
|
|
172
|
-
}, children: [_jsxs(Text, { sx: { color: costColor, fontWeight: 'semibold' }, children: ["$",
|
|
173
|
-
|
|
174
|
-
|
|
473
|
+
}, children: [_jsxs(Text, { sx: { color: costColor, fontWeight: 'semibold' }, children: ["$", runCostUsd.toFixed(4)] }), _jsx(Text, { sx: { color: 'fg.muted' }, children: runBudgetUsd != null
|
|
474
|
+
? ` / $${runBudgetUsd.toFixed(2)} run budget`
|
|
475
|
+
: ' / no run budget' })] }), _jsxs(ProgressBar, { "aria-label": "Run budget usage", "aria-valuenow": Math.max(0, costPercent), sx: { height: 6 }, children: [_jsx(ProgressBar.Item, { progress: usageSafePercent, style: { backgroundColor: 'var(--bgColor-success-emphasis)' }, "aria-label": `Healthy usage ${usageSafePercent.toFixed(1)}%` }), _jsx(ProgressBar.Item, { progress: usageWatchPercent, style: { backgroundColor: 'var(--bgColor-accent-emphasis)' }, "aria-label": `Watch usage ${usageWatchPercent.toFixed(1)}%` }), _jsx(ProgressBar.Item, { progress: usageDangerPercent, style: { backgroundColor: 'var(--bgColor-danger-emphasis)' }, "aria-label": `Critical usage ${usageDangerPercent.toFixed(1)}%` })] }), _jsxs(Box, { sx: {
|
|
476
|
+
display: 'flex',
|
|
477
|
+
alignItems: 'center',
|
|
478
|
+
gap: 2,
|
|
479
|
+
flexWrap: 'wrap',
|
|
480
|
+
mt: 1,
|
|
481
|
+
}, role: "presentation", children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1 }, children: [_jsx(DotFillIcon, { size: 12, fill: "var(--bgColor-success-emphasis)" }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "0-50%" })] }), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1 }, children: [_jsx(DotFillIcon, { size: 12, fill: "var(--bgColor-accent-emphasis)" }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "50-80%" })] }), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1 }, children: [_jsx(DotFillIcon, { size: 12, fill: "var(--bgColor-danger-emphasis)" }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "80-100%" })] }), overBudgetPercent > 0 && (_jsxs(Label, { variant: "danger", size: "small", children: ["+", overBudgetPercent.toFixed(1), "% over"] }))] })] }), _jsxs(Label, { variant: otelSampleTimestamp == null ? 'secondary' : 'success', children: ["OTEL ", otelSampleTimestamp == null ? 'waiting' : 'live'] }), cumulativeCostUsd != null && (_jsxs(Label, { variant: "secondary", children: ["Total $", cumulativeCostUsd.toFixed(4)] })), _jsxs(Label, { variant: "secondary", children: [totalTokens.toLocaleString(), " tokens"] })] }), isOverRunBudget && (_jsx(Flash, { variant: "danger", sx: { mx: 3, mt: 2 }, children: _jsxs(Text, { sx: { fontSize: 1 }, children: [_jsx("strong", { children: "Run budget exceeded." }), " Current run cost is $", runCostUsd.toFixed(4), " against a budget of $", runBudgetDisplayUsd, overBudgetAmountUsd > 0
|
|
482
|
+
? ` (over by $${overBudgetAmountUsd.toFixed(4)}).`
|
|
483
|
+
: '.', ' ', "Start a new run or increase the run budget before continuing."] }) })), approvals.map(req => (_jsx(Flash, { variant: "warning", sx: { mx: 3, mt: 2 }, children: _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsxs(Text, { sx: { flex: 1, fontSize: 1 }, children: [_jsx("strong", { children: req.tool_name }), " requests approval", req.tool_args
|
|
484
|
+
? ` — ${JSON.stringify(req.tool_args).slice(0, 120)}`
|
|
485
|
+
: ''] }), _jsx(Button, { size: "small", variant: "primary", leadingVisual: CheckIcon, onClick: () => handleApprove(req.id), disabled: approvalLoading === req.id, children: "Approve" }), _jsx(Button, { size: "small", variant: "danger", leadingVisual: XIcon, onClick: () => handleReject(req.id), disabled: approvalLoading === req.id, children: "Reject" })] }) }, req.id))), _jsx(Box, { sx: { flex: 1, minHeight: 0 }, children: _jsx(Chat, { protocol: "vercel-ai", baseUrl: agentBaseUrl, agentId: agentId, authToken: chatAuthToken, title: "Guardrails Agent", brandIcon: _jsx(ShieldCheckIcon, { size: 16 }), placeholder: "Ask something that triggers tools\u2026", description: "Cost guardrail with OTEL-backed gauge and hook-aware approvals (before_tool_execute, after_tool_execute, on_tool_execute_error, deferred_tool_calls)", showHeader: false, showTokenUsage: true, errorBanner: overBudgetBanner, disableInputPrompt: isOverRunBudget, autoFocus: true, height: "100%", runtimeId: agentId, historyEndpoint: `${agentBaseUrl}/api/v1/history`, suggestions: [
|
|
175
486
|
{ title: 'Update CRM', message: 'Update the CRM records for Q3' },
|
|
176
|
-
{
|
|
487
|
+
{
|
|
488
|
+
title: 'Trigger before_tool_execute',
|
|
489
|
+
message: "Call runtime_sensitive_echo with text 'hello' and reason 'audit', then explain the before_tool_execute authorization decision.",
|
|
490
|
+
},
|
|
491
|
+
{
|
|
492
|
+
title: 'Trigger deny policy',
|
|
493
|
+
message: "Call runtime_sensitive_echo with text 'danger' and reason 'delete CRM rows', then explain why policy denied it.",
|
|
494
|
+
},
|
|
495
|
+
{
|
|
496
|
+
title: 'Explain deferred flow',
|
|
497
|
+
message: 'Explain how deferred_tool_calls and manual approvals interact in this guardrails run.',
|
|
498
|
+
},
|
|
177
499
|
], submitOnSuggestionClick: true }) })] }));
|
|
178
500
|
};
|
|
179
501
|
// ─── Sync token to core IAM store ──────────────────────────────────────────
|
|
@@ -184,7 +506,7 @@ const syncTokenToIamStore = (token) => {
|
|
|
184
506
|
};
|
|
185
507
|
// ─── Main component with auth gate ─────────────────────────────────────────
|
|
186
508
|
const AgentGuardrailsExample = () => {
|
|
187
|
-
const { token,
|
|
509
|
+
const { token, clearAuth } = useSimpleAuthStore();
|
|
188
510
|
const hasSynced = useRef(false);
|
|
189
511
|
useEffect(() => {
|
|
190
512
|
if (token && !hasSynced.current) {
|
|
@@ -192,11 +514,6 @@ const AgentGuardrailsExample = () => {
|
|
|
192
514
|
syncTokenToIamStore(token);
|
|
193
515
|
}
|
|
194
516
|
}, [token]);
|
|
195
|
-
const handleSignIn = useCallback((newToken, handle) => {
|
|
196
|
-
setAuth(newToken, handle);
|
|
197
|
-
hasSynced.current = true;
|
|
198
|
-
syncTokenToIamStore(newToken);
|
|
199
|
-
}, [setAuth]);
|
|
200
517
|
const handleLogout = useCallback(() => {
|
|
201
518
|
clearAuth();
|
|
202
519
|
hasSynced.current = false;
|
|
@@ -205,7 +522,7 @@ const AgentGuardrailsExample = () => {
|
|
|
205
522
|
});
|
|
206
523
|
}, [clearAuth]);
|
|
207
524
|
if (!token) {
|
|
208
|
-
return (_jsx(ThemedProvider, { children: _jsx(
|
|
525
|
+
return (_jsx(ThemedProvider, { children: _jsx(AuthRequiredView, {}) }));
|
|
209
526
|
}
|
|
210
527
|
return (_jsx(QueryClientProvider, { client: queryClient, children: _jsx(ThemedProvider, { children: _jsx(AgentGuardrailsInner, { onLogout: handleLogout }) }) }));
|
|
211
528
|
};
|