@datalayer/agent-runtimes 1.0.3 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (275) hide show
  1. package/README.md +35 -119
  2. package/lib/App.js +1 -1
  3. package/lib/agents/AgentDetails.d.ts +22 -1
  4. package/lib/agents/AgentDetails.js +34 -47
  5. package/lib/api/index.d.ts +0 -1
  6. package/lib/api/index.js +4 -2
  7. package/lib/chat/Chat.d.ts +5 -104
  8. package/lib/chat/Chat.js +4 -4
  9. package/lib/chat/ChatFloating.d.ts +7 -140
  10. package/lib/chat/ChatFloating.js +2 -2
  11. package/lib/chat/ChatPopupStandalone.d.ts +8 -47
  12. package/lib/chat/ChatPopupStandalone.js +3 -3
  13. package/lib/chat/ChatSidebar.d.ts +4 -69
  14. package/lib/chat/ChatSidebar.js +2 -2
  15. package/lib/chat/ChatStandalone.d.ts +4 -54
  16. package/lib/chat/ChatStandalone.js +3 -3
  17. package/lib/chat/base/ChatBase.js +1118 -141
  18. package/lib/chat/header/ChatHeaderBase.d.ts +11 -6
  19. package/lib/chat/header/ChatHeaderBase.js +18 -16
  20. package/lib/chat/indicators/McpStatusIndicator.d.ts +7 -4
  21. package/lib/chat/indicators/McpStatusIndicator.js +7 -32
  22. package/lib/chat/indicators/SandboxStatusIndicator.d.ts +4 -1
  23. package/lib/chat/indicators/SandboxStatusIndicator.js +9 -9
  24. package/lib/chat/indicators/SkillsStatusIndicator.d.ts +7 -0
  25. package/lib/chat/indicators/SkillsStatusIndicator.js +88 -0
  26. package/lib/chat/indicators/index.d.ts +1 -0
  27. package/lib/chat/indicators/index.js +1 -0
  28. package/lib/chat/messages/ChatMessageList.d.ts +1 -1
  29. package/lib/chat/messages/ChatMessageList.js +110 -102
  30. package/lib/chat/prompt/InputFooter.d.ts +19 -6
  31. package/lib/chat/prompt/InputFooter.js +71 -18
  32. package/lib/chat/prompt/InputPrompt.d.ts +3 -1
  33. package/lib/chat/prompt/InputPrompt.js +4 -4
  34. package/lib/chat/prompt/InputPromptFooter.js +1 -1
  35. package/lib/chat/prompt/InputPromptLexical.d.ts +3 -1
  36. package/lib/chat/prompt/InputPromptLexical.js +12 -5
  37. package/lib/chat/prompt/InputPromptText.d.ts +3 -1
  38. package/lib/chat/prompt/InputPromptText.js +2 -2
  39. package/lib/chat/tools/ToolApprovalBanner.js +1 -1
  40. package/lib/chat/tools/ToolCallDisplay.d.ts +3 -1
  41. package/lib/chat/tools/ToolCallDisplay.js +2 -2
  42. package/lib/chat/usage/TokenUsageBar.js +20 -2
  43. package/lib/client/AgentRuntimesClientContext.d.ts +53 -0
  44. package/lib/client/AgentRuntimesClientContext.js +55 -0
  45. package/lib/client/AgentsMixin.d.ts +48 -19
  46. package/lib/client/AgentsMixin.js +115 -30
  47. package/lib/client/IAgentRuntimesClient.d.ts +215 -0
  48. package/lib/client/IAgentRuntimesClient.js +5 -0
  49. package/lib/client/SdkAgentRuntimesClient.d.ts +151 -0
  50. package/lib/client/SdkAgentRuntimesClient.js +134 -0
  51. package/lib/client/index.d.ts +4 -1
  52. package/lib/client/index.js +3 -1
  53. package/lib/components/NotificationEventCard.js +55 -26
  54. package/lib/components/OutputCard.js +21 -7
  55. package/lib/components/ToolApprovalCard.js +20 -2
  56. package/lib/config/AgentConfiguration.js +3 -3
  57. package/lib/context/ContextDistribution.d.ts +3 -1
  58. package/lib/context/ContextDistribution.js +8 -27
  59. package/lib/context/ContextInspector.d.ts +3 -1
  60. package/lib/context/ContextInspector.js +19 -67
  61. package/lib/context/ContextPanel.d.ts +3 -1
  62. package/lib/context/ContextPanel.js +104 -64
  63. package/lib/context/ContextUsage.d.ts +3 -1
  64. package/lib/context/ContextUsage.js +3 -3
  65. package/lib/context/CostTracker.d.ts +9 -3
  66. package/lib/context/CostTracker.js +26 -47
  67. package/lib/context/CostUsageChart.d.ts +12 -0
  68. package/lib/context/CostUsageChart.js +378 -0
  69. package/lib/context/GraphFlowChart.d.ts +16 -0
  70. package/lib/context/GraphFlowChart.js +182 -0
  71. package/lib/context/TokenUsageChart.d.ts +8 -1
  72. package/lib/context/TokenUsageChart.js +349 -211
  73. package/lib/context/TurnGraphChart.d.ts +39 -0
  74. package/lib/context/TurnGraphChart.js +538 -0
  75. package/lib/context/otelWsPool.d.ts +20 -0
  76. package/lib/context/otelWsPool.js +69 -0
  77. package/lib/examples/A2UiComponentGalleryExample.d.ts +0 -17
  78. package/lib/examples/A2UiComponentGalleryExample.js +315 -522
  79. package/lib/examples/A2UiContactCardExample.d.ts +0 -18
  80. package/lib/examples/A2UiContactCardExample.js +154 -411
  81. package/lib/examples/A2UiRestaurantExample.d.ts +0 -30
  82. package/lib/examples/A2UiRestaurantExample.js +114 -212
  83. package/lib/examples/A2UiViewerExample.d.ts +0 -18
  84. package/lib/examples/A2UiViewerExample.js +283 -532
  85. package/lib/examples/AgUiBackendToolRenderingExample.js +1 -1
  86. package/lib/examples/AgUiHaikuGenUiExample.d.ts +1 -1
  87. package/lib/examples/AgUiHaikuGenUiExample.js +1 -1
  88. package/lib/examples/AgentCheckpointsExample.js +14 -34
  89. package/lib/examples/AgentCodemodeExample.d.ts +4 -6
  90. package/lib/examples/AgentCodemodeExample.js +591 -175
  91. package/lib/examples/AgentEvalsExample.js +13 -23
  92. package/lib/examples/AgentGuardrailsExample.js +371 -71
  93. package/lib/examples/AgentHooksExample.d.ts +3 -0
  94. package/lib/examples/AgentHooksExample.js +104 -0
  95. package/lib/examples/AgentMCPExample.d.ts +3 -0
  96. package/lib/examples/AgentMCPExample.js +480 -0
  97. package/lib/examples/AgentMemoryExample.js +14 -24
  98. package/lib/examples/AgentMonitoringExample.js +261 -206
  99. package/lib/examples/AgentNotificationsExample.js +50 -24
  100. package/lib/examples/AgentOtelExample.js +2 -3
  101. package/lib/examples/AgentOutputsExample.d.ts +11 -6
  102. package/lib/examples/AgentOutputsExample.js +383 -88
  103. package/lib/examples/AgentParametersExample.d.ts +3 -0
  104. package/lib/examples/AgentParametersExample.js +246 -0
  105. package/lib/examples/AgentSandboxExample.d.ts +2 -2
  106. package/lib/examples/AgentSandboxExample.js +69 -47
  107. package/lib/examples/AgentSkillsExample.js +92 -106
  108. package/lib/examples/{AgentspecExample.js → AgentSpecsExample.js} +10 -21
  109. package/lib/examples/AgentSubagentsExample.d.ts +14 -0
  110. package/lib/examples/AgentSubagentsExample.js +228 -0
  111. package/lib/examples/AgentToolApprovalsExample.js +30 -493
  112. package/lib/examples/AgentTriggersExample.js +1067 -246
  113. package/lib/examples/ChatCustomExample.js +11 -24
  114. package/lib/examples/ChatExample.js +9 -34
  115. package/lib/examples/CopilotKitLexicalExample.js +2 -1
  116. package/lib/examples/CopilotKitNotebookExample.js +2 -1
  117. package/lib/examples/HomeExample.d.ts +15 -0
  118. package/lib/examples/HomeExample.js +77 -0
  119. package/lib/examples/Lexical2Example.js +4 -2
  120. package/lib/examples/{LexicalExample.d.ts → LexicalAgentExample.d.ts} +4 -4
  121. package/lib/examples/{LexicalExample.js → LexicalAgentExample.js} +65 -16
  122. package/lib/examples/{LexicalSidebarExample.d.ts → LexicalAgentSidebarExample.d.ts} +5 -5
  123. package/lib/examples/LexicalAgentSidebarExample.js +261 -0
  124. package/lib/examples/NotebookAgentExample.d.ts +9 -0
  125. package/lib/examples/NotebookAgentExample.js +192 -0
  126. package/lib/examples/{NotebookSidebarExample.d.ts → NotebookAgentSidebarExample.d.ts} +2 -2
  127. package/lib/examples/NotebookAgentSidebarExample.js +221 -0
  128. package/lib/examples/{DatalayerNotebookExample.d.ts → NotebookCollaborationExample.d.ts} +4 -4
  129. package/lib/examples/{DatalayerNotebookExample.js → NotebookCollaborationExample.js} +3 -3
  130. package/lib/examples/NotebookExample.d.ts +4 -7
  131. package/lib/examples/NotebookExample.js +14 -146
  132. package/lib/examples/components/AuthRequiredView.d.ts +6 -0
  133. package/lib/examples/components/AuthRequiredView.js +33 -0
  134. package/lib/examples/components/ErrorView.d.ts +14 -0
  135. package/lib/examples/components/ErrorView.js +20 -0
  136. package/lib/examples/components/ExampleWrapper.d.ts +7 -0
  137. package/lib/examples/components/ExampleWrapper.js +25 -6
  138. package/lib/examples/{ag-ui → components}/haiku/HaikuDisplay.js +1 -1
  139. package/lib/examples/{ag-ui → components}/haiku/InlineHaikuCard.js +1 -1
  140. package/lib/examples/{ag-ui → components}/haiku/index.d.ts +1 -1
  141. package/lib/examples/{ag-ui → components}/haiku/index.js +1 -1
  142. package/lib/examples/components/index.d.ts +5 -0
  143. package/lib/examples/components/index.js +5 -0
  144. package/lib/examples/{ag-ui → components}/weather/index.d.ts +1 -1
  145. package/lib/examples/{ag-ui → components}/weather/index.js +1 -1
  146. package/lib/examples/example-selector.d.ts +17 -4
  147. package/lib/examples/example-selector.js +107 -41
  148. package/lib/examples/index.d.ts +9 -6
  149. package/lib/examples/index.js +9 -6
  150. package/lib/examples/main.d.ts +1 -0
  151. package/lib/examples/main.js +218 -27
  152. package/lib/examples/utils/a2ui.d.ts +18 -0
  153. package/lib/examples/utils/a2ui.js +69 -0
  154. package/lib/examples/utils/a2uiMarkdownProvider.d.ts +7 -0
  155. package/lib/examples/utils/a2uiMarkdownProvider.js +9 -0
  156. package/lib/examples/utils/agentId.d.ts +18 -0
  157. package/lib/examples/utils/agentId.js +54 -0
  158. package/lib/examples/utils/agents/earthquake-detector.json +11 -11
  159. package/lib/examples/utils/agents/sales-forecaster.json +11 -11
  160. package/lib/examples/utils/agents/social-post-generator.json +11 -11
  161. package/lib/examples/utils/agents/stock-market.json +11 -11
  162. package/lib/examples/utils/examplesStore.js +82 -27
  163. package/lib/hooks/index.d.ts +8 -8
  164. package/lib/hooks/index.js +7 -7
  165. package/lib/hooks/useA2A.d.ts +2 -3
  166. package/lib/hooks/useAIAgentsWebSocket.d.ts +43 -4
  167. package/lib/hooks/useAIAgentsWebSocket.js +118 -12
  168. package/lib/hooks/useAcp.d.ts +1 -2
  169. package/lib/hooks/useAgUi.d.ts +1 -1
  170. package/lib/hooks/{useAgents.d.ts → useAgentRuntimes.d.ts} +39 -2
  171. package/lib/hooks/{useAgents.js → useAgentRuntimes.js} +125 -15
  172. package/lib/hooks/useAgentsCatalog.js +1 -1
  173. package/lib/hooks/useAgentsService.d.ts +2 -2
  174. package/lib/hooks/useAgentsService.js +7 -7
  175. package/lib/hooks/useCheckpoints.js +1 -1
  176. package/lib/hooks/useConfig.d.ts +4 -1
  177. package/lib/hooks/useConfig.js +10 -3
  178. package/lib/hooks/useContextSnapshot.d.ts +9 -4
  179. package/lib/hooks/useContextSnapshot.js +9 -37
  180. package/lib/hooks/useMonitoring.js +3 -0
  181. package/lib/hooks/useSandbox.d.ts +20 -8
  182. package/lib/hooks/useSandbox.js +105 -40
  183. package/lib/hooks/useSkills.d.ts +23 -5
  184. package/lib/hooks/useSkills.js +94 -39
  185. package/lib/hooks/useToolApprovals.d.ts +60 -36
  186. package/lib/hooks/useToolApprovals.js +318 -69
  187. package/lib/hooks/useVercelAI.d.ts +1 -1
  188. package/lib/index.d.ts +2 -1
  189. package/lib/index.js +1 -0
  190. package/lib/inference/index.d.ts +0 -1
  191. package/lib/middleware/index.d.ts +0 -1
  192. package/lib/protocols/AGUIAdapter.js +6 -0
  193. package/lib/protocols/VercelAIAdapter.d.ts +9 -0
  194. package/lib/protocols/VercelAIAdapter.js +144 -26
  195. package/lib/shims/json5.d.ts +4 -0
  196. package/lib/shims/json5.js +8 -0
  197. package/lib/specs/agents/agents.d.ts +10 -0
  198. package/lib/specs/agents/agents.js +752 -24
  199. package/lib/specs/envvars.d.ts +1 -0
  200. package/lib/specs/envvars.js +11 -0
  201. package/lib/specs/events.d.ts +1 -0
  202. package/lib/specs/events.js +1 -0
  203. package/lib/specs/index.d.ts +1 -0
  204. package/lib/specs/index.js +1 -0
  205. package/lib/specs/personas.d.ts +41 -0
  206. package/lib/specs/personas.js +168 -0
  207. package/lib/specs/skills.d.ts +2 -1
  208. package/lib/specs/skills.js +23 -5
  209. package/lib/specs/tools.js +3 -0
  210. package/lib/stores/agentRuntimeStore.d.ts +204 -0
  211. package/lib/stores/agentRuntimeStore.js +636 -0
  212. package/lib/stores/index.d.ts +1 -1
  213. package/lib/stores/index.js +1 -1
  214. package/lib/tools/adapters/copilotkit/lexicalHooks.d.ts +1 -2
  215. package/lib/tools/adapters/copilotkit/lexicalHooks.js +1 -3
  216. package/lib/tools/adapters/copilotkit/notebookHooks.d.ts +1 -2
  217. package/lib/tools/adapters/copilotkit/notebookHooks.js +1 -3
  218. package/lib/tools/index.d.ts +0 -2
  219. package/lib/tools/index.js +0 -1
  220. package/lib/types/agentspecs.d.ts +50 -1
  221. package/lib/types/chat.d.ts +309 -8
  222. package/lib/types/context.d.ts +27 -0
  223. package/lib/types/cost.d.ts +2 -2
  224. package/lib/types/index.d.ts +2 -0
  225. package/lib/types/index.js +2 -0
  226. package/lib/types/mcp.d.ts +8 -0
  227. package/lib/types/models.d.ts +2 -2
  228. package/lib/types/personas.d.ts +25 -0
  229. package/lib/types/personas.js +5 -0
  230. package/lib/types/skills.d.ts +43 -1
  231. package/lib/types/stream.d.ts +110 -0
  232. package/lib/types/stream.js +36 -0
  233. package/lib/types/tools.d.ts +2 -0
  234. package/lib/utils/utils.d.ts +9 -5
  235. package/lib/utils/utils.js +9 -5
  236. package/package.json +13 -9
  237. package/scripts/codegen/__pycache__/generate_agents.cpython-313.pyc +0 -0
  238. package/scripts/codegen/__pycache__/generate_events.cpython-313.pyc +0 -0
  239. package/scripts/codegen/__pycache__/versioning.cpython-313.pyc +0 -0
  240. package/scripts/codegen/generate_agents.py +106 -7
  241. package/scripts/codegen/generate_events.py +47 -17
  242. package/scripts/codegen/generate_personas.py +319 -0
  243. package/scripts/codegen/generate_skills.py +9 -9
  244. package/scripts/codegen/generate_tools.py +20 -0
  245. package/scripts/sync-jupyter.sh +26 -7
  246. package/style/primer-primitives.css +1 -6
  247. package/lib/api/tool-approvals.d.ts +0 -62
  248. package/lib/api/tool-approvals.js +0 -145
  249. package/lib/examples/LexicalSidebarExample.js +0 -163
  250. package/lib/examples/NotebookSidebarExample.js +0 -119
  251. package/lib/examples/NotebookSimpleExample.d.ts +0 -6
  252. package/lib/examples/NotebookSimpleExample.js +0 -22
  253. package/lib/examples/ag-ui/index.d.ts +0 -10
  254. package/lib/examples/ag-ui/index.js +0 -16
  255. package/lib/hooks/useAgentsRegistry.d.ts +0 -10
  256. package/lib/hooks/useAgentsRegistry.js +0 -20
  257. package/lib/stores/agentsStore.d.ts +0 -123
  258. package/lib/stores/agentsStore.js +0 -270
  259. package/scripts/codegen/__pycache__/generate_envvars.cpython-313.pyc +0 -0
  260. package/scripts/codegen/__pycache__/generate_evals.cpython-313.pyc +0 -0
  261. package/scripts/codegen/__pycache__/generate_guardrails.cpython-313.pyc +0 -0
  262. package/scripts/codegen/__pycache__/generate_mcp_servers.cpython-313.pyc +0 -0
  263. package/scripts/codegen/__pycache__/generate_memory.cpython-313.pyc +0 -0
  264. package/scripts/codegen/__pycache__/generate_models.cpython-313.pyc +0 -0
  265. package/scripts/codegen/__pycache__/generate_notifications.cpython-313.pyc +0 -0
  266. package/scripts/codegen/__pycache__/generate_outputs.cpython-313.pyc +0 -0
  267. package/scripts/codegen/__pycache__/generate_skills.cpython-313.pyc +0 -0
  268. package/scripts/codegen/__pycache__/generate_teams.cpython-313.pyc +0 -0
  269. package/scripts/codegen/__pycache__/generate_tools.cpython-313.pyc +0 -0
  270. package/scripts/codegen/__pycache__/generate_triggers.cpython-313.pyc +0 -0
  271. /package/lib/examples/{AgentspecExample.d.ts → AgentSpecsExample.d.ts} +0 -0
  272. /package/lib/examples/{ag-ui → components}/haiku/HaikuDisplay.d.ts +0 -0
  273. /package/lib/examples/{ag-ui → components}/haiku/InlineHaikuCard.d.ts +0 -0
  274. /package/lib/examples/{ag-ui → components}/weather/InlineWeatherCard.d.ts +0 -0
  275. /package/lib/examples/{ag-ui → components}/weather/InlineWeatherCard.js +0 -0
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } 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.
@@ -6,50 +6,77 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
6
6
  /**
7
7
  * AgentCodemodeExample
8
8
  *
9
- * Demonstrates Codemode: tools that return structured outputs with schemas
10
- * rendered inline as executable code blocks, diffs, or file previews.
9
+ * Compares two Tavily-based agents side-by-side:
10
+ * - Tavily MCP without codemode conversion
11
+ * - Tavily MCP with codemode conversion
11
12
  *
12
- * - Creates a cloud agent runtime (environment: 'ai-agents-env') via the Datalayer
13
- * Runtimes API and deploys an agent on its sidecar
14
- * - Shows a code panel alongside the chat displaying tool outputs with
15
- * syntax highlighting, diff views, and the ability to accept/reject changes
13
+ * A sidebar gauge tracks consumed tokens for each agent in real time.
16
14
  */
17
15
  /// <reference types="vite/client" />
18
- import { useEffect, useState, useCallback, useRef } from 'react';
19
- import { Text, Button, Spinner, Heading, Label, Flash } from '@primer/react';
20
- import { AlertIcon, CodeIcon, DiffIcon, FileCodeIcon, CheckIcon, XIcon, SignOutIcon, } from '@primer/octicons-react';
16
+ import { useEffect, useState, useCallback, useRef, useMemo, } from 'react';
17
+ import { Text, Spinner, Heading, Label, Flash } from '@primer/react';
18
+ import { CodeIcon } from '@primer/octicons-react';
21
19
  import { Box } from '@datalayer/primer-addons';
20
+ import ReactECharts from 'echarts-for-react';
22
21
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
23
22
  import { useSimpleAuthStore } from '@datalayer/core/lib/views/otel';
24
- import { SignInSimple } from '@datalayer/core/lib/views/iam';
25
- import { UserBadge } from '@datalayer/core/lib/views/profile';
26
23
  import { ThemedProvider } from './utils/themedProvider';
27
- import { useAgents } from '../hooks/useAgents';
24
+ import { AuthRequiredView } from './components';
25
+ import { uniqueAgentId } from './utils/agentId';
26
+ import { useAIAgentsWebSocket } from '../hooks';
28
27
  import { Chat } from '../chat';
28
+ import { ContextPanel, } from '../context/ContextPanel';
29
+ import { parseAgentStreamMessage, } from '../types/stream';
30
+ import { MCP_SERVER_LIBRARY } from '../specs/mcpServers';
29
31
  const queryClient = new QueryClient();
30
- // ─── Constants ─────────────────────────────────────────────────────────────
31
- const AGENT_NAME = 'codemode-demo-agent';
32
- const AGENT_SPEC_ID = 'monitor-sales-kpis';
33
- // ─── Inner component (rendered after auth) ─────────────────────────────────
34
- const AgentCodemodeInner = ({ onLogout, }) => {
35
- const { token } = useSimpleAuthStore();
36
- const { runtime, status: runtimeStatus, isReady, error: hookError, } = useAgents({
37
- agentSpecId: AGENT_SPEC_ID,
38
- autoStart: true,
39
- agentConfig: {
40
- name: AGENT_NAME,
41
- protocol: 'ag-ui',
42
- description: 'Agent with Codemode structured tool outputs',
43
- },
44
- });
45
- const [codeView, setCodeView] = useState('output');
46
- const [artifacts, setArtifacts] = useState([]);
47
- const [selectedId, setSelectedId] = useState(null);
48
- const [flash, setFlash] = useState(null);
49
- const agentBaseUrl = runtime?.agentBaseUrl || '';
50
- const agentId = runtime?.agentId || AGENT_NAME;
51
- const podName = runtime?.podName || '(launching…)';
52
- // Authenticated fetch helper
32
+ // Each pane talks to its own agent-runtimes process so the two agents are
33
+ // fully isolated (no shared global codemode/MCP state). Override via env:
34
+ // VITE_BASE_URL_NO_CODEMODE=http://localhost:8765
35
+ // VITE_BASE_URL_CODEMODE=http://localhost:8766
36
+ const NO_CODEMODE_BASE_URL = import.meta.env.VITE_BASE_URL_NO_CODEMODE ||
37
+ import.meta.env.VITE_BASE_URL ||
38
+ 'http://localhost:8765';
39
+ const CODEMODE_BASE_URL = import.meta.env.VITE_BASE_URL_CODEMODE || 'http://localhost:8766';
40
+ const NO_CODEMODE_SUGGESTION_MESSAGE = 'Use the Tavily Extract tool to extract information from https://datalayer.ai, then use your sandbox to persist that information in a variable named "about_datalayer".';
41
+ const CODEMODE_SUGGESTION_MESSAGE = 'Extract information from the https://datalayer.ai website and assign it to the variable "about_datalayer", all in one step using the sandbox';
42
+ const DEMO_AGENT_CONFIGS = [
43
+ {
44
+ key: 'no-codemode',
45
+ title: 'Tavily MCP (No Codemode)',
46
+ subtitle: 'Raw MCP tools without codemode conversion',
47
+ suggestionMessage: NO_CODEMODE_SUGGESTION_MESSAGE,
48
+ specId: 'demo-tavily-no-codemode',
49
+ color: '#0969DA',
50
+ baseUrl: NO_CODEMODE_BASE_URL,
51
+ },
52
+ {
53
+ key: 'codemode',
54
+ title: 'Tavily MCP (Codemode)',
55
+ subtitle: 'MCP tools converted into programmatic tools',
56
+ suggestionMessage: CODEMODE_SUGGESTION_MESSAGE,
57
+ specId: 'demo-tavily-codemode',
58
+ color: '#8250DF',
59
+ baseUrl: CODEMODE_BASE_URL,
60
+ },
61
+ ];
62
+ function extractConsumedTokens(payload) {
63
+ const snapshotCost = payload.contextSnapshot?.costUsage ?? payload.costUsage;
64
+ const totalFromCost = Number(snapshotCost?.totalTokensUsed ?? 0);
65
+ if (totalFromCost > 0) {
66
+ return totalFromCost;
67
+ }
68
+ return Number(payload.contextSnapshot?.totalTokens ?? 0);
69
+ }
70
+ const AgentRuntimePane = ({ config, token, onTokenConsumed, onAgentIdChange, onContextSnapshot, }) => {
71
+ const runtimeName = useRef(uniqueAgentId(`codemode-${config.key}`)).current;
72
+ const [runtimeStatus, setRuntimeStatus] = useState('launching');
73
+ const [hookError, setHookError] = useState(null);
74
+ const [agentId, setAgentId] = useState(runtimeName);
75
+ const [isReconnectedAgent, setIsReconnectedAgent] = useState(false);
76
+ const [selectedServerIds, setSelectedServerIds] = useState([]);
77
+ const [agentTools, setAgentTools] = useState([]);
78
+ const [liveMcpStatus, setLiveMcpStatus] = useState(undefined);
79
+ const [codemodeEnabled, setCodemodeEnabled] = useState(config.key === 'codemode');
53
80
  const authFetch = useCallback((url, opts = {}) => fetch(url, {
54
81
  ...opts,
55
82
  headers: {
@@ -58,70 +85,437 @@ const AgentCodemodeInner = ({ onLogout, }) => {
58
85
  ...(opts.headers ?? {}),
59
86
  },
60
87
  }), [token]);
61
- // ── Poll code artifacts ───────────────────────────────────────────────
62
88
  useEffect(() => {
63
- if (!isReady || !agentBaseUrl)
89
+ let cancelled = false;
90
+ const createLocalAgent = async () => {
91
+ setRuntimeStatus('launching');
92
+ setHookError(null);
93
+ setIsReconnectedAgent(false);
94
+ try {
95
+ const response = await authFetch(`${config.baseUrl}/api/v1/agents`, {
96
+ method: 'POST',
97
+ body: JSON.stringify({
98
+ name: runtimeName,
99
+ description: config.subtitle,
100
+ agent_library: 'pydantic-ai',
101
+ transport: 'vercel-ai',
102
+ agent_spec_id: config.specId,
103
+ enable_skills: true,
104
+ tools: [],
105
+ }),
106
+ });
107
+ let resolvedAgentId = runtimeName;
108
+ let alreadyRunning = false;
109
+ if (response.ok) {
110
+ const data = await response.json();
111
+ resolvedAgentId = data?.id || runtimeName;
112
+ }
113
+ else {
114
+ const contentType = response.headers.get('content-type') || '';
115
+ let detail = '';
116
+ if (contentType.includes('application/json')) {
117
+ const data = await response.json().catch(() => null);
118
+ detail =
119
+ (typeof data?.detail === 'string' && data.detail) ||
120
+ (typeof data?.message === 'string' && data.message) ||
121
+ '';
122
+ }
123
+ else {
124
+ detail = await response.text();
125
+ }
126
+ if (response.status === 409 || /already exists/i.test(detail || '')) {
127
+ alreadyRunning = true;
128
+ }
129
+ else {
130
+ throw new Error(detail || `Failed to create local agent: ${response.status}`);
131
+ }
132
+ }
133
+ if (!cancelled) {
134
+ setAgentId(resolvedAgentId);
135
+ onAgentIdChange?.(config.key, resolvedAgentId);
136
+ setIsReconnectedAgent(alreadyRunning);
137
+ setRuntimeStatus('ready');
138
+ }
139
+ }
140
+ catch (error) {
141
+ if (!cancelled) {
142
+ setHookError(error instanceof Error ? error.message : 'Agent failed to start');
143
+ setRuntimeStatus('error');
144
+ }
145
+ }
146
+ };
147
+ void createLocalAgent();
148
+ return () => {
149
+ cancelled = true;
150
+ };
151
+ }, [authFetch, config.specId, config.subtitle, config.baseUrl, runtimeName]);
152
+ const handleStreamMessage = useCallback((message) => {
153
+ try {
154
+ const stream = parseAgentStreamMessage(message?.raw ?? message);
155
+ if (!stream || stream.type !== 'agent.snapshot') {
156
+ return;
157
+ }
158
+ const payload = stream.payload;
159
+ const consumed = extractConsumedTokens(payload);
160
+ if (consumed >= 0) {
161
+ onTokenConsumed(config.key, consumed);
162
+ }
163
+ if (payload.mcpStatus !== undefined) {
164
+ setLiveMcpStatus(payload.mcpStatus ?? undefined);
165
+ }
166
+ if (payload.contextSnapshot) {
167
+ onContextSnapshot?.(config.key, payload.contextSnapshot);
168
+ }
169
+ const fc = payload.fullContext;
170
+ if (fc && Array.isArray(fc.tools) && fc.tools.length > 0) {
171
+ setAgentTools(fc.tools);
172
+ }
173
+ if (payload.codemodeStatus &&
174
+ typeof payload.codemodeStatus.enabled === 'boolean') {
175
+ setCodemodeEnabled(payload.codemodeStatus.enabled);
176
+ }
177
+ }
178
+ catch {
179
+ // Ignore malformed stream payloads.
180
+ }
181
+ }, [config.key, onTokenConsumed, onContextSnapshot]);
182
+ useAIAgentsWebSocket({
183
+ enabled: runtimeStatus === 'ready',
184
+ baseUrl: config.baseUrl,
185
+ path: '/api/v1/tool-approvals/ws',
186
+ queryParams: { agent_id: agentId },
187
+ onMessage: handleStreamMessage,
188
+ reconnectDelayMs: attempt => Math.min(1000 * 2 ** Math.max(0, attempt - 1), 10000),
189
+ });
190
+ // Fetch creation spec to get selected MCP server IDs (for the MCP indicator).
191
+ useEffect(() => {
192
+ if (runtimeStatus !== 'ready')
64
193
  return;
65
- const poll = async () => {
194
+ let cancelled = false;
195
+ const fetchSpec = async () => {
66
196
  try {
67
- const res = await authFetch(`${agentBaseUrl}/api/v1/agents/${agentId}/codemode/artifacts`);
68
- if (res.ok) {
69
- const d = await res.json();
70
- setArtifacts(Array.isArray(d) ? d : (d.artifacts ?? []));
197
+ const res = await authFetch(`${config.baseUrl}/api/v1/configure/agents/${agentId}/spec`);
198
+ if (!res.ok)
199
+ return;
200
+ const spec = await res.json();
201
+ const servers = (spec?.selected_mcp_servers ?? []);
202
+ if (!cancelled) {
203
+ setSelectedServerIds(servers.map(s => s.id));
71
204
  }
72
205
  }
73
206
  catch {
74
- /* ok */
207
+ // Non-fatal.
75
208
  }
76
209
  };
77
- poll();
78
- const interval = setInterval(poll, 5_000);
79
- return () => clearInterval(interval);
80
- }, [isReady, agentBaseUrl, agentId, authFetch]);
81
- // ── Accept / Reject ───────────────────────────────────────────────────
82
- const handleDecision = useCallback(async (artifactId, decision) => {
83
- if (!agentBaseUrl)
84
- return;
85
- setFlash(null);
210
+ void fetchSpec();
211
+ return () => {
212
+ cancelled = true;
213
+ };
214
+ }, [runtimeStatus, agentId, authFetch, config.baseUrl]);
215
+ // Build McpServerInfo[] from selected servers + catalog + WS tools.
216
+ const mcpServers = useMemo(() => {
217
+ if (selectedServerIds.length === 0)
218
+ return [];
219
+ return selectedServerIds.map(serverId => {
220
+ const catalogServer = MCP_SERVER_LIBRARY[serverId];
221
+ const serverName = catalogServer?.name ?? serverId;
222
+ const liveServer = liveMcpStatus?.servers?.find(s => s.id === serverId);
223
+ const serverTools = agentTools
224
+ .filter(t => t.name.startsWith(`${serverId}__`))
225
+ .map(t => ({
226
+ name: t.name,
227
+ description: t.description,
228
+ serverId,
229
+ serverName,
230
+ inputSchema: t.parametersSchema,
231
+ }));
232
+ const toolsFromLive = (liveServer?.tools ?? []).map(t => ({
233
+ name: t.name,
234
+ description: t.description ?? '',
235
+ serverId,
236
+ serverName,
237
+ inputSchema: undefined,
238
+ }));
239
+ const tools = toolsFromLive.length > 0 ? toolsFromLive : serverTools;
240
+ const status = liveServer?.status ?? (serverTools.length > 0 ? 'started' : 'starting');
241
+ const toolsCount = liveServer?.tools_count ?? tools.length;
242
+ return {
243
+ id: serverId,
244
+ name: serverName,
245
+ description: catalogServer?.description,
246
+ status,
247
+ toolsCount,
248
+ tools,
249
+ emoji: catalogServer?.emoji,
250
+ icon: catalogServer?.icon,
251
+ };
252
+ });
253
+ }, [selectedServerIds, agentTools, liveMcpStatus]);
254
+ // Build a synthetic McpToolsetsStatusResponse for the Chat MCP indicator.
255
+ const mcpStatusData = useMemo(() => {
256
+ const derivedEnabledToolsByServer = {};
257
+ const derivedApprovedToolsByServer = {};
258
+ for (const s of mcpServers) {
259
+ if (s.tools.length > 0) {
260
+ derivedEnabledToolsByServer[s.id] = s.tools.map(t => t.name);
261
+ derivedApprovedToolsByServer[s.id] = [];
262
+ }
263
+ }
264
+ if (liveMcpStatus && liveMcpStatus.servers.length > 0) {
265
+ const live = liveMcpStatus;
266
+ const enabledToolsByServer = { ...(live.enabled_tools_by_server ?? {}) };
267
+ for (const [serverId, tools] of Object.entries(derivedEnabledToolsByServer)) {
268
+ if (!enabledToolsByServer[serverId] ||
269
+ enabledToolsByServer[serverId].length === 0) {
270
+ enabledToolsByServer[serverId] = tools;
271
+ }
272
+ }
273
+ const approvedToolsByServer = {
274
+ ...(live.approved_tools_by_server ?? {}),
275
+ };
276
+ for (const [serverId, tools] of Object.entries(derivedApprovedToolsByServer)) {
277
+ if (!approvedToolsByServer[serverId]) {
278
+ approvedToolsByServer[serverId] = tools;
279
+ }
280
+ }
281
+ return {
282
+ ...live,
283
+ enabled_tools_by_server: enabledToolsByServer,
284
+ approved_tools_by_server: approvedToolsByServer,
285
+ };
286
+ }
287
+ if (mcpServers.length === 0)
288
+ return undefined;
289
+ const servers = mcpServers.map(s => ({
290
+ id: s.id,
291
+ status: s.status,
292
+ tools_count: s.toolsCount,
293
+ tools: s.tools.map(t => ({
294
+ name: t.name,
295
+ description: t.description,
296
+ enabled: true,
297
+ })),
298
+ }));
299
+ const readyServers = servers
300
+ .filter(s => s.status === 'started')
301
+ .map(s => s.id);
302
+ return {
303
+ initialized: true,
304
+ ready_count: readyServers.length,
305
+ failed_count: servers.filter(s => s.status === 'failed').length,
306
+ ready_servers: readyServers,
307
+ failed_servers: {},
308
+ servers,
309
+ enabled_tools_by_server: derivedEnabledToolsByServer,
310
+ approved_tools_by_server: derivedApprovedToolsByServer,
311
+ enabled_tools_count: mcpServers.reduce((sum, s) => sum + s.tools.length, 0),
312
+ };
313
+ }, [liveMcpStatus, mcpServers]);
314
+ // Synthetic codemode status so the Info panel never shows
315
+ // "Waiting for Codemode status from WebSocket stream...".
316
+ // This is configuration, so it's known locally from the spec/toggle state.
317
+ const codemodeStatusData = useMemo(() => ({
318
+ enabled: codemodeEnabled,
319
+ skills: [],
320
+ available_skills: [],
321
+ sandbox: null,
322
+ }), [codemodeEnabled]);
323
+ const handleToggleCodemode = useCallback(async (enabled) => {
324
+ // Optimistic update; WS snapshot will reconcile.
325
+ setCodemodeEnabled(enabled);
86
326
  try {
87
- const res = await authFetch(`${agentBaseUrl}/api/v1/agents/${agentId}/codemode/artifacts/${artifactId}`, {
88
- method: 'PATCH',
89
- body: JSON.stringify({ status: decision }),
327
+ const res = await authFetch(`${config.baseUrl}/api/v1/configure/codemode/toggle`, {
328
+ method: 'POST',
329
+ body: JSON.stringify({ enabled, agent_id: agentId }),
90
330
  });
91
- if (res.ok) {
92
- setArtifacts(prev => prev.map(a => a.id === artifactId ? { ...a, status: decision } : a));
93
- setFlash(`Change ${decision}`);
331
+ if (!res.ok) {
332
+ throw new Error(`Toggle failed: ${res.status}`);
94
333
  }
95
334
  }
96
335
  catch {
97
- setFlash('Network error');
336
+ // Rollback optimistic update on failure.
337
+ setCodemodeEnabled(prev => !prev);
98
338
  }
99
- }, [agentBaseUrl, agentId, authFetch]);
100
- // ── Loading / Error ───────────────────────────────────────────────────
101
- if (!isReady && runtimeStatus !== 'error') {
339
+ }, [authFetch, agentId, config.baseUrl]);
340
+ if (runtimeStatus === 'launching') {
102
341
  return (_jsxs(Box, { sx: {
342
+ border: '1px solid',
343
+ borderColor: 'border.default',
344
+ borderRadius: 2,
345
+ p: 3,
346
+ minHeight: 220,
103
347
  display: 'flex',
104
- flexDirection: 'column',
105
348
  alignItems: 'center',
106
349
  justifyContent: 'center',
107
- height: '100vh',
108
- gap: 3,
109
- }, children: [_jsx(Spinner, { size: "large" }), _jsx(Text, { sx: { color: 'fg.muted' }, children: runtimeStatus === 'launching'
110
- ? 'Launching runtime for codemode agent…'
111
- : 'Creating codemode demo agent…' })] }));
350
+ flexDirection: 'column',
351
+ gap: 2,
352
+ }, children: [_jsx(Spinner, { size: "small" }), _jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: ["Launching ", config.title, "..."] })] }));
112
353
  }
113
354
  if (runtimeStatus === 'error' || hookError) {
114
- return (_jsxs(Box, { sx: {
115
- display: 'flex',
116
- flexDirection: 'column',
117
- alignItems: 'center',
118
- justifyContent: 'center',
119
- height: '100vh',
120
- gap: 3,
121
- }, children: [_jsx(AlertIcon, { size: 48 }), _jsx(Text, { sx: { color: 'danger.fg' }, children: hookError || 'Agent failed to start' })] }));
355
+ return (_jsxs(Flash, { variant: "danger", sx: { borderRadius: 2 }, children: [config.title, ": ", hookError || 'Failed to start'] }));
356
+ }
357
+ return (_jsx(Box, { sx: {
358
+ border: '1px solid',
359
+ borderColor: 'border.default',
360
+ borderRadius: 2,
361
+ overflow: 'hidden',
362
+ minHeight: 560,
363
+ display: 'flex',
364
+ flexDirection: 'column',
365
+ }, children: _jsx(Box, { sx: { flex: 1, minHeight: 0 }, children: _jsx(Chat, { protocol: "vercel-ai", baseUrl: config.baseUrl, agentId: agentId, authToken: token, title: config.title, subtitle: config.subtitle, placeholder: "Ask both agents the same request to compare behavior...", description: config.subtitle, showHeader: true, headerActions: isReconnectedAgent ? (_jsx(Label, { size: "small", variant: "attention", children: "Reconnected" })) : undefined, autoFocus: false, height: "100%", runtimeId: agentId, historyEndpoint: `${config.baseUrl}/api/v1/history`, mcpStatusData: mcpStatusData, codemodeStatusData: codemodeStatusData, codemodeEnabled: codemodeEnabled, onToggleCodemode: handleToggleCodemode, suggestions: [
366
+ {
367
+ title: 'Datalayer extraction',
368
+ message: config.suggestionMessage,
369
+ },
370
+ ], submitOnSuggestionClick: true }) }) }));
371
+ };
372
+ const AgentCodemodeInner = ({ onLogout, }) => {
373
+ const { token } = useSimpleAuthStore();
374
+ const [consumedByAgent, setConsumedByAgent] = useState({
375
+ 'no-codemode': 0,
376
+ codemode: 0,
377
+ });
378
+ const [agentIdByKey, setAgentIdByKey] = useState({});
379
+ const [contextSnapshotByKey, setContextSnapshotByKey] = useState({});
380
+ const handleAgentIdChange = useCallback((agentKey, agentId) => {
381
+ setAgentIdByKey(prev => prev[agentKey] === agentId ? prev : { ...prev, [agentKey]: agentId });
382
+ }, []);
383
+ const handleContextSnapshot = useCallback((agentKey, snapshot) => {
384
+ setContextSnapshotByKey(prev => ({ ...prev, [agentKey]: snapshot }));
385
+ }, []);
386
+ const handleTokenConsumed = useCallback((agentKey, tokens) => {
387
+ setConsumedByAgent(prev => ({
388
+ ...prev,
389
+ [agentKey]: Math.max(prev[agentKey] ?? 0, tokens),
390
+ }));
391
+ }, []);
392
+ const maxGaugeValue = useMemo(() => {
393
+ const values = Object.values(consumedByAgent);
394
+ const currentMax = values.length > 0 ? Math.max(...values) : 0;
395
+ if (currentMax <= 2000) {
396
+ return 2000;
397
+ }
398
+ const magnitude = 10 ** Math.floor(Math.log10(currentMax));
399
+ return Math.ceil((currentMax * 1.2) / magnitude) * magnitude;
400
+ }, [consumedByAgent]);
401
+ const tokenComparison = useMemo(() => {
402
+ const noCodemodeTokens = consumedByAgent['no-codemode'] ?? 0;
403
+ const codemodeTokens = consumedByAgent.codemode ?? 0;
404
+ if (noCodemodeTokens === codemodeTokens) {
405
+ return {
406
+ tie: true,
407
+ winnerKey: null,
408
+ loserKey: null,
409
+ };
410
+ }
411
+ const winnerKey = noCodemodeTokens < codemodeTokens ? 'no-codemode' : 'codemode';
412
+ return {
413
+ tie: false,
414
+ winnerKey,
415
+ loserKey: winnerKey === 'codemode'
416
+ ? 'no-codemode'
417
+ : 'codemode',
418
+ };
419
+ }, [consumedByAgent]);
420
+ const displayNameFor = useCallback((agentKey) => agentKey === 'codemode' ? 'Codemode' : 'No codemode', []);
421
+ const outcomeFor = useCallback((agentKey) => {
422
+ if (tokenComparison.tie) {
423
+ return {
424
+ emoji: '🤝',
425
+ title: 'Tie',
426
+ message: 'Both agents are tied on token usage.',
427
+ bg: 'canvas.subtle',
428
+ borderColor: 'border.default',
429
+ color: 'fg.default',
430
+ };
431
+ }
432
+ if (tokenComparison.winnerKey === agentKey) {
433
+ return {
434
+ emoji: '🏆',
435
+ title: 'Winner',
436
+ message: `${displayNameFor(agentKey)} is the winner.`,
437
+ bg: 'success.subtle',
438
+ borderColor: 'success.muted',
439
+ color: 'success.fg',
440
+ };
441
+ }
442
+ return {
443
+ emoji: '😓',
444
+ title: 'Loser',
445
+ message: `${displayNameFor(agentKey)} is the loser.`,
446
+ bg: 'attention.subtle',
447
+ borderColor: 'attention.muted',
448
+ color: 'attention.fg',
449
+ };
450
+ }, [displayNameFor, tokenComparison]);
451
+ const gaugeOptionFor = useCallback((config) => ({
452
+ series: [
453
+ {
454
+ type: 'gauge',
455
+ center: ['50%', '55%'],
456
+ radius: '80%',
457
+ min: 0,
458
+ max: maxGaugeValue,
459
+ splitNumber: 5,
460
+ progress: {
461
+ show: true,
462
+ width: 14,
463
+ itemStyle: {
464
+ color: config.color,
465
+ },
466
+ },
467
+ axisLine: {
468
+ lineStyle: {
469
+ width: 14,
470
+ color: [[1, '#d1d9e0']],
471
+ },
472
+ },
473
+ axisTick: { show: false },
474
+ splitLine: {
475
+ length: 10,
476
+ lineStyle: { color: '#8c959f', width: 1 },
477
+ },
478
+ axisLabel: {
479
+ distance: 14,
480
+ color: '#57606a',
481
+ fontSize: 10,
482
+ },
483
+ pointer: {
484
+ width: 3,
485
+ length: '60%',
486
+ },
487
+ anchor: {
488
+ show: true,
489
+ size: 8,
490
+ itemStyle: {
491
+ color: config.color,
492
+ },
493
+ },
494
+ title: { show: false },
495
+ detail: {
496
+ valueAnimation: true,
497
+ offsetCenter: [0, '70%'],
498
+ color: '#24292f',
499
+ fontSize: 14,
500
+ fontWeight: 'bold',
501
+ formatter: (value) => `${Math.round(value).toLocaleString()} tok`,
502
+ },
503
+ data: [
504
+ {
505
+ value: consumedByAgent[config.key] ?? 0,
506
+ name: config.title,
507
+ },
508
+ ],
509
+ },
510
+ ],
511
+ tooltip: {
512
+ trigger: 'item',
513
+ formatter: (params) => `${params.seriesName || 'Agent'}<br/>${Math.round(params.value || 0).toLocaleString()} tokens`,
514
+ },
515
+ }), [consumedByAgent, maxGaugeValue]);
516
+ if (!token) {
517
+ return null;
122
518
  }
123
- const selected = artifacts.find(a => a.id === selectedId) ?? artifacts[0] ?? null;
124
- const pendingCount = artifacts.filter(a => a.status === 'pending').length;
125
519
  return (_jsxs(Box, { sx: {
126
520
  height: 'calc(100vh - 60px)',
127
521
  display: 'flex',
@@ -135,106 +529,133 @@ const AgentCodemodeInner = ({ onLogout, }) => {
135
529
  borderBottom: '1px solid',
136
530
  borderColor: 'border.default',
137
531
  flexShrink: 0,
138
- }, children: [_jsx(CodeIcon, { size: 16 }), _jsxs(Heading, { as: "h3", sx: { fontSize: 2, flex: 1 }, children: ["Codemode \u2014 ", podName] }), pendingCount > 0 && (_jsxs(Label, { variant: "attention", size: "small", children: [pendingCount, " pending"] })), token && _jsx(UserBadge, { token: token, variant: "small" }), _jsx(Button, { size: "small", variant: "invisible", onClick: onLogout, leadingVisual: SignOutIcon, sx: { color: 'fg.muted' }, children: "Sign out" })] }), _jsxs(Box, { sx: { flex: 1, minHeight: 0, display: 'flex' }, children: [_jsx(Box, { sx: { flex: 1, minWidth: 0 }, children: _jsx(Chat, { protocol: "ag-ui", baseUrl: agentBaseUrl, agentId: agentId, title: "Codemode Agent", placeholder: "Ask the agent to generate or modify code\u2026", description: `${artifacts.length} code artifact${artifacts.length !== 1 ? 's' : ''}`, showHeader: true, autoFocus: true, height: "100%", runtimeId: podName, historyEndpoint: `${agentBaseUrl}/api/v1/history`, suggestions: [
139
- {
140
- title: 'Generate script',
141
- message: 'Write a Python script to analyze the KPI data',
142
- },
143
- {
144
- title: 'Refactor',
145
- message: 'Refactor the last code block for readability',
146
- },
147
- ], submitOnSuggestionClick: true }) }), _jsxs(Box, { sx: {
148
- width: 480,
149
- borderLeft: '1px solid',
150
- borderColor: 'border.default',
151
- display: 'flex',
152
- flexDirection: 'column',
153
- }, children: [_jsx(Box, { sx: {
154
- display: 'flex',
155
- borderBottom: '1px solid',
156
- borderColor: 'border.default',
157
- flexShrink: 0,
158
- }, children: [
159
- {
160
- key: 'output',
161
- icon: FileCodeIcon,
162
- label: 'Output',
163
- },
164
- { key: 'diff', icon: DiffIcon, label: 'Diff' },
165
- ].map(t => (_jsx(Button, { size: "small", variant: "invisible", leadingVisual: t.icon, onClick: () => setCodeView(t.key), sx: {
166
- flex: 1,
167
- borderRadius: 0,
168
- borderBottom: codeView === t.key ? '2px solid' : '2px solid transparent',
169
- borderColor: codeView === t.key ? 'accent.fg' : 'transparent',
170
- fontWeight: codeView === t.key ? 'bold' : 'normal',
171
- }, children: t.label }, t.key))) }), _jsxs(Box, { sx: { display: 'flex', flex: 1, minHeight: 0 }, children: [_jsx(Box, { sx: {
172
- width: 140,
173
- borderRight: '1px solid',
174
- borderColor: 'border.default',
175
- overflow: 'auto',
176
- }, children: artifacts.length === 0 ? (_jsx(Text, { sx: {
177
- p: 2,
532
+ }, children: [_jsx(CodeIcon, { size: 16 }), _jsx(Heading, { as: "h3", sx: { fontSize: 2, flex: 1 }, children: "Codemode \u2014 Tavily MCP vs Tavily Codemode" })] }), _jsxs(Box, { sx: { flex: 1, minHeight: 0, display: 'flex' }, children: [DEMO_AGENT_CONFIGS.filter(c => c.key === 'no-codemode').map(config => (() => {
533
+ const outcome = outcomeFor(config.key);
534
+ return (_jsxs(Box, { sx: {
535
+ width: 320,
536
+ borderRight: '1px solid',
537
+ borderColor: 'border.default',
538
+ p: 3,
539
+ display: 'flex',
540
+ flexDirection: 'column',
541
+ gap: 3,
542
+ flexShrink: 0,
543
+ overflow: 'auto',
544
+ }, children: [_jsxs(Box, { children: [_jsx(Heading, { as: "h4", sx: { fontSize: 1, mb: 1 }, children: config.title }), _jsx(Text, { sx: { color: 'fg.muted', fontSize: 0, display: 'block' }, children: "Tokens consumed (no codemode)." }), _jsx(Text, { sx: {
545
+ color: 'fg.muted',
546
+ fontSize: 0,
547
+ fontFamily: 'mono',
548
+ display: 'block',
549
+ mt: 1,
550
+ }, children: config.baseUrl }), _jsx(Text, { sx: {
178
551
  color: 'fg.muted',
179
552
  fontSize: 0,
553
+ fontFamily: 'mono',
554
+ display: 'block',
555
+ mt: 1,
556
+ wordBreak: 'break-all',
557
+ }, children: agentIdByKey[config.key] || 'launching…' })] }), _jsxs(Box, { sx: {
558
+ p: 2,
559
+ borderRadius: 2,
560
+ border: '1px solid',
561
+ bg: outcome.bg,
562
+ borderColor: outcome.borderColor,
563
+ textAlign: 'center',
564
+ display: 'flex',
565
+ flexDirection: 'column',
566
+ alignItems: 'center',
567
+ }, children: [_jsx(Text, { sx: { fontSize: 4, lineHeight: 1, mb: 1 }, children: outcome.emoji }), _jsx(Text, { sx: {
568
+ fontSize: 0,
569
+ color: outcome.color,
570
+ fontWeight: 'bold',
571
+ }, children: outcome.title }), _jsx(Text, { sx: {
572
+ fontSize: 0,
573
+ color: 'fg.muted',
574
+ display: 'block',
575
+ mt: 1,
576
+ }, children: outcome.message })] }), _jsx(ReactECharts, { option: gaugeOptionFor(config), style: {
577
+ height: 240,
578
+ minHeight: 240,
579
+ maxHeight: 240,
580
+ width: '100%',
581
+ flexShrink: 0,
582
+ } }), _jsxs(Box, { sx: {
583
+ display: 'flex',
584
+ justifyContent: 'space-between',
585
+ gap: 2,
586
+ }, children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Consumed" }), _jsxs(Text, { sx: { fontSize: 0, fontWeight: 'bold' }, children: [(consumedByAgent[config.key] ?? 0).toLocaleString(), " tokens"] })] }), agentIdByKey[config.key] && (_jsx(ContextPanel, { agentId: agentIdByKey[config.key], apiBase: config.baseUrl, liveData: contextSnapshotByKey[config.key] ?? null, chartHeight: "180px" }))] }, config.key));
587
+ })()), _jsx(Box, { sx: {
588
+ flex: 1,
589
+ minWidth: 0,
590
+ p: 3,
591
+ display: 'grid',
592
+ gridTemplateColumns: ['1fr', null, '1fr 1fr'],
593
+ gap: 3,
594
+ overflow: 'auto',
595
+ }, children: DEMO_AGENT_CONFIGS.map(config => (_jsx(AgentRuntimePane, { config: config, token: token, onTokenConsumed: handleTokenConsumed, onAgentIdChange: handleAgentIdChange, onContextSnapshot: handleContextSnapshot }, config.key))) }), DEMO_AGENT_CONFIGS.filter(c => c.key === 'codemode').map(config => (() => {
596
+ const outcome = outcomeFor(config.key);
597
+ return (_jsxs(Box, { sx: {
598
+ width: 320,
599
+ borderLeft: '1px solid',
600
+ borderColor: 'border.default',
601
+ p: 3,
602
+ display: 'flex',
603
+ flexDirection: 'column',
604
+ gap: 3,
605
+ flexShrink: 0,
606
+ overflow: 'auto',
607
+ }, children: [_jsxs(Box, { children: [_jsx(Heading, { as: "h4", sx: { fontSize: 1, mb: 1 }, children: config.title }), _jsx(Text, { sx: { color: 'fg.muted', fontSize: 0, display: 'block' }, children: "Tokens consumed (codemode)." }), _jsx(Text, { sx: {
608
+ color: 'fg.muted',
609
+ fontSize: 0,
610
+ fontFamily: 'mono',
611
+ display: 'block',
612
+ mt: 1,
613
+ }, children: config.baseUrl }), _jsx(Text, { sx: {
614
+ color: 'fg.muted',
615
+ fontSize: 0,
616
+ fontFamily: 'mono',
617
+ display: 'block',
618
+ mt: 1,
619
+ wordBreak: 'break-all',
620
+ }, children: agentIdByKey[config.key] || 'launching…' })] }), _jsxs(Box, { sx: {
621
+ p: 2,
622
+ borderRadius: 2,
623
+ border: '1px solid',
624
+ bg: outcome.bg,
625
+ borderColor: outcome.borderColor,
626
+ textAlign: 'center',
627
+ display: 'flex',
628
+ flexDirection: 'column',
629
+ alignItems: 'center',
630
+ }, children: [_jsx(Text, { sx: { fontSize: 4, lineHeight: 1, mb: 1 }, children: outcome.emoji }), _jsx(Text, { sx: {
631
+ fontSize: 0,
632
+ color: outcome.color,
633
+ fontWeight: 'bold',
634
+ }, children: outcome.title }), _jsx(Text, { sx: {
635
+ fontSize: 0,
636
+ color: 'fg.muted',
180
637
  display: 'block',
181
- }, children: "No artifacts yet." })) : (artifacts.map(a => (_jsxs(Box, { onClick: () => setSelectedId(a.id), sx: {
182
- p: 2,
183
- borderBottom: '1px solid',
184
- borderColor: 'border.muted',
185
- bg: selected?.id === a.id ? 'accent.subtle' : 'transparent',
186
- cursor: 'pointer',
187
- ':hover': { bg: 'canvas.subtle' },
188
- }, children: [_jsx(Text, { sx: { fontSize: 0, fontWeight: 'bold', display: 'block' }, children: a.tool_name }), _jsx(Label, { size: "small", variant: a.status === 'accepted'
189
- ? 'success'
190
- : a.status === 'rejected'
191
- ? 'danger'
192
- : 'attention', children: a.status })] }, a.id)))) }), _jsx(Box, { sx: {
193
- flex: 1,
194
- display: 'flex',
195
- flexDirection: 'column',
196
- overflow: 'auto',
197
- }, children: selected ? (_jsxs(_Fragment, { children: [_jsxs(Box, { sx: {
198
- p: 2,
199
- borderBottom: '1px solid',
200
- borderColor: 'border.default',
201
- display: 'flex',
202
- justifyContent: 'space-between',
203
- alignItems: 'center',
204
- flexShrink: 0,
205
- }, children: [_jsxs(Box, { children: [_jsx(Text, { sx: { fontWeight: 'bold', fontSize: 1 }, children: selected.tool_name }), _jsx(Label, { size: "small", variant: "secondary", sx: { ml: 1 }, children: selected.language })] }), selected.status === 'pending' && (_jsxs(Box, { sx: { display: 'flex', gap: 1 }, children: [_jsx(Button, { size: "small", variant: "primary", leadingVisual: CheckIcon, onClick: () => handleDecision(selected.id, 'accepted'), children: "Accept" }), _jsx(Button, { size: "small", variant: "danger", leadingVisual: XIcon, onClick: () => handleDecision(selected.id, 'rejected'), children: "Reject" })] }))] }), _jsx(Box, { sx: {
206
- flex: 1,
207
- overflow: 'auto',
208
- bg: 'canvas.subtle',
209
- p: 3,
210
- }, children: _jsx(Box, { as: "pre", sx: {
211
- fontFamily: 'mono',
212
- fontSize: 0,
213
- m: 0,
214
- whiteSpace: 'pre-wrap',
215
- wordBreak: 'break-word',
216
- }, children: codeView === 'diff' && selected.diff
217
- ? selected.diff
218
- : selected.content }) })] })) : (_jsx(Box, { sx: {
219
- flex: 1,
220
- display: 'flex',
221
- alignItems: 'center',
222
- justifyContent: 'center',
223
- }, children: _jsx(Text, { sx: { color: 'fg.muted', fontSize: 0 }, children: "Ask the agent to generate code to see it here." }) })) })] }), flash && (_jsx(Flash, { variant: flash.includes('accepted')
224
- ? 'success'
225
- : flash.includes('rejected')
226
- ? 'warning'
227
- : 'danger', sx: { m: 2, fontSize: 0 }, children: flash }))] })] })] }));
638
+ mt: 1,
639
+ }, children: outcome.message })] }), _jsx(ReactECharts, { option: gaugeOptionFor(config), style: {
640
+ height: 240,
641
+ minHeight: 240,
642
+ maxHeight: 240,
643
+ width: '100%',
644
+ flexShrink: 0,
645
+ } }), _jsxs(Box, { sx: {
646
+ display: 'flex',
647
+ justifyContent: 'space-between',
648
+ gap: 2,
649
+ }, children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Consumed" }), _jsxs(Text, { sx: { fontSize: 0, fontWeight: 'bold' }, children: [(consumedByAgent[config.key] ?? 0).toLocaleString(), " tokens"] })] }), agentIdByKey[config.key] && (_jsx(ContextPanel, { agentId: agentIdByKey[config.key], apiBase: config.baseUrl, liveData: contextSnapshotByKey[config.key] ?? null, chartHeight: "180px" }))] }, config.key));
650
+ })())] })] }));
228
651
  };
229
- // ─── Sync token to core IAM store ──────────────────────────────────────────
230
652
  const syncTokenToIamStore = (token) => {
231
653
  import('@datalayer/core/lib/state').then(({ iamStore }) => {
232
654
  iamStore.setState({ token });
233
655
  });
234
656
  };
235
- // ─── Main component with auth gate ─────────────────────────────────────────
236
657
  const AgentCodemodeExample = () => {
237
- const { token, setAuth, clearAuth } = useSimpleAuthStore();
658
+ const { token, clearAuth } = useSimpleAuthStore();
238
659
  const hasSynced = useRef(false);
239
660
  useEffect(() => {
240
661
  if (token && !hasSynced.current) {
@@ -242,11 +663,6 @@ const AgentCodemodeExample = () => {
242
663
  syncTokenToIamStore(token);
243
664
  }
244
665
  }, [token]);
245
- const handleSignIn = useCallback((newToken, handle) => {
246
- setAuth(newToken, handle);
247
- hasSynced.current = true;
248
- syncTokenToIamStore(newToken);
249
- }, [setAuth]);
250
666
  const handleLogout = useCallback(() => {
251
667
  clearAuth();
252
668
  hasSynced.current = false;
@@ -255,7 +671,7 @@ const AgentCodemodeExample = () => {
255
671
  });
256
672
  }, [clearAuth]);
257
673
  if (!token) {
258
- return (_jsx(ThemedProvider, { children: _jsx(SignInSimple, { onSignIn: handleSignIn, onApiKeySignIn: apiKey => handleSignIn(apiKey, 'api-key-user'), title: "Agent Codemode", description: "Sign in to use Codemode with structured tool outputs.", leadingIcon: _jsx(CodeIcon, { size: 24 }) }) }));
674
+ return (_jsx(ThemedProvider, { children: _jsx(AuthRequiredView, {}) }));
259
675
  }
260
676
  return (_jsx(QueryClientProvider, { client: queryClient, children: _jsx(ThemedProvider, { children: _jsx(AgentCodemodeInner, { onLogout: handleLogout }) }) }));
261
677
  };