@datalayer/agent-runtimes 1.0.3 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (275) hide show
  1. package/README.md +35 -119
  2. package/lib/App.js +1 -1
  3. package/lib/agents/AgentDetails.d.ts +22 -1
  4. package/lib/agents/AgentDetails.js +34 -47
  5. package/lib/api/index.d.ts +0 -1
  6. package/lib/api/index.js +4 -2
  7. package/lib/chat/Chat.d.ts +5 -104
  8. package/lib/chat/Chat.js +4 -4
  9. package/lib/chat/ChatFloating.d.ts +7 -140
  10. package/lib/chat/ChatFloating.js +2 -2
  11. package/lib/chat/ChatPopupStandalone.d.ts +8 -47
  12. package/lib/chat/ChatPopupStandalone.js +3 -3
  13. package/lib/chat/ChatSidebar.d.ts +4 -69
  14. package/lib/chat/ChatSidebar.js +2 -2
  15. package/lib/chat/ChatStandalone.d.ts +4 -54
  16. package/lib/chat/ChatStandalone.js +3 -3
  17. package/lib/chat/base/ChatBase.js +1118 -141
  18. package/lib/chat/header/ChatHeaderBase.d.ts +11 -6
  19. package/lib/chat/header/ChatHeaderBase.js +18 -16
  20. package/lib/chat/indicators/McpStatusIndicator.d.ts +7 -4
  21. package/lib/chat/indicators/McpStatusIndicator.js +7 -32
  22. package/lib/chat/indicators/SandboxStatusIndicator.d.ts +4 -1
  23. package/lib/chat/indicators/SandboxStatusIndicator.js +9 -9
  24. package/lib/chat/indicators/SkillsStatusIndicator.d.ts +7 -0
  25. package/lib/chat/indicators/SkillsStatusIndicator.js +88 -0
  26. package/lib/chat/indicators/index.d.ts +1 -0
  27. package/lib/chat/indicators/index.js +1 -0
  28. package/lib/chat/messages/ChatMessageList.d.ts +1 -1
  29. package/lib/chat/messages/ChatMessageList.js +110 -102
  30. package/lib/chat/prompt/InputFooter.d.ts +19 -6
  31. package/lib/chat/prompt/InputFooter.js +71 -18
  32. package/lib/chat/prompt/InputPrompt.d.ts +3 -1
  33. package/lib/chat/prompt/InputPrompt.js +4 -4
  34. package/lib/chat/prompt/InputPromptFooter.js +1 -1
  35. package/lib/chat/prompt/InputPromptLexical.d.ts +3 -1
  36. package/lib/chat/prompt/InputPromptLexical.js +12 -5
  37. package/lib/chat/prompt/InputPromptText.d.ts +3 -1
  38. package/lib/chat/prompt/InputPromptText.js +2 -2
  39. package/lib/chat/tools/ToolApprovalBanner.js +1 -1
  40. package/lib/chat/tools/ToolCallDisplay.d.ts +3 -1
  41. package/lib/chat/tools/ToolCallDisplay.js +2 -2
  42. package/lib/chat/usage/TokenUsageBar.js +20 -2
  43. package/lib/client/AgentRuntimesClientContext.d.ts +53 -0
  44. package/lib/client/AgentRuntimesClientContext.js +55 -0
  45. package/lib/client/AgentsMixin.d.ts +48 -19
  46. package/lib/client/AgentsMixin.js +115 -30
  47. package/lib/client/IAgentRuntimesClient.d.ts +215 -0
  48. package/lib/client/IAgentRuntimesClient.js +5 -0
  49. package/lib/client/SdkAgentRuntimesClient.d.ts +151 -0
  50. package/lib/client/SdkAgentRuntimesClient.js +134 -0
  51. package/lib/client/index.d.ts +4 -1
  52. package/lib/client/index.js +3 -1
  53. package/lib/components/NotificationEventCard.js +55 -26
  54. package/lib/components/OutputCard.js +21 -7
  55. package/lib/components/ToolApprovalCard.js +20 -2
  56. package/lib/config/AgentConfiguration.js +3 -3
  57. package/lib/context/ContextDistribution.d.ts +3 -1
  58. package/lib/context/ContextDistribution.js +8 -27
  59. package/lib/context/ContextInspector.d.ts +3 -1
  60. package/lib/context/ContextInspector.js +19 -67
  61. package/lib/context/ContextPanel.d.ts +3 -1
  62. package/lib/context/ContextPanel.js +104 -64
  63. package/lib/context/ContextUsage.d.ts +3 -1
  64. package/lib/context/ContextUsage.js +3 -3
  65. package/lib/context/CostTracker.d.ts +9 -3
  66. package/lib/context/CostTracker.js +26 -47
  67. package/lib/context/CostUsageChart.d.ts +12 -0
  68. package/lib/context/CostUsageChart.js +378 -0
  69. package/lib/context/GraphFlowChart.d.ts +16 -0
  70. package/lib/context/GraphFlowChart.js +182 -0
  71. package/lib/context/TokenUsageChart.d.ts +8 -1
  72. package/lib/context/TokenUsageChart.js +349 -211
  73. package/lib/context/TurnGraphChart.d.ts +39 -0
  74. package/lib/context/TurnGraphChart.js +538 -0
  75. package/lib/context/otelWsPool.d.ts +20 -0
  76. package/lib/context/otelWsPool.js +69 -0
  77. package/lib/examples/A2UiComponentGalleryExample.d.ts +0 -17
  78. package/lib/examples/A2UiComponentGalleryExample.js +315 -522
  79. package/lib/examples/A2UiContactCardExample.d.ts +0 -18
  80. package/lib/examples/A2UiContactCardExample.js +154 -411
  81. package/lib/examples/A2UiRestaurantExample.d.ts +0 -30
  82. package/lib/examples/A2UiRestaurantExample.js +114 -212
  83. package/lib/examples/A2UiViewerExample.d.ts +0 -18
  84. package/lib/examples/A2UiViewerExample.js +283 -532
  85. package/lib/examples/AgUiBackendToolRenderingExample.js +1 -1
  86. package/lib/examples/AgUiHaikuGenUiExample.d.ts +1 -1
  87. package/lib/examples/AgUiHaikuGenUiExample.js +1 -1
  88. package/lib/examples/AgentCheckpointsExample.js +14 -34
  89. package/lib/examples/AgentCodemodeExample.d.ts +4 -6
  90. package/lib/examples/AgentCodemodeExample.js +591 -175
  91. package/lib/examples/AgentEvalsExample.js +13 -23
  92. package/lib/examples/AgentGuardrailsExample.js +371 -71
  93. package/lib/examples/AgentHooksExample.d.ts +3 -0
  94. package/lib/examples/AgentHooksExample.js +104 -0
  95. package/lib/examples/AgentMCPExample.d.ts +3 -0
  96. package/lib/examples/AgentMCPExample.js +480 -0
  97. package/lib/examples/AgentMemoryExample.js +14 -24
  98. package/lib/examples/AgentMonitoringExample.js +261 -206
  99. package/lib/examples/AgentNotificationsExample.js +50 -24
  100. package/lib/examples/AgentOtelExample.js +2 -3
  101. package/lib/examples/AgentOutputsExample.d.ts +11 -6
  102. package/lib/examples/AgentOutputsExample.js +383 -88
  103. package/lib/examples/AgentParametersExample.d.ts +3 -0
  104. package/lib/examples/AgentParametersExample.js +246 -0
  105. package/lib/examples/AgentSandboxExample.d.ts +2 -2
  106. package/lib/examples/AgentSandboxExample.js +69 -47
  107. package/lib/examples/AgentSkillsExample.js +92 -106
  108. package/lib/examples/{AgentspecExample.js → AgentSpecsExample.js} +10 -21
  109. package/lib/examples/AgentSubagentsExample.d.ts +14 -0
  110. package/lib/examples/AgentSubagentsExample.js +228 -0
  111. package/lib/examples/AgentToolApprovalsExample.js +30 -493
  112. package/lib/examples/AgentTriggersExample.js +1067 -246
  113. package/lib/examples/ChatCustomExample.js +11 -24
  114. package/lib/examples/ChatExample.js +9 -34
  115. package/lib/examples/CopilotKitLexicalExample.js +2 -1
  116. package/lib/examples/CopilotKitNotebookExample.js +2 -1
  117. package/lib/examples/HomeExample.d.ts +15 -0
  118. package/lib/examples/HomeExample.js +77 -0
  119. package/lib/examples/Lexical2Example.js +4 -2
  120. package/lib/examples/{LexicalExample.d.ts → LexicalAgentExample.d.ts} +4 -4
  121. package/lib/examples/{LexicalExample.js → LexicalAgentExample.js} +65 -16
  122. package/lib/examples/{LexicalSidebarExample.d.ts → LexicalAgentSidebarExample.d.ts} +5 -5
  123. package/lib/examples/LexicalAgentSidebarExample.js +261 -0
  124. package/lib/examples/NotebookAgentExample.d.ts +9 -0
  125. package/lib/examples/NotebookAgentExample.js +192 -0
  126. package/lib/examples/{NotebookSidebarExample.d.ts → NotebookAgentSidebarExample.d.ts} +2 -2
  127. package/lib/examples/NotebookAgentSidebarExample.js +221 -0
  128. package/lib/examples/{DatalayerNotebookExample.d.ts → NotebookCollaborationExample.d.ts} +4 -4
  129. package/lib/examples/{DatalayerNotebookExample.js → NotebookCollaborationExample.js} +3 -3
  130. package/lib/examples/NotebookExample.d.ts +4 -7
  131. package/lib/examples/NotebookExample.js +14 -146
  132. package/lib/examples/components/AuthRequiredView.d.ts +6 -0
  133. package/lib/examples/components/AuthRequiredView.js +33 -0
  134. package/lib/examples/components/ErrorView.d.ts +14 -0
  135. package/lib/examples/components/ErrorView.js +20 -0
  136. package/lib/examples/components/ExampleWrapper.d.ts +7 -0
  137. package/lib/examples/components/ExampleWrapper.js +25 -6
  138. package/lib/examples/{ag-ui → components}/haiku/HaikuDisplay.js +1 -1
  139. package/lib/examples/{ag-ui → components}/haiku/InlineHaikuCard.js +1 -1
  140. package/lib/examples/{ag-ui → components}/haiku/index.d.ts +1 -1
  141. package/lib/examples/{ag-ui → components}/haiku/index.js +1 -1
  142. package/lib/examples/components/index.d.ts +5 -0
  143. package/lib/examples/components/index.js +5 -0
  144. package/lib/examples/{ag-ui → components}/weather/index.d.ts +1 -1
  145. package/lib/examples/{ag-ui → components}/weather/index.js +1 -1
  146. package/lib/examples/example-selector.d.ts +17 -4
  147. package/lib/examples/example-selector.js +107 -41
  148. package/lib/examples/index.d.ts +9 -6
  149. package/lib/examples/index.js +9 -6
  150. package/lib/examples/main.d.ts +1 -0
  151. package/lib/examples/main.js +218 -27
  152. package/lib/examples/utils/a2ui.d.ts +18 -0
  153. package/lib/examples/utils/a2ui.js +69 -0
  154. package/lib/examples/utils/a2uiMarkdownProvider.d.ts +7 -0
  155. package/lib/examples/utils/a2uiMarkdownProvider.js +9 -0
  156. package/lib/examples/utils/agentId.d.ts +18 -0
  157. package/lib/examples/utils/agentId.js +54 -0
  158. package/lib/examples/utils/agents/earthquake-detector.json +11 -11
  159. package/lib/examples/utils/agents/sales-forecaster.json +11 -11
  160. package/lib/examples/utils/agents/social-post-generator.json +11 -11
  161. package/lib/examples/utils/agents/stock-market.json +11 -11
  162. package/lib/examples/utils/examplesStore.js +82 -27
  163. package/lib/hooks/index.d.ts +8 -8
  164. package/lib/hooks/index.js +7 -7
  165. package/lib/hooks/useA2A.d.ts +2 -3
  166. package/lib/hooks/useAIAgentsWebSocket.d.ts +43 -4
  167. package/lib/hooks/useAIAgentsWebSocket.js +118 -12
  168. package/lib/hooks/useAcp.d.ts +1 -2
  169. package/lib/hooks/useAgUi.d.ts +1 -1
  170. package/lib/hooks/{useAgents.d.ts → useAgentRuntimes.d.ts} +39 -2
  171. package/lib/hooks/{useAgents.js → useAgentRuntimes.js} +125 -15
  172. package/lib/hooks/useAgentsCatalog.js +1 -1
  173. package/lib/hooks/useAgentsService.d.ts +2 -2
  174. package/lib/hooks/useAgentsService.js +7 -7
  175. package/lib/hooks/useCheckpoints.js +1 -1
  176. package/lib/hooks/useConfig.d.ts +4 -1
  177. package/lib/hooks/useConfig.js +10 -3
  178. package/lib/hooks/useContextSnapshot.d.ts +9 -4
  179. package/lib/hooks/useContextSnapshot.js +9 -37
  180. package/lib/hooks/useMonitoring.js +3 -0
  181. package/lib/hooks/useSandbox.d.ts +20 -8
  182. package/lib/hooks/useSandbox.js +105 -40
  183. package/lib/hooks/useSkills.d.ts +23 -5
  184. package/lib/hooks/useSkills.js +94 -39
  185. package/lib/hooks/useToolApprovals.d.ts +60 -36
  186. package/lib/hooks/useToolApprovals.js +318 -69
  187. package/lib/hooks/useVercelAI.d.ts +1 -1
  188. package/lib/index.d.ts +2 -1
  189. package/lib/index.js +1 -0
  190. package/lib/inference/index.d.ts +0 -1
  191. package/lib/middleware/index.d.ts +0 -1
  192. package/lib/protocols/AGUIAdapter.js +6 -0
  193. package/lib/protocols/VercelAIAdapter.d.ts +9 -0
  194. package/lib/protocols/VercelAIAdapter.js +144 -26
  195. package/lib/shims/json5.d.ts +4 -0
  196. package/lib/shims/json5.js +8 -0
  197. package/lib/specs/agents/agents.d.ts +10 -0
  198. package/lib/specs/agents/agents.js +752 -24
  199. package/lib/specs/envvars.d.ts +1 -0
  200. package/lib/specs/envvars.js +11 -0
  201. package/lib/specs/events.d.ts +1 -0
  202. package/lib/specs/events.js +1 -0
  203. package/lib/specs/index.d.ts +1 -0
  204. package/lib/specs/index.js +1 -0
  205. package/lib/specs/personas.d.ts +41 -0
  206. package/lib/specs/personas.js +168 -0
  207. package/lib/specs/skills.d.ts +2 -1
  208. package/lib/specs/skills.js +23 -5
  209. package/lib/specs/tools.js +3 -0
  210. package/lib/stores/agentRuntimeStore.d.ts +204 -0
  211. package/lib/stores/agentRuntimeStore.js +636 -0
  212. package/lib/stores/index.d.ts +1 -1
  213. package/lib/stores/index.js +1 -1
  214. package/lib/tools/adapters/copilotkit/lexicalHooks.d.ts +1 -2
  215. package/lib/tools/adapters/copilotkit/lexicalHooks.js +1 -3
  216. package/lib/tools/adapters/copilotkit/notebookHooks.d.ts +1 -2
  217. package/lib/tools/adapters/copilotkit/notebookHooks.js +1 -3
  218. package/lib/tools/index.d.ts +0 -2
  219. package/lib/tools/index.js +0 -1
  220. package/lib/types/agentspecs.d.ts +50 -1
  221. package/lib/types/chat.d.ts +309 -8
  222. package/lib/types/context.d.ts +27 -0
  223. package/lib/types/cost.d.ts +2 -2
  224. package/lib/types/index.d.ts +2 -0
  225. package/lib/types/index.js +2 -0
  226. package/lib/types/mcp.d.ts +8 -0
  227. package/lib/types/models.d.ts +2 -2
  228. package/lib/types/personas.d.ts +25 -0
  229. package/lib/types/personas.js +5 -0
  230. package/lib/types/skills.d.ts +43 -1
  231. package/lib/types/stream.d.ts +110 -0
  232. package/lib/types/stream.js +36 -0
  233. package/lib/types/tools.d.ts +2 -0
  234. package/lib/utils/utils.d.ts +9 -5
  235. package/lib/utils/utils.js +9 -5
  236. package/package.json +13 -9
  237. package/scripts/codegen/__pycache__/generate_agents.cpython-313.pyc +0 -0
  238. package/scripts/codegen/__pycache__/generate_events.cpython-313.pyc +0 -0
  239. package/scripts/codegen/__pycache__/versioning.cpython-313.pyc +0 -0
  240. package/scripts/codegen/generate_agents.py +106 -7
  241. package/scripts/codegen/generate_events.py +47 -17
  242. package/scripts/codegen/generate_personas.py +319 -0
  243. package/scripts/codegen/generate_skills.py +9 -9
  244. package/scripts/codegen/generate_tools.py +20 -0
  245. package/scripts/sync-jupyter.sh +26 -7
  246. package/style/primer-primitives.css +1 -6
  247. package/lib/api/tool-approvals.d.ts +0 -62
  248. package/lib/api/tool-approvals.js +0 -145
  249. package/lib/examples/LexicalSidebarExample.js +0 -163
  250. package/lib/examples/NotebookSidebarExample.js +0 -119
  251. package/lib/examples/NotebookSimpleExample.d.ts +0 -6
  252. package/lib/examples/NotebookSimpleExample.js +0 -22
  253. package/lib/examples/ag-ui/index.d.ts +0 -10
  254. package/lib/examples/ag-ui/index.js +0 -16
  255. package/lib/hooks/useAgentsRegistry.d.ts +0 -10
  256. package/lib/hooks/useAgentsRegistry.js +0 -20
  257. package/lib/stores/agentsStore.d.ts +0 -123
  258. package/lib/stores/agentsStore.js +0 -270
  259. package/scripts/codegen/__pycache__/generate_envvars.cpython-313.pyc +0 -0
  260. package/scripts/codegen/__pycache__/generate_evals.cpython-313.pyc +0 -0
  261. package/scripts/codegen/__pycache__/generate_guardrails.cpython-313.pyc +0 -0
  262. package/scripts/codegen/__pycache__/generate_mcp_servers.cpython-313.pyc +0 -0
  263. package/scripts/codegen/__pycache__/generate_memory.cpython-313.pyc +0 -0
  264. package/scripts/codegen/__pycache__/generate_models.cpython-313.pyc +0 -0
  265. package/scripts/codegen/__pycache__/generate_notifications.cpython-313.pyc +0 -0
  266. package/scripts/codegen/__pycache__/generate_outputs.cpython-313.pyc +0 -0
  267. package/scripts/codegen/__pycache__/generate_skills.cpython-313.pyc +0 -0
  268. package/scripts/codegen/__pycache__/generate_teams.cpython-313.pyc +0 -0
  269. package/scripts/codegen/__pycache__/generate_tools.cpython-313.pyc +0 -0
  270. package/scripts/codegen/__pycache__/generate_triggers.cpython-313.pyc +0 -0
  271. /package/lib/examples/{AgentspecExample.d.ts → AgentSpecsExample.d.ts} +0 -0
  272. /package/lib/examples/{ag-ui → components}/haiku/HaikuDisplay.d.ts +0 -0
  273. /package/lib/examples/{ag-ui → components}/haiku/InlineHaikuCard.d.ts +0 -0
  274. /package/lib/examples/{ag-ui → components}/weather/InlineWeatherCard.d.ts +0 -0
  275. /package/lib/examples/{ag-ui → components}/weather/InlineWeatherCard.js +0 -0
@@ -1,22 +1,28 @@
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';
25
+ import '../../style/primer-primitives.css';
20
26
  // Load configurations from DOM
21
27
  const loadConfigurations = () => {
22
28
  // Load Datalayer configuration
@@ -59,7 +65,7 @@ const loadConfigurations = () => {
59
65
  CLI: 0,
60
66
  VSCode: 0,
61
67
  },
62
- position: {},
68
+ position: 'top',
63
69
  tours: {},
64
70
  },
65
71
  events: [],
@@ -90,13 +96,15 @@ const loadConfigurations = () => {
90
96
  }
91
97
  }
92
98
  };
93
- 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
+ };
94
104
  // Check if we're on the notebook-only route
95
105
  const isNotebookOnlyRoute = () => {
96
106
  const path = window.location.pathname;
97
- console.log('Current pathname:', path);
98
107
  const isNotebookRoute = path === '/datalayer/notebook';
99
- console.log('Is notebook-only route:', isNotebookRoute);
100
108
  return isNotebookRoute;
101
109
  };
102
110
  // Check if we're handling an OAuth callback (code and state in URL params)
@@ -138,7 +146,6 @@ const NotebookOnlyApp = () => {
138
146
  runUrl: configuration.runUrl,
139
147
  token: configuration.token,
140
148
  });
141
- console.log('[NotebookOnlyApp] Created collaboration provider:', provider);
142
149
  setCollaborationProvider(provider);
143
150
  }
144
151
  catch (error) {
@@ -192,11 +199,6 @@ const NotebookOnlyApp = () => {
192
199
  return null;
193
200
  }
194
201
  const NOTEBOOK_ID = '01JZQRQ35GG871QQCZW9TB1A8J';
195
- console.log('[NotebookOnlyApp] Rendering with:', {
196
- hasServiceManager: !!serviceManager,
197
- hasCollaborationProvider: !!collaborationProvider,
198
- notebookId: NOTEBOOK_ID,
199
- });
200
202
  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 }) }) }));
201
203
  };
202
204
  // Main App component that loads and renders the selected example
@@ -206,7 +208,26 @@ export const ExampleApp = () => {
206
208
  const [error, setError] = useState(null);
207
209
  const [serviceManager, setServiceManager] = useState(null);
208
210
  const [selectedExample, setSelectedExample] = useState(getDefaultExampleName());
211
+ const [searchQuery, setSearchQuery] = useState(getInitialSearchQuery());
209
212
  const [isChangingExample, setIsChangingExample] = useState(false);
213
+ const filteredExampleEntries = useMemo(() => {
214
+ const normalized = searchQuery.trim().toLowerCase();
215
+ const all = getExampleEntriesList();
216
+ if (!normalized) {
217
+ return all;
218
+ }
219
+ return all.filter(entry => {
220
+ const haystack = [
221
+ entry.id,
222
+ entry.title,
223
+ entry.description,
224
+ entry.tags.join(' '),
225
+ ]
226
+ .join(' ')
227
+ .toLowerCase();
228
+ return haystack.includes(normalized);
229
+ });
230
+ }, [searchQuery]);
210
231
  const loadExample = async (exampleName, _manager) => {
211
232
  try {
212
233
  setIsChangingExample(true);
@@ -275,8 +296,75 @@ export const ExampleApp = () => {
275
296
  const handleExampleChange = async (newExample) => {
276
297
  if (newExample === selectedExample || !serviceManager)
277
298
  return;
278
- // Clear chat store when changing examples to start fresh
279
- useChatStore.getState().clearMessages();
299
+ // 1) Unmount the current example FIRST so its useEffect cleanup hooks
300
+ // (e.g. AGUIAdapter.disconnect → /ag-ui/terminate, abort fetches,
301
+ // close runtime sandboxes) run against a still-valid store state.
302
+ setIsChangingExample(true);
303
+ setExampleComponent(null);
304
+ // Yield to React so the unmount actually commits before we wipe stores.
305
+ await new Promise(resolve => {
306
+ requestAnimationFrame(() => resolve());
307
+ });
308
+ // 2) Tear down any server-side agents created by the previous example.
309
+ // Each example caches its agent id in sessionStorage via
310
+ // `uniqueAgentId(baseName)` under key `agent-runtimes:agentId:<base>`.
311
+ // Delete those agents on the server and drop the cached ids so the
312
+ // next example (and a future re-entry into this one) boots fresh.
313
+ const agentBaseUrl = import.meta.env.VITE_BASE_URL || 'http://localhost:8765';
314
+ const token = useSimpleAuthStore.getState().token;
315
+ const agentIdKeys = [];
316
+ try {
317
+ for (let i = 0; i < sessionStorage.length; i++) {
318
+ const key = sessionStorage.key(i);
319
+ if (key && key.startsWith('agent-runtimes:agentId:')) {
320
+ agentIdKeys.push(key);
321
+ }
322
+ }
323
+ }
324
+ catch {
325
+ // sessionStorage unavailable; skip teardown.
326
+ }
327
+ await Promise.all(agentIdKeys.map(async (key) => {
328
+ let agentId = null;
329
+ try {
330
+ agentId = sessionStorage.getItem(key);
331
+ }
332
+ catch {
333
+ /* ignore */
334
+ }
335
+ if (!agentId)
336
+ return;
337
+ try {
338
+ await fetch(`${agentBaseUrl}/api/v1/agents/${encodeURIComponent(agentId)}`, {
339
+ method: 'DELETE',
340
+ headers: token ? { Authorization: `Bearer ${token}` } : {},
341
+ });
342
+ }
343
+ catch {
344
+ // Best-effort teardown: ignore network / 404 errors.
345
+ }
346
+ try {
347
+ sessionStorage.removeItem(key);
348
+ }
349
+ catch {
350
+ /* ignore */
351
+ }
352
+ }));
353
+ // 3) Wipe every piece of in-process agent state so the next example boots
354
+ // with a clean slate (no leftover messages, threads, pending tool
355
+ // calls, runtime snapshots, monitoring caches, or sockets).
356
+ useChatStore.getState().reset();
357
+ useConversationStore.getState().clearAll();
358
+ agentRuntimeStore.getState().reset();
359
+ // 4) Drop the persisted slice from localStorage so a fresh example never
360
+ // rehydrates a previous example's agents / monitoring cache.
361
+ try {
362
+ localStorage.removeItem('agent-runtimes-storage');
363
+ }
364
+ catch {
365
+ // Ignore storage failures (e.g. private mode).
366
+ }
367
+ // 5) Load and mount the new example.
280
368
  setSelectedExample(newExample);
281
369
  localStorage.setItem('selectedExample', newExample);
282
370
  await loadExample(newExample, serviceManager);
@@ -296,16 +384,42 @@ export const ExampleApp = () => {
296
384
  if (serviceManager) {
297
385
  exampleProps.serviceManager = serviceManager;
298
386
  }
299
- return (_jsx(ExampleAppThemed, { selectedExample: selectedExample, isChangingExample: isChangingExample, error: error, ExampleComponent: ExampleComponent, exampleProps: exampleProps, onExampleChange: handleExampleChange }));
387
+ exampleProps.examples = filteredExampleEntries.filter(entry => entry.id !== 'HomeExample');
388
+ exampleProps.searchQuery = searchQuery;
389
+ exampleProps.onSearchChange = (value) => setSearchQuery(value);
390
+ exampleProps.onSelectExample = (name) => {
391
+ void handleExampleChange(name);
392
+ };
393
+ return (_jsx(ExampleAppThemed, { selectedExample: selectedExample, isChangingExample: isChangingExample, error: error, ExampleComponent: ExampleComponent, exampleProps: exampleProps, onExampleChange: handleExampleChange, availableExamples: getExampleEntriesList() }));
300
394
  };
301
395
  /**
302
396
  * Inner shell that reads from the theme store and wires
303
397
  * DatalayerThemeProvider + the header bar with selectors.
304
398
  */
305
- const ExampleAppThemed = ({ selectedExample, isChangingExample, error, ExampleComponent, exampleProps, onExampleChange, }) => {
399
+ const ExampleAppThemed = ({ selectedExample, isChangingExample, error, ExampleComponent, exampleProps, onExampleChange, availableExamples, }) => {
306
400
  const { colorMode, theme: themeVariant } = useExampleThemeStore();
307
401
  const cfg = themeConfigs[themeVariant];
308
402
  const logoColors = getLogoColors(themeVariant, colorMode);
403
+ const { token, setAuth, clearAuth } = useSimpleAuthStore();
404
+ const [showSignIn, setShowSignIn] = useState(false);
405
+ const syncTokenToIamStore = useCallback((newToken) => {
406
+ import('@datalayer/core/lib/state').then(({ iamStore: coreIamStore }) => {
407
+ coreIamStore.setState({ token: newToken });
408
+ });
409
+ }, []);
410
+ useEffect(() => {
411
+ // Keep iamStore aligned with persisted auth token on app load/refresh.
412
+ syncTokenToIamStore(token || undefined);
413
+ }, [token, syncTokenToIamStore]);
414
+ const handleHeaderSignIn = useCallback((newToken, handle) => {
415
+ setAuth(newToken, handle);
416
+ syncTokenToIamStore(newToken);
417
+ setShowSignIn(false);
418
+ }, [setAuth, syncTokenToIamStore]);
419
+ const handleHeaderLogout = useCallback(() => {
420
+ clearAuth();
421
+ syncTokenToIamStore(undefined);
422
+ }, [clearAuth, syncTokenToIamStore]);
309
423
  return (_jsx(DatalayerThemeProvider, { colorMode: colorMode, theme: cfg.primerTheme, themeStyles: cfg.themeStyles, children: _jsxs(Box, { sx: {
310
424
  width: '100vw',
311
425
  height: '100vh',
@@ -327,7 +441,19 @@ const ExampleAppThemed = ({ selectedExample, isChangingExample, error, ExampleCo
327
441
  bg: 'canvas.subtle',
328
442
  borderBottom: '1px solid',
329
443
  borderColor: 'border.default',
330
- }, 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: {
444
+ }, 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: {
445
+ display: 'inline-flex',
446
+ alignItems: 'center',
447
+ justifyContent: 'center',
448
+ width: '32px',
449
+ height: '32px',
450
+ border: '1px solid',
451
+ borderColor: 'border.default',
452
+ borderRadius: 2,
453
+ bg: 'canvas.default',
454
+ color: 'fg.default',
455
+ cursor: isChangingExample ? 'not-allowed' : 'pointer',
456
+ }, disabled: isChangingExample, children: _jsx(HomeIcon, { size: 16 }) }), _jsx(Box, { as: "select", value: selectedExample, onChange: (e) => onExampleChange(e.target.value), disabled: isChangingExample, sx: {
331
457
  px: 2,
332
458
  py: '6px',
333
459
  fontSize: 1,
@@ -343,13 +469,81 @@ const ExampleAppThemed = ({ selectedExample, isChangingExample, error, ExampleCo
343
469
  '&:focus-visible': {
344
470
  boxShadow: '0 0 0 2px var(--bgColor-accent-muted, rgba(9,105,218,0.3))',
345
471
  },
346
- }, children: getExampleNames()
347
- .sort()
348
- .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: {
472
+ }, children: (() => {
473
+ const home = availableExamples.find(e => e.id === 'HomeExample');
474
+ const rest = availableExamples.filter(e => e.id !== 'HomeExample');
475
+ // Classify each example into a named group.
476
+ const groupOf = (id) => {
477
+ if (id === 'AgentSpecsExample')
478
+ return 'Personas';
479
+ if (id.startsWith('A2Ui'))
480
+ return 'A2UI';
481
+ if (id.startsWith('AgUi'))
482
+ return 'AG-UI';
483
+ if (id.startsWith('CopilotKit'))
484
+ return 'CopilotKit';
485
+ if (id.startsWith('Agent'))
486
+ return 'Agent';
487
+ if (id.startsWith('Chat'))
488
+ return 'Chat';
489
+ if (id.startsWith('Lexical'))
490
+ return 'Lexical';
491
+ if (id.startsWith('Notebook') ||
492
+ id === 'NotebookCollaborationExample')
493
+ return 'Notebook';
494
+ return 'Cell';
495
+ };
496
+ const groupOrder = [
497
+ 'Personas',
498
+ 'A2UI',
499
+ 'AG-UI',
500
+ 'Agent',
501
+ 'Chat',
502
+ 'Lexical',
503
+ 'Notebook',
504
+ 'Cell',
505
+ 'CopilotKit',
506
+ ];
507
+ const grouped = new Map();
508
+ for (const ex of rest) {
509
+ const g = groupOf(ex.id);
510
+ if (!grouped.has(g))
511
+ grouped.set(g, []);
512
+ grouped.get(g).push(ex);
513
+ }
514
+ for (const list of grouped.values()) {
515
+ list.sort((a, b) => a.title.localeCompare(b.title));
516
+ }
517
+ const nodes = [];
518
+ if (home) {
519
+ nodes.push(_jsx("option", { value: home.id, children: home.title }, home.id));
520
+ }
521
+ let sepIndex = 0;
522
+ for (const g of groupOrder) {
523
+ const items = grouped.get(g);
524
+ if (!items || items.length === 0)
525
+ continue;
526
+ 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++}`));
527
+ for (const example of items) {
528
+ nodes.push(_jsx("option", { value: example.id, children: example.title }, example.id));
529
+ }
530
+ }
531
+ return _jsx(_Fragment, { children: nodes });
532
+ })() }), 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" }), _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 }) })] })] }), showSignIn && !token && (_jsx(Box, { sx: {
533
+ position: 'fixed',
534
+ top: 60,
535
+ left: 0,
536
+ right: 0,
537
+ bottom: 0,
538
+ zIndex: 150,
539
+ bg: 'canvas.backdrop',
540
+ p: 3,
541
+ overflow: 'auto',
542
+ }, children: _jsxs(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 }) }), _jsx(Box, { sx: { mt: 2, display: 'flex', justifyContent: 'center' }, children: _jsx(Button, { size: "small", variant: "invisible", onClick: () => setShowSignIn(false), children: "Cancel" }) })] }) })), _jsx(Box, { sx: {
349
543
  marginTop: '60px',
350
544
  height: 'calc(100vh - 60px)',
351
545
  overflow: 'hidden',
352
- }, 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 })] }) }));
546
+ }, 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 }, selectedExample) }, selectedExample)) : null })] }) }));
353
547
  };
354
548
  // Mount the app - check route to determine which app to render
355
549
  const root = document.getElementById('root');
@@ -358,15 +552,12 @@ if (root) {
358
552
  (window.__agentRuntimesExamplesRoot = createRoot(root));
359
553
  if (isOAuthCallback()) {
360
554
  // Handle OAuth callback - render OAuthCallback component
361
- console.log('Rendering OAuthCallback (popup flow)');
362
555
  appRoot.render(_jsx(JupyterReactTheme, { children: _jsx(OAuthCallback, { autoClose: true, autoCloseDelay: 1000 }) }));
363
556
  }
364
557
  else if (isNotebookOnlyRoute()) {
365
- console.log('Rendering NotebookOnlyApp');
366
558
  appRoot.render(_jsx(NotebookOnlyApp, {}));
367
559
  }
368
560
  else {
369
- console.log('Rendering ExampleApp');
370
561
  appRoot.render(_jsx(ExampleApp, {}));
371
562
  }
372
563
  }
@@ -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-demo-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-demo-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
  }
@@ -1,13 +1,13 @@
1
1
  {
2
- "id": "social-post-generator",
3
- "title": "Social Post Generator",
4
- "description": "A powerful agent template for automated social media post generation.",
5
- "image": "https://images.unsplash.com/photo-1611926653458-09294b3142bf?w=300&h=150&fit=crop",
6
- "author": "Eric Charles",
7
- "editTimestamp": "2 hours ago",
8
- "status": "paused",
9
- "transport": "ag-ui",
10
- "avatarUrl": "https://avatars.githubusercontent.com/primer",
11
- "stars": 3,
12
- "notifications": 1
2
+ "id": "social-post-generator",
3
+ "title": "Social Post Generator",
4
+ "description": "A powerful agent template for automated social media post generation.",
5
+ "image": "https://images.unsplash.com/photo-1611926653458-09294b3142bf?w=300&h=150&fit=crop",
6
+ "author": "Eric Charles",
7
+ "editTimestamp": "2 hours ago",
8
+ "status": "paused",
9
+ "transport": "ag-ui",
10
+ "avatarUrl": "https://avatars.githubusercontent.com/primer",
11
+ "stars": 3,
12
+ "notifications": 1
13
13
  }
@@ -1,13 +1,13 @@
1
1
  {
2
- "id": "stocks-watcher",
3
- "title": "Stocks Watcher",
4
- "description": "Intelligent stock market analysis and portfolio tracking agent.",
5
- "image": "https://images.unsplash.com/photo-1611974789855-9c2a0a7236a3?w=300&h=150&fit=crop",
6
- "author": "Gonzalo Peña-Castellanos",
7
- "editTimestamp": "3 days ago",
8
- "status": "paused",
9
- "transport": "acp",
10
- "avatarUrl": "https://avatars.githubusercontent.com/desktop",
11
- "stars": 1,
12
- "notifications": 0
2
+ "id": "stocks-watcher",
3
+ "title": "Stocks Watcher",
4
+ "description": "Intelligent stock market analysis and portfolio tracking agent.",
5
+ "image": "https://images.unsplash.com/photo-1611974789855-9c2a0a7236a3?w=300&h=150&fit=crop",
6
+ "author": "Gonzalo Peña-Castellanos",
7
+ "editTimestamp": "3 days ago",
8
+ "status": "paused",
9
+ "transport": "acp",
10
+ "avatarUrl": "https://avatars.githubusercontent.com/desktop",
11
+ "stars": 1,
12
+ "notifications": 0
13
13
  }