@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,19 +1,24 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  /*
3
3
  * Copyright (c) 2025-2026 Datalayer, Inc.
4
4
  * Distributed under the terms of the Modified BSD License.
5
5
  */
6
6
  /// <reference types="vite/client" />
7
- import { useEffect, useState } from 'react';
7
+ import { useCallback, useEffect, useMemo, useState } from 'react';
8
8
  import { createRoot } from 'react-dom/client';
9
9
  import { loadJupyterConfig, JupyterReactTheme, createServerSettings, setJupyterServerUrl, setJupyterServerToken, getJupyterServerUrl, getJupyterServerToken, } from '@datalayer/jupyter-react';
10
10
  import { ServiceManager } from '@jupyterlab/services';
11
- import { DatalayerThemeProvider, DatalayerLogo, getLogoColors, themeConfigs, Box, } from '@datalayer/primer-addons';
11
+ import { DatalayerThemeProvider, DatalayerLogoText, getLogoColors, themeConfigs, Box, } from '@datalayer/primer-addons';
12
+ import { HomeIcon, SignInIcon, SignOutIcon } from '@primer/octicons-react';
13
+ import { Button } from '@primer/react';
12
14
  import { AppearanceControlsWithStore } from '@datalayer/primer-addons/lib/components/appearance';
13
15
  import { coreStore, iamStore, createDatalayerServiceManager, } from '@datalayer/core';
14
- import { useChatStore } from '../stores';
16
+ import { SignInSimple } from '@datalayer/core/lib/views/iam';
17
+ import { UserBadge } from '@datalayer/core/lib/views/profile';
18
+ import { useSimpleAuthStore } from '@datalayer/core/lib/views/otel';
19
+ import { agentRuntimeStore, useChatStore, useConversationStore, } from '../stores';
15
20
  import { OAuthCallback } from '../identity';
16
- import { EXAMPLES } from './example-selector';
21
+ import { EXAMPLES, getExampleEntries, } from './example-selector';
17
22
  import { useExampleThemeStore } from './utils/themeStore';
18
23
  import { ExampleWrapper } from './components/ExampleWrapper';
19
24
  import nbformatExample from './utils/notebooks/NotebookExample1.ipynb.json';
@@ -60,7 +65,7 @@ const loadConfigurations = () => {
60
65
  CLI: 0,
61
66
  VSCode: 0,
62
67
  },
63
- position: {},
68
+ position: 'top',
64
69
  tours: {},
65
70
  },
66
71
  events: [],
@@ -91,13 +96,15 @@ const loadConfigurations = () => {
91
96
  }
92
97
  }
93
98
  };
94
- const getExampleNames = () => Object.keys(EXAMPLES);
99
+ const getExampleEntriesList = () => getExampleEntries();
100
+ const getInitialSearchQuery = () => {
101
+ const params = new URLSearchParams(window.location.search);
102
+ return (params.get('q') || '').trim();
103
+ };
95
104
  // Check if we're on the notebook-only route
96
105
  const isNotebookOnlyRoute = () => {
97
106
  const path = window.location.pathname;
98
- console.log('Current pathname:', path);
99
107
  const isNotebookRoute = path === '/datalayer/notebook';
100
- console.log('Is notebook-only route:', isNotebookRoute);
101
108
  return isNotebookRoute;
102
109
  };
103
110
  // Check if we're handling an OAuth callback (code and state in URL params)
@@ -116,6 +123,34 @@ const getDefaultExampleName = () => {
116
123
  }
117
124
  return 'NotebookExample';
118
125
  };
126
+ const parseJwtPayload = (token) => {
127
+ const parts = token.split('.');
128
+ if (parts.length !== 3 || !parts[1]) {
129
+ return null;
130
+ }
131
+ try {
132
+ const base64 = parts[1].replace(/-/g, '+').replace(/_/g, '/');
133
+ const padded = base64.padEnd(Math.ceil(base64.length / 4) * 4, '=');
134
+ const decoded = atob(padded);
135
+ return JSON.parse(decoded);
136
+ }
137
+ catch {
138
+ return null;
139
+ }
140
+ };
141
+ const isExpiredJwt = (token) => {
142
+ const payload = parseJwtPayload(token);
143
+ if (!payload) {
144
+ // Non-JWT tokens (for example API keys) should not be treated as expired.
145
+ return false;
146
+ }
147
+ const exp = payload.exp;
148
+ if (typeof exp !== 'number') {
149
+ return false;
150
+ }
151
+ const nowSeconds = Math.floor(Date.now() / 1000);
152
+ return nowSeconds >= exp;
153
+ };
119
154
  // Notebook-only component for iframe display - renders ONLY the notebook without any UI chrome
120
155
  const NotebookOnlyApp = () => {
121
156
  const [serviceManager, setServiceManager] = useState(null);
@@ -139,7 +174,6 @@ const NotebookOnlyApp = () => {
139
174
  runUrl: configuration.runUrl,
140
175
  token: configuration.token,
141
176
  });
142
- console.log('[NotebookOnlyApp] Created collaboration provider:', provider);
143
177
  setCollaborationProvider(provider);
144
178
  }
145
179
  catch (error) {
@@ -193,11 +227,6 @@ const NotebookOnlyApp = () => {
193
227
  return null;
194
228
  }
195
229
  const NOTEBOOK_ID = '01JZQRQ35GG871QQCZW9TB1A8J';
196
- console.log('[NotebookOnlyApp] Rendering with:', {
197
- hasServiceManager: !!serviceManager,
198
- hasCollaborationProvider: !!collaborationProvider,
199
- notebookId: NOTEBOOK_ID,
200
- });
201
230
  return (_jsx(JupyterReactTheme, { children: _jsx("div", { style: { width: '100vw', height: '100vh' }, children: _jsx(NotebookComponent, { id: NOTEBOOK_ID, height: "100vh", nbformat: nbformat, readonly: false, serviceManager: serviceManager, startDefaultKernel: true, collaborationProvider: collaborationProvider }) }) }));
202
231
  };
203
232
  // Main App component that loads and renders the selected example
@@ -207,7 +236,26 @@ export const ExampleApp = () => {
207
236
  const [error, setError] = useState(null);
208
237
  const [serviceManager, setServiceManager] = useState(null);
209
238
  const [selectedExample, setSelectedExample] = useState(getDefaultExampleName());
239
+ const [searchQuery, setSearchQuery] = useState(getInitialSearchQuery());
210
240
  const [isChangingExample, setIsChangingExample] = useState(false);
241
+ const filteredExampleEntries = useMemo(() => {
242
+ const normalized = searchQuery.trim().toLowerCase();
243
+ const all = getExampleEntriesList();
244
+ if (!normalized) {
245
+ return all;
246
+ }
247
+ return all.filter(entry => {
248
+ const haystack = [
249
+ entry.id,
250
+ entry.title,
251
+ entry.description,
252
+ entry.tags.join(' '),
253
+ ]
254
+ .join(' ')
255
+ .toLowerCase();
256
+ return haystack.includes(normalized);
257
+ });
258
+ }, [searchQuery]);
211
259
  const loadExample = async (exampleName, _manager) => {
212
260
  try {
213
261
  setIsChangingExample(true);
@@ -276,8 +324,75 @@ export const ExampleApp = () => {
276
324
  const handleExampleChange = async (newExample) => {
277
325
  if (newExample === selectedExample || !serviceManager)
278
326
  return;
279
- // Clear chat store when changing examples to start fresh
280
- useChatStore.getState().clearMessages();
327
+ // 1) Unmount the current example FIRST so its useEffect cleanup hooks
328
+ // (e.g. AGUIAdapter.disconnect → /ag-ui/terminate, abort fetches,
329
+ // close runtime sandboxes) run against a still-valid store state.
330
+ setIsChangingExample(true);
331
+ setExampleComponent(null);
332
+ // Yield to React so the unmount actually commits before we wipe stores.
333
+ await new Promise(resolve => {
334
+ requestAnimationFrame(() => resolve());
335
+ });
336
+ // 2) Tear down any server-side agents created by the previous example.
337
+ // Each example caches its agent id in sessionStorage via
338
+ // `uniqueAgentId(baseName)` under key `agent-runtimes:agentId:<base>`.
339
+ // Delete those agents on the server and drop the cached ids so the
340
+ // next example (and a future re-entry into this one) boots fresh.
341
+ const agentBaseUrl = import.meta.env.VITE_BASE_URL || 'http://localhost:8765';
342
+ const token = useSimpleAuthStore.getState().token;
343
+ const agentIdKeys = [];
344
+ try {
345
+ for (let i = 0; i < sessionStorage.length; i++) {
346
+ const key = sessionStorage.key(i);
347
+ if (key && key.startsWith('agent-runtimes:agentId:')) {
348
+ agentIdKeys.push(key);
349
+ }
350
+ }
351
+ }
352
+ catch {
353
+ // sessionStorage unavailable; skip teardown.
354
+ }
355
+ await Promise.all(agentIdKeys.map(async (key) => {
356
+ let agentId = null;
357
+ try {
358
+ agentId = sessionStorage.getItem(key);
359
+ }
360
+ catch {
361
+ /* ignore */
362
+ }
363
+ if (!agentId)
364
+ return;
365
+ try {
366
+ await fetch(`${agentBaseUrl}/api/v1/agents/${encodeURIComponent(agentId)}`, {
367
+ method: 'DELETE',
368
+ headers: token ? { Authorization: `Bearer ${token}` } : {},
369
+ });
370
+ }
371
+ catch {
372
+ // Best-effort teardown: ignore network / 404 errors.
373
+ }
374
+ try {
375
+ sessionStorage.removeItem(key);
376
+ }
377
+ catch {
378
+ /* ignore */
379
+ }
380
+ }));
381
+ // 3) Wipe every piece of in-process agent state so the next example boots
382
+ // with a clean slate (no leftover messages, threads, pending tool
383
+ // calls, code sandbox snapshots, monitoring caches, or sockets).
384
+ useChatStore.getState().reset();
385
+ useConversationStore.getState().clearAll();
386
+ agentRuntimeStore.getState().reset();
387
+ // 4) Drop the persisted slice from localStorage so a fresh example never
388
+ // rehydrates a previous example's agents / monitoring cache.
389
+ try {
390
+ localStorage.removeItem('agent-runtimes-storage');
391
+ }
392
+ catch {
393
+ // Ignore storage failures (e.g. private mode).
394
+ }
395
+ // 5) Load and mount the new example.
281
396
  setSelectedExample(newExample);
282
397
  localStorage.setItem('selectedExample', newExample);
283
398
  await loadExample(newExample, serviceManager);
@@ -297,16 +412,55 @@ export const ExampleApp = () => {
297
412
  if (serviceManager) {
298
413
  exampleProps.serviceManager = serviceManager;
299
414
  }
300
- return (_jsx(ExampleAppThemed, { selectedExample: selectedExample, isChangingExample: isChangingExample, error: error, ExampleComponent: ExampleComponent, exampleProps: exampleProps, onExampleChange: handleExampleChange }));
415
+ exampleProps.examples = filteredExampleEntries.filter(entry => entry.id !== 'HomeExample');
416
+ exampleProps.searchQuery = searchQuery;
417
+ exampleProps.onSearchChange = (value) => setSearchQuery(value);
418
+ exampleProps.onSelectExample = (name) => {
419
+ void handleExampleChange(name);
420
+ };
421
+ return (_jsx(ExampleAppThemed, { selectedExample: selectedExample, isChangingExample: isChangingExample, error: error, ExampleComponent: ExampleComponent, exampleProps: exampleProps, onExampleChange: handleExampleChange, availableExamples: getExampleEntriesList() }));
301
422
  };
302
423
  /**
303
424
  * Inner shell that reads from the theme store and wires
304
425
  * DatalayerThemeProvider + the header bar with selectors.
305
426
  */
306
- const ExampleAppThemed = ({ selectedExample, isChangingExample, error, ExampleComponent, exampleProps, onExampleChange, }) => {
427
+ const ExampleAppThemed = ({ selectedExample, isChangingExample, error, ExampleComponent, exampleProps, onExampleChange, availableExamples, }) => {
307
428
  const { colorMode, theme: themeVariant } = useExampleThemeStore();
308
429
  const cfg = themeConfigs[themeVariant];
309
430
  const logoColors = getLogoColors(themeVariant, colorMode);
431
+ const { token, setAuth, clearAuth } = useSimpleAuthStore();
432
+ const [showSignIn, setShowSignIn] = useState(false);
433
+ const shouldShowAuthScreen = showSignIn && !token;
434
+ const syncTokenToIamStore = useCallback((newToken) => {
435
+ import('@datalayer/core/lib/state').then(({ iamStore: coreIamStore }) => {
436
+ coreIamStore.setState({ token: newToken });
437
+ });
438
+ }, []);
439
+ useEffect(() => {
440
+ // Keep iamStore aligned with persisted auth token on app load/refresh.
441
+ syncTokenToIamStore(token || undefined);
442
+ }, [token, syncTokenToIamStore]);
443
+ useEffect(() => {
444
+ if (!token) {
445
+ setShowSignIn(true);
446
+ return;
447
+ }
448
+ if (isExpiredJwt(token)) {
449
+ clearAuth();
450
+ syncTokenToIamStore(undefined);
451
+ setShowSignIn(true);
452
+ }
453
+ }, [token, clearAuth, syncTokenToIamStore]);
454
+ const handleHeaderSignIn = useCallback((newToken, handle) => {
455
+ setAuth(newToken, handle);
456
+ syncTokenToIamStore(newToken);
457
+ setShowSignIn(false);
458
+ }, [setAuth, syncTokenToIamStore]);
459
+ const handleHeaderLogout = useCallback(() => {
460
+ clearAuth();
461
+ syncTokenToIamStore(undefined);
462
+ setShowSignIn(true);
463
+ }, [clearAuth, syncTokenToIamStore]);
310
464
  return (_jsx(DatalayerThemeProvider, { colorMode: colorMode, theme: cfg.primerTheme, themeStyles: cfg.themeStyles, children: _jsxs(Box, { sx: {
311
465
  width: '100vw',
312
466
  height: '100vh',
@@ -328,7 +482,19 @@ const ExampleAppThemed = ({ selectedExample, isChangingExample, error, ExampleCo
328
482
  bg: 'canvas.subtle',
329
483
  borderBottom: '1px solid',
330
484
  borderColor: 'border.default',
331
- }, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(Box, { as: "select", value: selectedExample, onChange: (e) => onExampleChange(e.target.value), disabled: isChangingExample, sx: {
485
+ }, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(Box, { as: "button", onClick: () => void onExampleChange('HomeExample'), title: "Home", "aria-label": "Go to examples home", sx: {
486
+ display: 'inline-flex',
487
+ alignItems: 'center',
488
+ justifyContent: 'center',
489
+ width: '32px',
490
+ height: '32px',
491
+ border: '1px solid',
492
+ borderColor: 'border.default',
493
+ borderRadius: 2,
494
+ bg: 'canvas.default',
495
+ color: 'fg.default',
496
+ cursor: isChangingExample ? 'not-allowed' : 'pointer',
497
+ }, disabled: isChangingExample, children: _jsx(HomeIcon, { size: 16 }) }), _jsx(Box, { as: "select", value: selectedExample, onChange: (e) => onExampleChange(e.target.value), disabled: isChangingExample, sx: {
332
498
  px: 2,
333
499
  py: '6px',
334
500
  fontSize: 1,
@@ -344,13 +510,80 @@ const ExampleAppThemed = ({ selectedExample, isChangingExample, error, ExampleCo
344
510
  '&:focus-visible': {
345
511
  boxShadow: '0 0 0 2px var(--bgColor-accent-muted, rgba(9,105,218,0.3))',
346
512
  },
347
- }, children: getExampleNames()
348
- .sort()
349
- .map(name => (_jsx("option", { value: name, children: name }, name))) }), isChangingExample && (_jsx(Box, { as: "span", sx: { color: 'fg.muted', fontSize: 0 }, children: "Loading\u2026" })), error && (_jsxs(Box, { as: "span", sx: { color: 'danger.fg', fontSize: 0 }, children: ["Error: ", error] }))] }), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 3 }, children: [_jsx(AppearanceControlsWithStore, { useStore: useExampleThemeStore }), _jsx(DatalayerLogo, { size: 24, primaryColor: logoColors.primary, secondaryColor: logoColors.secondary })] })] }), _jsx(Box, { sx: {
513
+ }, children: (() => {
514
+ const home = availableExamples.find(e => e.id === 'HomeExample');
515
+ const rest = availableExamples.filter(e => e.id !== 'HomeExample');
516
+ // Classify each example into a named group.
517
+ const groupOf = (id) => {
518
+ if (id === 'AgentspecsExample')
519
+ return 'Personas';
520
+ if (id.startsWith('A2Ui'))
521
+ return 'A2UI';
522
+ if (id.startsWith('AgUi'))
523
+ return 'AG-UI';
524
+ if (id.startsWith('CopilotKit'))
525
+ return 'CopilotKit';
526
+ if (id.startsWith('Agent'))
527
+ return 'Agent';
528
+ if (id.startsWith('Chat'))
529
+ return 'Chat';
530
+ if (id.startsWith('Lexical'))
531
+ return 'Lexical';
532
+ if (id.startsWith('Notebook') ||
533
+ id === 'NotebookCollaborationExample')
534
+ return 'Notebook';
535
+ return 'Cell';
536
+ };
537
+ const groupOrder = [
538
+ 'Personas',
539
+ 'A2UI',
540
+ 'AG-UI',
541
+ 'Agent',
542
+ 'Chat',
543
+ 'Lexical',
544
+ 'Notebook',
545
+ 'Cell',
546
+ 'CopilotKit',
547
+ ];
548
+ const grouped = new Map();
549
+ for (const ex of rest) {
550
+ const g = groupOf(ex.id);
551
+ if (!grouped.has(g))
552
+ grouped.set(g, []);
553
+ grouped.get(g).push(ex);
554
+ }
555
+ for (const list of grouped.values()) {
556
+ list.sort((a, b) => a.title.localeCompare(b.title));
557
+ }
558
+ const nodes = [];
559
+ if (home) {
560
+ nodes.push(_jsx("option", { value: home.id, disabled: home.id === selectedExample, children: home.title }, home.id));
561
+ }
562
+ let sepIndex = 0;
563
+ for (const g of groupOrder) {
564
+ const items = grouped.get(g);
565
+ if (!items || items.length === 0)
566
+ continue;
567
+ nodes.push(_jsxs("option", { disabled: true, value: `__sep_${sepIndex}`, children: ["\u2500\u2500\u2500\u2500\u2500\u2500 ", g, " \u2500\u2500\u2500\u2500\u2500\u2500"] }, `__sep_${sepIndex++}`));
568
+ for (const example of items) {
569
+ nodes.push(_jsx("option", { value: example.id, disabled: example.id === selectedExample, children: example.title }, example.id));
570
+ }
571
+ }
572
+ return _jsx(_Fragment, { children: nodes });
573
+ })() }), isChangingExample && (_jsx(Box, { as: "span", sx: { color: 'fg.muted', fontSize: 0 }, children: "Loading\u2026" })), error && (_jsxs(Box, { as: "span", sx: { color: 'danger.fg', fontSize: 0 }, children: ["Error: ", error] }))] }), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 3 }, children: [_jsx(AppearanceControlsWithStore, { useStore: useExampleThemeStore }), _jsx(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: token ? (_jsxs(_Fragment, { children: [_jsx(UserBadge, { token: token, variant: "small", onTokenExpired: () => {
574
+ handleHeaderLogout();
575
+ setShowSignIn(true);
576
+ } }), _jsx(Button, { size: "small", variant: "invisible", onClick: handleHeaderLogout, leadingVisual: SignOutIcon, sx: { color: 'fg.muted' }, children: "Sign out" })] })) : (_jsx(Button, { size: "small", variant: "invisible", onClick: () => setShowSignIn(true), leadingVisual: SignInIcon, sx: { color: 'fg.muted' }, children: "Sign in" })) }), _jsx(Box, { as: "a", href: "https://datalayer.ai", target: "_blank", rel: "noopener noreferrer", "aria-label": "Open Datalayer website", sx: { display: 'inline-flex', alignItems: 'center' }, children: _jsx(DatalayerLogoText, { size: 24, variant: themeVariant, colorMode: colorMode, primaryColor: logoColors.primary, secondaryColor: logoColors.secondary, textColor: logoColors.textColor, primaryGradient: logoColors.primaryGradient, secondaryGradient: logoColors.secondaryGradient, gradient: true }) })] })] }), _jsx(Box, { sx: {
350
577
  marginTop: '60px',
351
578
  height: 'calc(100vh - 60px)',
352
579
  overflow: 'hidden',
353
- }, children: isChangingExample ? (_jsxs(Box, { sx: { p: 5, textAlign: 'center', color: 'fg.muted' }, children: [_jsxs("h3", { children: ["Loading ", selectedExample, "\u2026"] }), _jsx("p", { children: "Please wait while the example loads." })] })) : ExampleComponent ? (_jsx(ExampleWrapper, { children: _jsx(ExampleComponent, { ...exampleProps }) })) : null })] }) }));
580
+ }, children: shouldShowAuthScreen ? (_jsx(Box, { sx: {
581
+ width: '100%',
582
+ height: '100%',
583
+ bg: 'canvas.backdrop',
584
+ p: 3,
585
+ overflow: 'auto',
586
+ }, children: _jsx(Box, { sx: { maxWidth: 640, mx: 'auto' }, children: _jsx(SignInSimple, { onSignIn: handleHeaderSignIn, onApiKeySignIn: apiKey => handleHeaderSignIn(apiKey, 'api-key-user'), title: "Agent Runtimes Examples", description: "Sign in to run authenticated examples and tools.", leadingIcon: _jsx(HomeIcon, { size: 24 }) }) }) })) : isChangingExample ? (_jsxs(Box, { sx: { p: 5, textAlign: 'center', color: 'fg.muted' }, children: [_jsxs("h3", { children: ["Loading ", selectedExample, "\u2026"] }), _jsx("p", { children: "Please wait while the example loads." })] })) : ExampleComponent ? (_jsx(ExampleWrapper, { children: _jsx(ExampleComponent, { ...exampleProps }, selectedExample) }, selectedExample)) : null })] }) }));
354
587
  };
355
588
  // Mount the app - check route to determine which app to render
356
589
  const root = document.getElementById('root');
@@ -359,15 +592,12 @@ if (root) {
359
592
  (window.__agentRuntimesExamplesRoot = createRoot(root));
360
593
  if (isOAuthCallback()) {
361
594
  // Handle OAuth callback - render OAuthCallback component
362
- console.log('Rendering OAuthCallback (popup flow)');
363
595
  appRoot.render(_jsx(JupyterReactTheme, { children: _jsx(OAuthCallback, { autoClose: true, autoCloseDelay: 1000 }) }));
364
596
  }
365
597
  else if (isNotebookOnlyRoute()) {
366
- console.log('Rendering NotebookOnlyApp');
367
598
  appRoot.render(_jsx(NotebookOnlyApp, {}));
368
599
  }
369
600
  else {
370
- console.log('Rendering ExampleApp');
371
601
  appRoot.render(_jsx(ExampleApp, {}));
372
602
  }
373
603
  }
@@ -0,0 +1,18 @@
1
+ import { type ReactComponentImplementation } from '@a2ui/react/v0_9';
2
+ import { MessageProcessor, type A2uiClientAction, type A2uiMessage, type SurfaceModel } from '@a2ui/web_core/v0_9';
3
+ export type A2uiProcessor = MessageProcessor<ReactComponentImplementation>;
4
+ export type A2uiSurfaceModel = SurfaceModel<ReactComponentImplementation>;
5
+ export declare function useA2uiProcessor(onAction?: (action: A2uiClientAction) => void): {
6
+ processor: MessageProcessor<ReactComponentImplementation>;
7
+ surfaces: A2uiSurfaceModel[];
8
+ processMessages: (messages: A2uiMessage[]) => void;
9
+ resetSurfaces: () => void;
10
+ };
11
+ export declare function createSceneMessages(args: {
12
+ surfaceId: string;
13
+ components: Array<Record<string, unknown>>;
14
+ value?: Record<string, unknown>;
15
+ path?: string;
16
+ theme?: Record<string, unknown>;
17
+ sendDataModel?: boolean;
18
+ }): A2uiMessage[];
@@ -0,0 +1,69 @@
1
+ /*
2
+ * Copyright (c) 2025-2026 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ import { useCallback, useEffect, useMemo, useState } from 'react';
6
+ import { basicCatalog, } from '@a2ui/react/v0_9';
7
+ import { MessageProcessor, } from '@a2ui/web_core/v0_9';
8
+ export function useA2uiProcessor(onAction) {
9
+ const processor = useMemo(() => new MessageProcessor([basicCatalog], onAction), [onAction]);
10
+ const [surfaces, setSurfaces] = useState(() => Array.from(processor.model.surfacesMap.values()));
11
+ useEffect(() => {
12
+ const createdSub = processor.onSurfaceCreated(surface => {
13
+ setSurfaces(prev => [...prev, surface]);
14
+ });
15
+ const deletedSub = processor.onSurfaceDeleted(id => {
16
+ setSurfaces(prev => prev.filter(surface => surface.id !== id));
17
+ });
18
+ return () => {
19
+ createdSub.unsubscribe();
20
+ deletedSub.unsubscribe();
21
+ };
22
+ }, [processor]);
23
+ const processMessages = useCallback((messages) => {
24
+ processor.processMessages(messages);
25
+ }, [processor]);
26
+ const resetSurfaces = useCallback(() => {
27
+ Array.from(processor.model.surfacesMap.keys()).forEach(id => {
28
+ processor.model.deleteSurface(id);
29
+ });
30
+ }, [processor]);
31
+ return {
32
+ processor,
33
+ surfaces,
34
+ processMessages,
35
+ resetSurfaces,
36
+ };
37
+ }
38
+ export function createSceneMessages(args) {
39
+ const { surfaceId, components, value, path = '/', theme, sendDataModel = true, } = args;
40
+ const messages = [
41
+ {
42
+ version: 'v0.9',
43
+ createSurface: {
44
+ surfaceId,
45
+ catalogId: basicCatalog.id,
46
+ theme,
47
+ sendDataModel,
48
+ },
49
+ },
50
+ {
51
+ version: 'v0.9',
52
+ updateComponents: {
53
+ surfaceId,
54
+ components,
55
+ },
56
+ },
57
+ ];
58
+ if (value !== undefined) {
59
+ messages.push({
60
+ version: 'v0.9',
61
+ updateDataModel: {
62
+ surfaceId,
63
+ path,
64
+ value,
65
+ },
66
+ });
67
+ }
68
+ return messages;
69
+ }
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ /**
3
+ * Provides the A2UI v0.9 markdown renderer to all child `A2uiSurface`
4
+ * instances. Without it, `Text` components fall back to the raw markdown
5
+ * string (e.g. `## Title` instead of a rendered `<h2>`).
6
+ */
7
+ export declare const A2uiMarkdownProvider: React.FC<React.PropsWithChildren>;
@@ -0,0 +1,9 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { MarkdownContext } from '@a2ui/react/v0_9';
3
+ import { renderMarkdown } from '@a2ui/markdown-it';
4
+ /**
5
+ * Provides the A2UI v0.9 markdown renderer to all child `A2uiSurface`
6
+ * instances. Without it, `Text` components fall back to the raw markdown
7
+ * string (e.g. `## Title` instead of a rendered `<h2>`).
8
+ */
9
+ export const A2uiMarkdownProvider = ({ children, }) => (_jsx(MarkdownContext.Provider, { value: renderMarkdown, children: children }));
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Build a unique agent ID by appending a random slug to a base name.
3
+ *
4
+ * The resulting id is cached in ``sessionStorage`` under a key derived from
5
+ * ``baseName``, so a browser refresh within the same tab reuses the same
6
+ * agent id. This is required for server-side per-agent state (enabled
7
+ * tools, approved tools, approved skills, codemode status…) to survive a
8
+ * page reload — those maps are keyed by ``agent_id`` in
9
+ * ``agent_runtimes.streams.loop``.
10
+ *
11
+ * A fresh tab (or a ``sessionStorage.clear()``) produces a new id, which
12
+ * preserves the original "clean telemetry per run" guarantee.
13
+ *
14
+ * @example
15
+ * uniqueAgentId('simple') // → "simple-a3f7b2" (cached)
16
+ * uniqueAgentId('codemode-demo') // → "codemode-example-k9x2m1" (cached)
17
+ */
18
+ export declare function uniqueAgentId(baseName: string): string;
@@ -0,0 +1,54 @@
1
+ /*
2
+ * Copyright (c) 2025-2026 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ /**
6
+ * Generate a short random alphanumeric slug (e.g. "a3f7b2").
7
+ * Used to make agent IDs unique per session so that each fresh
8
+ * example run starts with clean OTEL / telemetry data.
9
+ */
10
+ function randomSlug(length = 6) {
11
+ const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
12
+ let slug = '';
13
+ const array = new Uint8Array(length);
14
+ crypto.getRandomValues(array);
15
+ for (let i = 0; i < length; i++) {
16
+ slug += chars[array[i] % chars.length];
17
+ }
18
+ return slug;
19
+ }
20
+ /**
21
+ * Build a unique agent ID by appending a random slug to a base name.
22
+ *
23
+ * The resulting id is cached in ``sessionStorage`` under a key derived from
24
+ * ``baseName``, so a browser refresh within the same tab reuses the same
25
+ * agent id. This is required for server-side per-agent state (enabled
26
+ * tools, approved tools, approved skills, codemode status…) to survive a
27
+ * page reload — those maps are keyed by ``agent_id`` in
28
+ * ``agent_runtimes.streams.loop``.
29
+ *
30
+ * A fresh tab (or a ``sessionStorage.clear()``) produces a new id, which
31
+ * preserves the original "clean telemetry per run" guarantee.
32
+ *
33
+ * @example
34
+ * uniqueAgentId('simple') // → "simple-a3f7b2" (cached)
35
+ * uniqueAgentId('codemode-demo') // → "codemode-example-k9x2m1" (cached)
36
+ */
37
+ export function uniqueAgentId(baseName) {
38
+ const storageKey = `agent-runtimes:agentId:${baseName}`;
39
+ try {
40
+ if (typeof sessionStorage !== 'undefined') {
41
+ const cached = sessionStorage.getItem(storageKey);
42
+ if (cached && cached.startsWith(`${baseName}-`)) {
43
+ return cached;
44
+ }
45
+ const fresh = `${baseName}-${randomSlug()}`;
46
+ sessionStorage.setItem(storageKey, fresh);
47
+ return fresh;
48
+ }
49
+ }
50
+ catch {
51
+ // sessionStorage unavailable (e.g. SSR, privacy mode); fall through.
52
+ }
53
+ return `${baseName}-${randomSlug()}`;
54
+ }
@@ -1,13 +1,13 @@
1
1
  {
2
- "id": "earthquake-detector",
3
- "title": "Earthquake Detector",
4
- "description": "Real-time seismic activity monitoring and earthquake alert system.",
5
- "image": "https://images.unsplash.com/photo-1589519160732-57fc498494f8?w=300&h=150&fit=crop",
6
- "author": "Eric Charles",
7
- "editTimestamp": "53 minutes ago",
8
- "status": "paused",
9
- "transport": "ag-ui",
10
- "avatarUrl": "https://avatars.githubusercontent.com/atom",
11
- "stars": 4,
12
- "notifications": 0
2
+ "id": "earthquake-detector",
3
+ "title": "Earthquake Detector",
4
+ "description": "Real-time seismic activity monitoring and earthquake alert system.",
5
+ "image": "https://images.unsplash.com/photo-1589519160732-57fc498494f8?w=300&h=150&fit=crop",
6
+ "author": "Eric Charles",
7
+ "editTimestamp": "53 minutes ago",
8
+ "status": "paused",
9
+ "transport": "ag-ui",
10
+ "avatarUrl": "https://avatars.githubusercontent.com/atom",
11
+ "stars": 4,
12
+ "notifications": 0
13
13
  }
@@ -1,13 +1,13 @@
1
1
  {
2
- "id": "sales-forecaster",
3
- "title": "Sales Forecaster",
4
- "description": "AI-powered sales prediction and revenue forecasting tool.",
5
- "image": "https://images.unsplash.com/photo-1460925895917-afdab827c52f?w=300&h=150&fit=crop",
6
- "author": "Eric Charles",
7
- "editTimestamp": "1 hour ago",
8
- "status": "running",
9
- "transport": "vercel-ai",
10
- "avatarUrl": "https://avatars.githubusercontent.com/github",
11
- "stars": 5,
12
- "notifications": 2
2
+ "id": "sales-forecaster",
3
+ "title": "Sales Forecaster",
4
+ "description": "AI-powered sales prediction and revenue forecasting tool.",
5
+ "image": "https://images.unsplash.com/photo-1460925895917-afdab827c52f?w=300&h=150&fit=crop",
6
+ "author": "Eric Charles",
7
+ "editTimestamp": "1 hour ago",
8
+ "status": "running",
9
+ "transport": "vercel-ai",
10
+ "avatarUrl": "https://avatars.githubusercontent.com/github",
11
+ "stars": 5,
12
+ "notifications": 2
13
13
  }