@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,45 +1,100 @@
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 { useCallback, useEffect, useRef, useState } from 'react';
7
+ import { useCallback, useEffect, useMemo, useRef, useState, } from 'react';
8
8
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
9
9
  import { Box } from '@datalayer/primer-addons';
10
- import { Button, Heading, Label, Spinner, Text, Token as PrimerToken, } from '@primer/react';
11
- import { AlertIcon, BeakerIcon, BriefcaseIcon, PackageIcon, SignOutIcon, } from '@primer/octicons-react';
10
+ import { AuthRequiredView, ErrorView } from './components';
11
+ import { Button, Dialog, Heading, Label, Spinner, Text, Token as PrimerToken, } from '@primer/react';
12
+ import { BriefcaseIcon, FileIcon } from '@primer/octicons-react';
12
13
  import { useSimpleAuthStore } from '@datalayer/core/lib/views/otel';
13
- import { SignInSimple } from '@datalayer/core/lib/views/iam';
14
- import { UserBadge } from '@datalayer/core/lib/views/profile';
15
14
  import { ThemedProvider } from './utils/themedProvider';
15
+ import { uniqueAgentId } from './utils/agentId';
16
16
  import { Chat } from '../chat';
17
+ import { useSkills, useSkillActions } from '../hooks';
17
18
  const queryClient = new QueryClient();
18
19
  const AGENT_NAME = 'skills-demo-agent';
19
20
  const AGENT_SPEC_ID = 'demo-full';
20
21
  const DEFAULT_LOCAL_BASE_URL = import.meta.env.VITE_BASE_URL || 'http://localhost:8765';
21
- const SkillCard = ({ skill }) => (_jsxs(Box, { sx: {
22
- border: '1px solid',
23
- borderColor: 'border.default',
24
- borderRadius: 2,
25
- p: 2,
26
- mb: 2,
27
- bg: 'canvas.default',
28
- }, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1, mb: 1 }, children: [skill.emoji && _jsx(Text, { sx: { fontSize: 2 }, children: skill.emoji }), _jsx(Text, { sx: { fontWeight: 600, fontSize: 1 }, children: skill.name }), _jsx(Label, { size: "small", variant: skill.variant === 'package' ? 'accent' : 'primary', children: skill.variant === 'package'
29
- ? 'package-based'
30
- : skill.variant === 'path'
31
- ? 'path-based'
32
- : 'name-based' })] }), _jsx(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted', mb: 1, mt: 0 }, children: skill.description }), skill.variant === 'module' && skill.module && (_jsxs(Text, { sx: { fontSize: 0, fontFamily: 'mono', color: 'fg.muted' }, children: ["module: ", skill.module] })), skill.variant === 'package' && (_jsxs(Box, { sx: { fontSize: 0, fontFamily: 'mono', color: 'fg.muted' }, children: [_jsxs(Text, { sx: { display: 'block' }, children: ["package: ", skill.package] }), _jsxs(Text, { sx: { display: 'block' }, children: ["method: ", skill.method] })] })), skill.variant === 'path' && skill.path && (_jsxs(Text, { sx: { fontSize: 0, fontFamily: 'mono', color: 'fg.muted' }, children: ["path: ", skill.path] })), skill.license && (_jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted', display: 'block', mt: 1 }, children: ["License: ", skill.license] })), skill.compatibility && (_jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted', display: 'block' }, children: ["Compat: ", skill.compatibility] })), skill.allowedTools && skill.allowedTools.length > 0 && (_jsx(Box, { sx: { mt: 1, display: 'flex', gap: 1, flexWrap: 'wrap' }, children: skill.allowedTools.map(tool => (_jsx(PrimerToken, { text: tool, size: "small" }, tool))) })), skill.tags && skill.tags.length > 0 && (_jsx(Box, { sx: { mt: 1, display: 'flex', gap: 1, flexWrap: 'wrap' }, children: skill.tags.map(tag => (_jsx(PrimerToken, { text: tag, size: "small" }, tag))) }))] }));
22
+ const SkillCard = ({ skill, onToggle, onToggleApproval }) => {
23
+ const [showDefinition, setShowDefinition] = useState(false);
24
+ const sourceVariant = skill.source_variant ?? 'unknown';
25
+ const sourceLabel = sourceVariant === 'path'
26
+ ? 'file-based'
27
+ : sourceVariant === 'package'
28
+ ? 'package-based'
29
+ : sourceVariant === 'module'
30
+ ? 'module-based'
31
+ : 'unknown';
32
+ const sourceDetail = sourceVariant === 'package'
33
+ ? [skill.package, skill.method].filter(Boolean).join('#')
34
+ : sourceVariant === 'module'
35
+ ? skill.module
36
+ : sourceVariant === 'path'
37
+ ? skill.path
38
+ : undefined;
39
+ return (_jsxs(_Fragment, { children: [_jsxs(Box, { sx: {
40
+ border: '1px solid',
41
+ borderColor: 'border.default',
42
+ borderRadius: 2,
43
+ p: 2,
44
+ mb: 2,
45
+ bg: 'canvas.default',
46
+ }, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1, mb: 1 }, children: [_jsx(Text, { sx: { fontWeight: 600, fontSize: 1 }, children: skill.name }), skill.status && (_jsx(Label, { size: "small", variant: skill.status === 'loaded'
47
+ ? 'success'
48
+ : skill.status === 'enabled'
49
+ ? 'attention'
50
+ : 'secondary', children: skill.status })), skill.approved && (_jsx(Label, { size: "small", variant: "success", children: "approved" })), skill.status === 'loaded' && skill.skill_definition && (_jsx(Button, { size: "small", variant: "invisible", onClick: () => setShowDefinition(true), leadingVisual: FileIcon, sx: { fontSize: 0, p: 0, color: 'fg.muted' }, "aria-label": "View SKILL.md", children: "SKILL.md" })), _jsxs(Box, { sx: { ml: 'auto', display: 'flex', alignItems: 'center', gap: 1 }, children: [_jsx(Button, { size: "small", variant: "invisible", onClick: () => onToggleApproval(skill.id), sx: { fontSize: 0 }, children: skill.approved ? 'Unapprove' : 'Approve' }), _jsx(Button, { size: "small", variant: "invisible", onClick: () => onToggle(skill.id), sx: { fontSize: 0 }, children: skill.status === 'available' ? 'Enable' : 'Disable' })] })] }), skill.description && (_jsx(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted', mb: 1, mt: 0 }, children: skill.description })), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1, mb: 1 }, children: [_jsx(Label, { size: "small", variant: "secondary", children: sourceLabel }), sourceDetail && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: sourceDetail }))] }), skill.tags && skill.tags.length > 0 && (_jsx(Box, { sx: { mt: 1, display: 'flex', gap: 1, flexWrap: 'wrap' }, children: skill.tags.map(tag => (_jsx(PrimerToken, { text: tag, size: "small" }, tag))) }))] }), showDefinition && skill.skill_definition && (_jsx(Dialog, { title: `${skill.name} — SKILL.md`, onClose: () => setShowDefinition(false), width: "xlarge", children: _jsx(Box, { sx: { p: 3, maxHeight: '70vh', overflow: 'auto' }, children: _jsx(Box, { as: "pre", sx: {
51
+ fontFamily: 'mono',
52
+ fontSize: 0,
53
+ whiteSpace: 'pre-wrap',
54
+ wordBreak: 'break-word',
55
+ m: 0,
56
+ p: 3,
57
+ bg: 'canvas.inset',
58
+ borderRadius: 2,
59
+ border: '1px solid',
60
+ borderColor: 'border.muted',
61
+ }, children: skill.skill_definition }) }) }))] }));
62
+ };
33
63
  const AgentSkillsInner = ({ onLogout }) => {
34
64
  const { token } = useSimpleAuthStore();
65
+ const agentName = useRef(uniqueAgentId(AGENT_NAME)).current;
35
66
  const [runtimeStatus, setRuntimeStatus] = useState('launching');
36
67
  const [isReady, setIsReady] = useState(false);
37
68
  const [hookError, setHookError] = useState(null);
38
- const [agentId, setAgentId] = useState(AGENT_NAME);
69
+ const [agentId, setAgentId] = useState(agentName);
39
70
  const [isReconnectedAgent, setIsReconnectedAgent] = useState(false);
40
- const [skills, setSkills] = useState([]);
41
71
  const agentBaseUrl = DEFAULT_LOCAL_BASE_URL;
42
72
  const chatAuthToken = token === null ? undefined : token;
73
+ // WS-sourced skills (reads from codemodeStatus pushed via monitoring WS)
74
+ const skillsQuery = useSkills(isReady);
75
+ const skills = useMemo(() => skillsQuery.data?.skills ?? [], [skillsQuery.data]);
76
+ const { enableSkill, disableSkill, approveSkill, unapproveSkill } = useSkillActions(agentId);
77
+ const toggleSkill = useCallback((skillId) => {
78
+ const skill = skills.find(s => s.id === skillId);
79
+ if (skill?.status === 'available') {
80
+ enableSkill(skillId);
81
+ }
82
+ else {
83
+ disableSkill(skillId);
84
+ }
85
+ }, [skills, enableSkill, disableSkill]);
86
+ const toggleSkillApproval = useCallback((skillId) => {
87
+ const skill = skills.find(s => s.id === skillId);
88
+ if (skill?.approved) {
89
+ unapproveSkill(skillId);
90
+ }
91
+ else {
92
+ approveSkill(skillId);
93
+ }
94
+ }, [skills, approveSkill, unapproveSkill]);
95
+ const fileBasedSkills = skills.filter(s => s.source_variant === 'path');
96
+ const packageBasedSkills = skills.filter(s => s.source_variant === 'package');
97
+ const moduleBasedSkills = skills.filter(s => s.source_variant === 'module');
43
98
  const authFetch = useCallback((url, opts = {}) => fetch(url, {
44
99
  ...opts,
45
100
  headers: {
@@ -57,12 +112,12 @@ const AgentSkillsInner = ({ onLogout }) => {
57
112
  setIsReconnectedAgent(false);
58
113
  try {
59
114
  // Create local agent runtime using the demo-full spec.
60
- // The spec contains both code-based and path-based skills.
115
+ // The spec contains module-based, package-based and file-based skills.
61
116
  const response = await authFetch(`${agentBaseUrl}/api/v1/agents`, {
62
117
  method: 'POST',
63
118
  body: JSON.stringify({
64
- name: AGENT_NAME,
65
- description: 'Agent with skills demo - code-based and path-based skills',
119
+ name: agentName,
120
+ description: 'Agent with skills demo - module, package and file based skills',
66
121
  agent_library: 'pydantic-ai',
67
122
  transport: 'vercel-ai',
68
123
  agent_spec_id: AGENT_SPEC_ID,
@@ -70,11 +125,11 @@ const AgentSkillsInner = ({ onLogout }) => {
70
125
  tools: [],
71
126
  }),
72
127
  });
73
- let resolvedAgentId = AGENT_NAME;
128
+ let resolvedAgentId = agentName;
74
129
  let isAlreadyRunning = false;
75
130
  if (response.ok) {
76
131
  const data = await response.json();
77
- resolvedAgentId = data?.id || AGENT_NAME;
132
+ resolvedAgentId = data?.id || agentName;
78
133
  }
79
134
  else {
80
135
  const contentType = response.headers.get('content-type') || '';
@@ -114,68 +169,7 @@ const AgentSkillsInner = ({ onLogout }) => {
114
169
  return () => {
115
170
  isCancelled = true;
116
171
  };
117
- }, [agentBaseUrl, authFetch]);
118
- // Fetch skill information from the agent's spec endpoint
119
- useEffect(() => {
120
- if (!isReady)
121
- return;
122
- const fetchSkills = async () => {
123
- try {
124
- const res = await authFetch(`${agentBaseUrl}/api/v1/agents/${agentId}/spec`);
125
- if (!res.ok)
126
- return;
127
- const spec = await res.json();
128
- const skillNames = spec?.skills ?? [];
129
- // For each skill name, build a SkillInfo from the catalog when possible.
130
- const { getSkillSpec } = await import('../specs/skills');
131
- const infos = skillNames.map((name) => {
132
- const baseName = name.includes(':') ? name.split(':')[0] : name;
133
- const catalogSpec = getSkillSpec(baseName);
134
- if (catalogSpec?.path) {
135
- // Variant 3: path-based skill
136
- return {
137
- name: catalogSpec.name,
138
- description: catalogSpec.description || `Skill: ${baseName}`,
139
- variant: 'path',
140
- path: catalogSpec.path,
141
- tags: catalogSpec.tags ? [...catalogSpec.tags] : [],
142
- emoji: catalogSpec.emoji,
143
- };
144
- }
145
- if (catalogSpec?.package && catalogSpec?.method) {
146
- // Variant 2: package-based skill
147
- return {
148
- name: catalogSpec.name,
149
- description: catalogSpec.description || `Skill: ${baseName}`,
150
- variant: 'package',
151
- package: catalogSpec.package,
152
- method: catalogSpec.method,
153
- license: catalogSpec.license,
154
- compatibility: catalogSpec.compatibility,
155
- allowedTools: catalogSpec.allowedTools,
156
- skillMetadata: catalogSpec.skillMetadata,
157
- tags: catalogSpec.tags ? [...catalogSpec.tags] : [],
158
- emoji: catalogSpec.emoji,
159
- };
160
- }
161
- // Variant 1: name-based (module discovery)
162
- return {
163
- name: catalogSpec?.name ?? baseName,
164
- description: catalogSpec?.description ?? `Skill: ${baseName}`,
165
- variant: 'module',
166
- module: catalogSpec?.module ?? `agent_skills.skills.${baseName}`,
167
- tags: catalogSpec?.tags ? [...catalogSpec.tags] : [],
168
- emoji: catalogSpec?.emoji,
169
- };
170
- });
171
- setSkills(infos);
172
- }
173
- catch {
174
- // Non-fatal: skill display is informational
175
- }
176
- };
177
- void fetchSkills();
178
- }, [isReady, agentId, agentBaseUrl, authFetch]);
172
+ }, [agentBaseUrl, agentName, authFetch]);
179
173
  if (!isReady && runtimeStatus !== 'error') {
180
174
  return (_jsxs(Box, { sx: {
181
175
  display: 'flex',
@@ -187,14 +181,7 @@ const AgentSkillsInner = ({ onLogout }) => {
187
181
  }, children: [_jsx(Spinner, { size: "large" }), _jsx(Text, { sx: { color: 'fg.muted' }, children: "Launching skills demo agent..." })] }));
188
182
  }
189
183
  if (runtimeStatus === 'error' || hookError) {
190
- return (_jsxs(Box, { sx: {
191
- display: 'flex',
192
- flexDirection: 'column',
193
- alignItems: 'center',
194
- justifyContent: 'center',
195
- height: '100vh',
196
- gap: 3,
197
- }, children: [_jsx(AlertIcon, { size: 48 }), _jsx(Text, { sx: { color: 'danger.fg' }, children: hookError || 'Agent failed to start' })] }));
184
+ return _jsx(ErrorView, { error: hookError, onLogout: onLogout });
198
185
  }
199
186
  return (_jsxs(Box, { sx: {
200
187
  height: 'calc(100vh - 60px)',
@@ -205,11 +192,15 @@ const AgentSkillsInner = ({ onLogout }) => {
205
192
  py: 1,
206
193
  borderBottom: '1px solid',
207
194
  borderColor: 'border.default',
208
- }, children: _jsx(Text, { sx: { color: 'fg.muted', fontSize: 0 }, children: "Agent already running - reconnected." }) })), _jsxs(Box, { sx: { flex: 1, minHeight: 0, display: 'flex' }, children: [_jsx(Box, { sx: { flex: 1, minWidth: 0 }, children: _jsx(Chat, { protocol: "vercel-ai", baseUrl: agentBaseUrl, agentId: agentId, authToken: chatAuthToken, title: `Skills Demo Agent`, placeholder: "Ask the agent to use its skills...", showHeader: true, showNewChatButton: true, showClearButton: false, showTokenUsage: true, autoFocus: true, height: "100%", runtimeId: agentId, historyEndpoint: `${agentBaseUrl}/api/v1/history`, headerActions: _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsxs(Text, { sx: { color: 'fg.muted', fontSize: 1 }, children: ["Skills: ", skills.length] }), token && _jsx(UserBadge, { token: token, variant: "small" }), _jsx(Button, { size: "small", variant: "invisible", onClick: onLogout, leadingVisual: SignOutIcon, sx: { color: 'fg.muted' }, children: "Sign out" })] }), suggestions: [
195
+ }, children: _jsx(Text, { sx: { color: 'fg.muted', fontSize: 0 }, children: "Agent already running - reconnected." }) })), _jsxs(Box, { sx: { flex: 1, minHeight: 0, display: 'flex' }, children: [_jsx(Box, { sx: { flex: 1, minWidth: 0 }, children: _jsx(Chat, { protocol: "vercel-ai", baseUrl: agentBaseUrl, agentId: agentId, authToken: chatAuthToken, title: `Skills Demo Agent`, placeholder: "Ask the agent to use its skills...", showHeader: true, showNewChatButton: true, showClearButton: false, showTokenUsage: true, showSkillsMenu: true, autoFocus: true, height: "100%", runtimeId: agentId, historyEndpoint: `${agentBaseUrl}/api/v1/history`, headerActions: _jsx(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: _jsxs(Text, { sx: { color: 'fg.muted', fontSize: 1 }, children: ["Skills: ", skills.length] }) }), suggestions: [
209
196
  {
210
197
  title: 'List available skills',
211
198
  message: 'List all your available skills and what they can do.',
212
199
  },
200
+ {
201
+ title: '👤 Who am I',
202
+ message: 'Use the datalayer-whoami skill to tell me who I am, including my user identity and available context.',
203
+ },
213
204
  {
214
205
  title: '🌐 Crawl a webpage',
215
206
  message: 'Use the crawl skill to fetch the content of https://datalayer.ai and summarize it.',
@@ -220,7 +211,7 @@ const AgentSkillsInner = ({ onLogout }) => {
220
211
  },
221
212
  {
222
213
  title: '🐙 GitHub repos',
223
- message: 'Use the GitHub skill to list the public repositories for the "datalayer" organization.',
214
+ message: 'Use the GitHub skill to show two sections: first, the top 3 recently updated public repositories from the datalayer organization; second, my top 3 recently updated private repositories. Keep the output clear and concise.',
224
215
  },
225
216
  {
226
217
  title: '📄 Read a PDF',
@@ -247,14 +238,14 @@ const AgentSkillsInner = ({ onLogout }) => {
247
238
  p: 2,
248
239
  borderBottom: '1px solid',
249
240
  borderColor: 'border.default',
250
- }, children: [_jsx(Heading, { as: "h4", sx: { fontSize: 1, mb: 1 }, children: _jsxs(Box, { sx: { display: 'inline-flex', alignItems: 'center', gap: 1 }, children: [_jsx(BriefcaseIcon, { size: 16 }), "Agent Skills"] }) }), _jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: ["Loaded: ", skills.length, " skill", skills.length !== 1 ? 's' : ''] })] }), _jsxs(Box, { sx: { p: 2, overflow: 'auto', flex: 1 }, children: [skills.length === 0 ? (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "No skills loaded." })) : (skills.map(skill => _jsx(SkillCard, { skill: skill }, skill.name))), _jsxs(Box, { sx: {
241
+ }, children: [_jsx(Heading, { as: "h4", sx: { fontSize: 1, mb: 1 }, children: _jsxs(Box, { sx: { display: 'inline-flex', alignItems: 'center', gap: 1 }, children: [_jsx(BriefcaseIcon, { size: 16 }), "Agent Skills"] }) }), _jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: [skills.length, " skill", skills.length !== 1 ? 's' : '', " \u00B7", ' ', skills.filter(s => s.status === 'loaded').length, " loaded \u00B7", ' ', skills.filter(s => s.approved).length, " approved"] }), _jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted', mt: 1, display: 'block' }, children: [fileBasedSkills.length, " file-based \u00B7", ' ', packageBasedSkills.length, " package-based \u00B7", ' ', moduleBasedSkills.length, " module-based"] })] }), _jsxs(Box, { sx: { p: 2, overflow: 'auto', flex: 1 }, children: [skills.length === 0 ? (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Waiting for skills snapshot..." })) : (skills.map(skill => (_jsx(SkillCard, { skill: skill, onToggle: toggleSkill, onToggleApproval: toggleSkillApproval }, skill.id)))), _jsxs(Box, { sx: {
251
242
  mt: 3,
252
243
  p: 2,
253
244
  borderRadius: 2,
254
245
  bg: 'canvas.inset',
255
246
  border: '1px solid',
256
247
  borderColor: 'border.muted',
257
- }, children: [_jsx(Heading, { as: "h5", sx: { fontSize: 0, mb: 1 }, children: "Skill Spec Variants" }), _jsxs(Box, { sx: { fontSize: 0, color: 'fg.muted' }, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1, mb: 1 }, children: [_jsx(BeakerIcon, { size: 12 }), _jsxs(Text, { children: [_jsx("strong", { children: "Path-based:" }), " Discovered from a local SKILL.md directory path"] })] }), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1 }, children: [_jsx(PackageIcon, { size: 12 }), _jsxs(Text, { children: [_jsx("strong", { children: "Module-based:" }), " Python module or package + method with frontmatter"] })] })] })] })] })] })] })] }));
248
+ }, children: [_jsx(Heading, { as: "h5", sx: { fontSize: 0, mb: 1 }, children: "Skill Statuses" }), _jsxs(Box, { sx: { fontSize: 0, color: 'fg.muted' }, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1, mb: 1 }, children: [_jsx(Label, { size: "small", variant: "secondary", children: "available" }), _jsx(Text, { children: "In catalog, not yet enabled" })] }), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1, mb: 1 }, children: [_jsx(Label, { size: "small", variant: "attention", children: "enabled" }), _jsx(Text, { children: "Enabled, loading pending" })] }), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1 }, children: [_jsx(Label, { size: "small", variant: "success", children: "loaded" }), _jsx(Text, { children: "SKILL.md loaded, in system prompt" })] })] })] })] })] })] })] }));
258
249
  };
259
250
  const syncTokenToIamStore = (token) => {
260
251
  import('@datalayer/core/lib/state').then(({ iamStore }) => {
@@ -262,7 +253,7 @@ const syncTokenToIamStore = (token) => {
262
253
  });
263
254
  };
264
255
  const AgentSkillsExample = () => {
265
- const { token, setAuth, clearAuth } = useSimpleAuthStore();
256
+ const { token, clearAuth } = useSimpleAuthStore();
266
257
  const hasSynced = useRef(false);
267
258
  useEffect(() => {
268
259
  if (token && !hasSynced.current) {
@@ -270,11 +261,6 @@ const AgentSkillsExample = () => {
270
261
  syncTokenToIamStore(token);
271
262
  }
272
263
  }, [token]);
273
- const handleSignIn = useCallback((newToken, handle) => {
274
- setAuth(newToken, handle);
275
- hasSynced.current = true;
276
- syncTokenToIamStore(newToken);
277
- }, [setAuth]);
278
264
  const handleLogout = useCallback(() => {
279
265
  clearAuth();
280
266
  hasSynced.current = false;
@@ -283,7 +269,7 @@ const AgentSkillsExample = () => {
283
269
  });
284
270
  }, [clearAuth]);
285
271
  if (!token) {
286
- return (_jsx(ThemedProvider, { children: _jsx(SignInSimple, { onSignIn: handleSignIn, onApiKeySignIn: apiKey => handleSignIn(apiKey, 'api-key-user'), title: "Agent Skills Demo", description: "Sign in to test code-based and path-based agent skills.", leadingIcon: _jsx(BriefcaseIcon, { size: 24 }) }) }));
272
+ return (_jsx(ThemedProvider, { children: _jsx(AuthRequiredView, {}) }));
287
273
  }
288
274
  return (_jsx(QueryClientProvider, { client: queryClient, children: _jsx(ThemedProvider, { children: _jsx(AgentSkillsInner, { onLogout: handleLogout }) }) }));
289
275
  };
@@ -9,16 +9,16 @@ import { PageLayout, IconButton } from '@primer/react';
9
9
  import { SidebarCollapseIcon, SidebarExpandIcon } from '@primer/octicons-react';
10
10
  import { AiAgentIcon } from '@datalayer/icons-react';
11
11
  import { Blankslate } from '@primer/react/experimental';
12
- import { QueryClient, QueryClientProvider, useQuery, } from '@tanstack/react-query';
12
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
13
13
  import { Box } from '@datalayer/primer-addons';
14
- import { ThemedProvider } from './utils/themedProvider';
14
+ import { AgentConfiguration } from '../config';
15
15
  import { Chat } from '../chat';
16
16
  import { DEFAULT_MODEL } from '../specs';
17
- import { useAgentsStore } from './utils/examplesStore';
18
17
  import { useIdentity } from '../identity';
18
+ import { useAgentsStore } from './utils/examplesStore';
19
+ import { ThemedProvider } from './utils/themedProvider';
19
20
  import { isSpecSelection, getSpecId } from '../config/AgentConfiguration';
20
21
  import { MockFileBrowser, MainContent, Header } from './components';
21
- import { AgentConfiguration } from '../config';
22
22
  import { useChatStore } from '../stores';
23
23
  // Create a query client for React Query
24
24
  const queryClient = new QueryClient({
@@ -35,19 +35,9 @@ const queryClient = new QueryClient({
35
35
  * Hook to fetch codemode status and compute Jupyter error banner.
36
36
  * Must be used inside QueryClientProvider.
37
37
  */
38
- function useJupyterSandboxStatus(baseUrl, isConfigured, enableCodemode, useJupyterSandbox) {
39
- const { data: codemodeStatus } = useQuery({
40
- queryKey: ['codemode-status', baseUrl],
41
- queryFn: async () => {
42
- const response = await fetch(`${baseUrl}/api/v1/configure/codemode-status`);
43
- if (!response.ok) {
44
- throw new Error('Failed to fetch codemode status');
45
- }
46
- return response.json();
47
- },
48
- enabled: isConfigured && enableCodemode && useJupyterSandbox,
49
- refetchInterval: 10000, // Refresh every 10 seconds
50
- });
38
+ function useJupyterSandboxStatus(baseUrl, isConfigured, enableCodemode, useJupyterSandbox, codemodeStatusData) {
39
+ // REST polling removed — data comes exclusively via WS `agent.snapshot`.
40
+ const codemodeStatus = codemodeStatusData;
51
41
  return React.useMemo(() => {
52
42
  if (!isConfigured || !enableCodemode || !useJupyterSandbox) {
53
43
  return undefined;
@@ -57,7 +47,7 @@ function useJupyterSandboxStatus(baseUrl, isConfigured, enableCodemode, useJupyt
57
47
  return undefined;
58
48
  }
59
49
  // Check if Jupyter variant is selected but not connected
60
- if (sandbox.variant === 'local-jupyter' && !sandbox.jupyter_connected) {
50
+ if (sandbox.variant === 'jupyter' && !sandbox.jupyter_connected) {
61
51
  return {
62
52
  message: sandbox.jupyter_error
63
53
  ? `Jupyter Sandbox Error: ${sandbox.jupyter_error}`
@@ -386,7 +376,7 @@ githubClientId, kaggleToken, }) => {
386
376
  setAllowDirectToolCalls(false);
387
377
  setEnableToolReranker(false);
388
378
  setUseJupyterSandbox(false);
389
- setTransport('ag-ui');
379
+ setTransport('vercel-ai');
390
380
  }
391
381
  else if (isSpecSelection(agentId)) {
392
382
  // Populate form fields from the selected library spec
@@ -425,8 +415,7 @@ githubClientId, kaggleToken, }) => {
425
415
  codemodeConfig?.allow_direct_tool_calls));
426
416
  setEnableToolReranker(Boolean(codemodeConfig?.enableToolReranker ??
427
417
  codemodeConfig?.enable_tool_reranker));
428
- setUseJupyterSandbox(spec.sandboxVariant === 'local-jupyter' ||
429
- spec.sandboxVariant === 'jupyter');
418
+ setUseJupyterSandbox(spec.sandboxVariant === 'jupyter');
430
419
  }
431
420
  else {
432
421
  setSelectedLibrarySpec(null);
@@ -0,0 +1,14 @@
1
+ /**
2
+ * AgentSubagentsExample
3
+ *
4
+ * Demonstrates multi-agent delegation using subagents-pydantic-ai.
5
+ * The parent agent orchestrates a researcher and a writer subagent,
6
+ * delegating tasks and combining results for the user.
7
+ *
8
+ * - Creates a local agent from the 'demo-subagents' spec
9
+ * - Shows a Chat component for interacting with the orchestrator
10
+ * - Sidebar displays subagent info and active task status
11
+ */
12
+ import React from 'react';
13
+ declare const AgentSubagentsExample: React.FC;
14
+ export default AgentSubagentsExample;
@@ -0,0 +1,228 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /*
3
+ * Copyright (c) 2025-2026 Datalayer, Inc.
4
+ * Distributed under the terms of the Modified BSD License.
5
+ */
6
+ /**
7
+ * AgentSubagentsExample
8
+ *
9
+ * Demonstrates multi-agent delegation using subagents-pydantic-ai.
10
+ * The parent agent orchestrates a researcher and a writer subagent,
11
+ * delegating tasks and combining results for the user.
12
+ *
13
+ * - Creates a local agent from the 'demo-subagents' spec
14
+ * - Shows a Chat component for interacting with the orchestrator
15
+ * - Sidebar displays subagent info and active task status
16
+ */
17
+ /// <reference types="vite/client" />
18
+ import { useEffect, useState, useCallback, useRef } from 'react';
19
+ import { Text, Spinner, Heading, Label, Timeline } from '@primer/react';
20
+ import { PeopleIcon, PersonIcon, CheckCircleFillIcon, ClockIcon, XCircleFillIcon, } from '@primer/octicons-react';
21
+ import { Box } from '@datalayer/primer-addons';
22
+ import { AuthRequiredView, ErrorView } from './components';
23
+ import { ThemedProvider } from './utils/themedProvider';
24
+ import { uniqueAgentId } from './utils/agentId';
25
+ import { useSimpleAuthStore } from '@datalayer/core/lib/views/otel';
26
+ import { Chat } from '../chat';
27
+ const AGENT_NAME = 'subagents-demo-agent';
28
+ const AGENT_SPEC_ID = 'demo-subagents';
29
+ const DEFAULT_LOCAL_BASE_URL = import.meta.env.VITE_BASE_URL || 'http://localhost:8765';
30
+ const SUBAGENTS = [
31
+ {
32
+ name: 'researcher',
33
+ description: 'Researches topics, gathers facts, and provides detailed analysis',
34
+ preferredMode: 'sync',
35
+ typicalComplexity: 'moderate',
36
+ canAskQuestions: true,
37
+ },
38
+ {
39
+ name: 'writer',
40
+ description: 'Writes clear, structured content based on research or instructions',
41
+ preferredMode: 'sync',
42
+ typicalComplexity: 'moderate',
43
+ canAskQuestions: false,
44
+ },
45
+ ];
46
+ const AgentSubagentsInner = ({ onLogout, }) => {
47
+ const { token } = useSimpleAuthStore();
48
+ const agentName = useRef(uniqueAgentId(AGENT_NAME)).current;
49
+ const [runtimeStatus, setRuntimeStatus] = useState('launching');
50
+ const [isReady, setIsReady] = useState(false);
51
+ const [hookError, setHookError] = useState(null);
52
+ const [agentId, setAgentId] = useState(agentName);
53
+ const [isReconnectedAgent, setIsReconnectedAgent] = useState(false);
54
+ const agentBaseUrl = DEFAULT_LOCAL_BASE_URL;
55
+ const chatAuthToken = token === null ? undefined : token;
56
+ const authFetch = useCallback((url, opts = {}) => fetch(url, {
57
+ ...opts,
58
+ headers: {
59
+ 'Content-Type': 'application/json',
60
+ ...(token ? { Authorization: `Bearer ${token}` } : {}),
61
+ ...(opts.headers ?? {}),
62
+ },
63
+ }), [token]);
64
+ useEffect(() => {
65
+ let isCancelled = false;
66
+ const createLocalAgent = async () => {
67
+ setRuntimeStatus('launching');
68
+ setIsReady(false);
69
+ setHookError(null);
70
+ setIsReconnectedAgent(false);
71
+ try {
72
+ const response = await authFetch(`${agentBaseUrl}/api/v1/agents`, {
73
+ method: 'POST',
74
+ body: JSON.stringify({
75
+ name: agentName,
76
+ description: 'Subagents demo – multi-agent delegation with researcher and writer',
77
+ agent_library: 'pydantic-ai',
78
+ transport: 'vercel-ai',
79
+ agent_spec_id: AGENT_SPEC_ID,
80
+ enable_skills: true,
81
+ tools: [],
82
+ }),
83
+ });
84
+ let resolvedAgentId = agentName;
85
+ let isAlreadyRunning = false;
86
+ if (response.ok) {
87
+ const data = await response.json();
88
+ resolvedAgentId = data?.id || agentName;
89
+ }
90
+ else {
91
+ const contentType = response.headers.get('content-type') || '';
92
+ let detail = '';
93
+ if (contentType.includes('application/json')) {
94
+ const data = await response.json().catch(() => null);
95
+ detail =
96
+ (typeof data?.detail === 'string' && data.detail) ||
97
+ (typeof data?.message === 'string' && data.message) ||
98
+ '';
99
+ }
100
+ else {
101
+ detail = await response.text();
102
+ }
103
+ if (response.status === 409 || /already exists/i.test(detail || '')) {
104
+ isAlreadyRunning = true;
105
+ }
106
+ else {
107
+ throw new Error(detail || `Failed to create local agent: ${response.status}`);
108
+ }
109
+ }
110
+ if (!isCancelled) {
111
+ setAgentId(resolvedAgentId);
112
+ setIsReconnectedAgent(isAlreadyRunning);
113
+ setIsReady(true);
114
+ setRuntimeStatus('ready');
115
+ }
116
+ }
117
+ catch (error) {
118
+ if (!isCancelled) {
119
+ setHookError(error instanceof Error ? error.message : 'Agent failed to start');
120
+ setRuntimeStatus('error');
121
+ }
122
+ }
123
+ };
124
+ void createLocalAgent();
125
+ return () => {
126
+ isCancelled = true;
127
+ };
128
+ }, [agentBaseUrl, authFetch]);
129
+ if (!isReady && runtimeStatus !== 'error') {
130
+ return (_jsxs(Box, { sx: {
131
+ display: 'flex',
132
+ flexDirection: 'column',
133
+ alignItems: 'center',
134
+ justifyContent: 'center',
135
+ height: '100vh',
136
+ gap: 3,
137
+ }, children: [_jsx(Spinner, { size: "large" }), _jsx(Text, { sx: { color: 'fg.muted' }, children: "Launching subagents demo agent..." })] }));
138
+ }
139
+ if (runtimeStatus === 'error' || hookError) {
140
+ return _jsx(ErrorView, { error: hookError, onLogout: onLogout });
141
+ }
142
+ return (_jsxs(Box, { sx: {
143
+ height: 'calc(100vh - 60px)',
144
+ display: 'flex',
145
+ flexDirection: 'column',
146
+ }, children: [_jsxs(Box, { sx: {
147
+ display: 'flex',
148
+ alignItems: 'center',
149
+ gap: 2,
150
+ px: 3,
151
+ py: 2,
152
+ borderBottom: '1px solid',
153
+ borderColor: 'border.default',
154
+ flexShrink: 0,
155
+ }, children: [_jsx(PeopleIcon, { size: 16 }), _jsx(Heading, { as: "h3", sx: { fontSize: 2, flex: 1 }, children: "Subagents Demo" }), isReconnectedAgent && (_jsx(Label, { variant: "secondary", size: "small", children: "Reconnected" })), _jsxs(Label, { variant: "accent", children: [SUBAGENTS.length, " subagents"] })] }), _jsxs(Box, { sx: { flex: 1, minHeight: 0, display: 'flex' }, children: [_jsx(Box, { sx: { flex: 1, minWidth: 0 }, children: _jsx(Chat, { protocol: "vercel-ai", baseUrl: agentBaseUrl, agentId: agentId, authToken: chatAuthToken, title: "Subagents Orchestrator", placeholder: "Ask me to research a topic, write content, or both...", description: "Multi-agent delegation with researcher & writer", showHeader: true, autoFocus: true, height: "100%", runtimeId: agentId, historyEndpoint: `${agentBaseUrl}/api/v1/history`, suggestions: [
156
+ {
157
+ title: 'Research & write',
158
+ message: 'Research the pros and cons of Python async patterns and write a summary.',
159
+ },
160
+ {
161
+ title: 'Research only',
162
+ message: 'Find recent advances in LLM fine-tuning and provide a detailed analysis.',
163
+ },
164
+ {
165
+ title: 'Write only',
166
+ message: 'Write a concise guide on REST API design best practices.',
167
+ },
168
+ ], submitOnSuggestionClick: true }) }), _jsxs(Box, { sx: {
169
+ width: 320,
170
+ borderLeft: '1px solid',
171
+ borderColor: 'border.default',
172
+ display: 'flex',
173
+ flexDirection: 'column',
174
+ overflow: 'auto',
175
+ }, children: [_jsxs(Box, { sx: {
176
+ p: 3,
177
+ borderBottom: '1px solid',
178
+ borderColor: 'border.default',
179
+ }, children: [_jsx(Heading, { as: "h4", sx: { fontSize: 1, mb: 2 }, children: "Available Subagents" }), _jsx(Timeline, { children: SUBAGENTS.map(sa => (_jsxs(Timeline.Item, { children: [_jsx(Timeline.Badge, { children: _jsx(PersonIcon, {}) }), _jsxs(Timeline.Body, { children: [_jsx(Box, { sx: { mb: 1 }, children: _jsx(Text, { sx: { fontWeight: 'bold', fontSize: 1 }, children: sa.name }) }), _jsx(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted', mt: 0, mb: 1 }, children: sa.description }), _jsxs(Box, { sx: { display: 'flex', gap: 1, flexWrap: 'wrap' }, children: [_jsx(Label, { size: "small", variant: "secondary", children: sa.preferredMode }), _jsx(Label, { size: "small", variant: "secondary", children: sa.typicalComplexity }), sa.canAskQuestions && (_jsx(Label, { size: "small", variant: "accent", children: "can ask questions" }))] })] })] }, sa.name))) })] }), _jsxs(Box, { sx: {
180
+ p: 3,
181
+ borderBottom: '1px solid',
182
+ borderColor: 'border.default',
183
+ }, children: [_jsx(Heading, { as: "h4", sx: { fontSize: 1, mb: 2 }, children: "Delegation Tools" }), _jsx(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 2 }, children: [
184
+ {
185
+ name: 'task',
186
+ desc: 'Assign a task to a subagent',
187
+ icon: ClockIcon,
188
+ },
189
+ {
190
+ name: 'check_task',
191
+ desc: 'Check status of a running task',
192
+ icon: CheckCircleFillIcon,
193
+ },
194
+ {
195
+ name: 'list_active_tasks',
196
+ desc: 'View all active delegated tasks',
197
+ icon: PeopleIcon,
198
+ },
199
+ {
200
+ name: 'soft_cancel_task',
201
+ desc: 'Gracefully cancel a task',
202
+ icon: XCircleFillIcon,
203
+ },
204
+ ].map(tool => (_jsxs(Box, { sx: {
205
+ p: 2,
206
+ border: '1px solid',
207
+ borderColor: 'border.default',
208
+ borderRadius: 2,
209
+ display: 'flex',
210
+ alignItems: 'center',
211
+ gap: 2,
212
+ }, children: [_jsx(tool.icon, { size: 14 }), _jsxs(Box, { children: [_jsx(Text, { sx: {
213
+ fontSize: 1,
214
+ fontWeight: 'bold',
215
+ fontFamily: 'mono',
216
+ }, children: tool.name }), _jsx(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted', mt: 0, mb: 0 }, children: tool.desc })] })] }, tool.name))) })] }), _jsxs(Box, { sx: { p: 3 }, children: [_jsx(Heading, { as: "h4", sx: { fontSize: 1, mb: 2 }, children: "How It Works" }), _jsxs(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted', mb: 2 }, children: ["The orchestrator agent delegates tasks to specialised subagents using the ", _jsx("code", { children: "task" }), " tool. Each subagent runs independently with its own model, instructions, and context."] }), _jsx(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted', mb: 0 }, children: "Subagents can be configured with different execution modes (sync, async, auto), complexity hints, and question-asking capabilities for interactive workflows." })] })] })] })] }));
217
+ };
218
+ const AgentSubagentsExample = () => {
219
+ const { token, clearAuth } = useSimpleAuthStore();
220
+ const handleLogout = useCallback(() => {
221
+ clearAuth();
222
+ }, [clearAuth]);
223
+ if (!token) {
224
+ return (_jsx(ThemedProvider, { children: _jsx(AuthRequiredView, {}) }));
225
+ }
226
+ return (_jsx(ThemedProvider, { children: _jsx(AgentSubagentsInner, { onLogout: handleLogout }) }));
227
+ };
228
+ export default AgentSubagentsExample;