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