@datalayer/agent-runtimes 0.0.9 → 0.0.10

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 +2 -1
  2. package/lib/{examples/components → components}/AgentConfiguration.d.ts +27 -12
  3. package/lib/{examples/components → components}/AgentConfiguration.js +170 -22
  4. package/lib/{examples/components → components}/FooterMetrics.d.ts +1 -2
  5. package/lib/{examples/components → components}/Header.d.ts +1 -6
  6. package/lib/{examples/components → components}/Header.js +5 -39
  7. package/lib/{examples/components → components}/HeaderControls.d.ts +1 -2
  8. package/lib/{examples/components → components}/HeaderControls.js +1 -1
  9. package/lib/{examples/components → components}/LexicalEditor.d.ts +2 -3
  10. package/lib/{examples/components → components}/LexicalEditor.js +2 -2
  11. package/lib/components/MainContent.d.ts +34 -0
  12. package/lib/{examples/components → components}/MainContent.js +18 -9
  13. package/lib/components/McpServerManager.d.ts +30 -0
  14. package/lib/components/McpServerManager.js +331 -0
  15. package/lib/{examples/components → components}/MockFileBrowser.d.ts +1 -2
  16. package/lib/{examples/components → components}/SessionTabs.d.ts +2 -3
  17. package/lib/{examples/components → components}/TimeTravel.d.ts +1 -2
  18. package/lib/components/chat/components/AgentDetails.d.ts +3 -1
  19. package/lib/components/chat/components/AgentDetails.js +323 -31
  20. package/lib/components/chat/components/Chat.d.ts +37 -3
  21. package/lib/components/chat/components/Chat.js +29 -10
  22. package/lib/components/chat/components/ChatFloating.d.ts +27 -2
  23. package/lib/components/chat/components/ChatFloating.js +17 -10
  24. package/lib/components/chat/components/ChatPopupStandalone.js +1 -1
  25. package/lib/components/chat/components/ChatSidebar.d.ts +1 -1
  26. package/lib/components/chat/components/ChatStandalone.d.ts +1 -1
  27. package/lib/components/chat/components/ChatStandalone.js +1 -1
  28. package/lib/components/chat/components/ContextDistribution.d.ts +70 -6
  29. package/lib/components/chat/components/ContextDistribution.js +11 -4
  30. package/lib/components/chat/components/ContextInspector.d.ts +81 -0
  31. package/lib/components/chat/components/ContextInspector.js +261 -0
  32. package/lib/components/chat/components/ContextPanel.d.ts +112 -0
  33. package/lib/components/chat/components/ContextPanel.js +373 -0
  34. package/lib/components/chat/components/base/ChatBase.d.ts +74 -19
  35. package/lib/components/chat/components/base/ChatBase.js +296 -37
  36. package/lib/components/chat/components/index.d.ts +3 -1
  37. package/lib/components/chat/components/index.js +2 -0
  38. package/lib/components/chat/extensions/ExtensionRegistry.d.ts +1 -1
  39. package/lib/components/chat/extensions/index.d.ts +1 -0
  40. package/lib/components/chat/index.d.ts +3 -3
  41. package/lib/components/chat/protocols/AGUIAdapter.js +24 -4
  42. package/lib/components/chat/protocols/VercelAIAdapter.js +35 -1
  43. package/lib/components/chat/store/chatStore.d.ts +2 -3
  44. package/lib/components/chat/store/conversationStore.d.ts +83 -0
  45. package/lib/components/chat/store/conversationStore.js +174 -0
  46. package/lib/components/chat/store/index.d.ts +2 -1
  47. package/lib/components/chat/store/index.js +1 -0
  48. package/lib/components/chat/types/inference.d.ts +17 -0
  49. package/lib/components/chat/types/protocol.d.ts +10 -0
  50. package/lib/components/index.d.ts +23 -0
  51. package/lib/components/index.js +11 -0
  52. package/lib/config/agents.d.ts +33 -0
  53. package/lib/config/agents.js +424 -0
  54. package/lib/config/index.d.ts +4 -0
  55. package/lib/config/index.js +8 -0
  56. package/lib/config/mcpServers.d.ts +18 -0
  57. package/lib/config/mcpServers.js +129 -0
  58. package/lib/config/skills.d.ts +25 -0
  59. package/lib/config/skills.js +54 -0
  60. package/lib/{lib → config}/utils.d.ts +1 -1
  61. package/lib/{lib → config}/utils.js +2 -2
  62. package/lib/examples/AgentRuntimeLexical2Example.d.ts +1 -0
  63. package/lib/examples/AgentRuntimeLexical2Example.js +3 -2
  64. package/lib/examples/AgentRuntimeLexicalExample.d.ts +1 -0
  65. package/lib/examples/AgentRuntimeLexicalExample.js +5 -3
  66. package/lib/examples/AgentRuntimeLexicalSidebarExample.d.ts +1 -0
  67. package/lib/examples/AgentRuntimeLexicalSidebarExample.js +3 -3
  68. package/lib/examples/AgentRuntimeNotebookExample.js +1 -1
  69. package/lib/examples/AgentSpaceFormExample.d.ts +2 -2
  70. package/lib/examples/AgentSpaceFormExample.js +167 -29
  71. package/lib/examples/CopilotKitLexicalExample.d.ts +1 -0
  72. package/lib/examples/CopilotKitLexicalExample.js +3 -2
  73. package/lib/examples/index.d.ts +1 -0
  74. package/lib/examples/stores/notebooks/NotebookExample2.ipynb.json +43 -43
  75. package/lib/hooks/useAGUI.d.ts +1 -1
  76. package/lib/hooks/useAGUI.js +1 -1
  77. package/lib/identity/types.d.ts +1 -1
  78. package/lib/index.d.ts +2 -0
  79. package/lib/index.js +1 -0
  80. package/lib/runtime/index.d.ts +3 -0
  81. package/lib/runtime/runtimeStore.d.ts +3 -4
  82. package/lib/runtime/useAgentConnection.d.ts +2 -3
  83. package/lib/runtime/useAgentRuntime.d.ts +2 -3
  84. package/lib/stories/Cell.stories.js +1 -1
  85. package/lib/tools/adapters/agent-runtimes/notebookHooks.js +1 -0
  86. package/lib/tools/adapters/copilotkit/notebookHooks.js +1 -0
  87. package/lib/types.d.ts +150 -0
  88. package/package.json +4 -5
  89. package/scripts/apply-patches.sh +1 -1
  90. package/scripts/codegen/generate_agents.py +452 -0
  91. package/scripts/codegen/generate_mcp_servers.py +424 -0
  92. package/scripts/codegen/generate_skills.py +321 -0
  93. package/scripts/download-ai-elements.py +35 -20
  94. package/scripts/sync-jupyter.sh +6 -0
  95. package/lib/components/ui/accordion.d.ts +0 -7
  96. package/lib/components/ui/accordion.js +0 -22
  97. package/lib/components/ui/alert-dialog.d.ts +0 -14
  98. package/lib/components/ui/alert-dialog.js +0 -43
  99. package/lib/components/ui/alert.d.ts +0 -9
  100. package/lib/components/ui/alert.js +0 -24
  101. package/lib/components/ui/aspect-ratio.d.ts +0 -3
  102. package/lib/components/ui/aspect-ratio.js +0 -11
  103. package/lib/components/ui/avatar.d.ts +0 -6
  104. package/lib/components/ui/avatar.js +0 -18
  105. package/lib/components/ui/badge.d.ts +0 -9
  106. package/lib/components/ui/badge.js +0 -22
  107. package/lib/components/ui/breadcrumb.d.ts +0 -11
  108. package/lib/components/ui/breadcrumb.js +0 -27
  109. package/lib/components/ui/button-group.d.ts +0 -11
  110. package/lib/components/ui/button-group.js +0 -31
  111. package/lib/components/ui/button.d.ts +0 -13
  112. package/lib/components/ui/button.js +0 -39
  113. package/lib/components/ui/calendar.d.ts +0 -8
  114. package/lib/components/ui/calendar.js +0 -80
  115. package/lib/components/ui/card.d.ts +0 -9
  116. package/lib/components/ui/card.js +0 -24
  117. package/lib/components/ui/carousel.d.ts +0 -19
  118. package/lib/components/ui/carousel.js +0 -95
  119. package/lib/components/ui/chart.d.ts +0 -53
  120. package/lib/components/ui/chart.js +0 -136
  121. package/lib/components/ui/checkbox.d.ts +0 -4
  122. package/lib/components/ui/checkbox.js +0 -13
  123. package/lib/components/ui/collapsible.d.ts +0 -5
  124. package/lib/components/ui/collapsible.js +0 -17
  125. package/lib/components/ui/command.d.ts +0 -18
  126. package/lib/components/ui/command.js +0 -38
  127. package/lib/components/ui/context-menu.d.ts +0 -25
  128. package/lib/components/ui/context-menu.js +0 -55
  129. package/lib/components/ui/dialog.d.ts +0 -15
  130. package/lib/components/ui/dialog.js +0 -40
  131. package/lib/components/ui/drawer.d.ts +0 -13
  132. package/lib/components/ui/drawer.js +0 -39
  133. package/lib/components/ui/dropdown-menu.d.ts +0 -25
  134. package/lib/components/ui/dropdown-menu.js +0 -55
  135. package/lib/components/ui/empty.d.ts +0 -11
  136. package/lib/components/ui/empty.js +0 -37
  137. package/lib/components/ui/field.d.ts +0 -24
  138. package/lib/components/ui/field.js +0 -80
  139. package/lib/components/ui/form.d.ts +0 -24
  140. package/lib/components/ui/form.js +0 -63
  141. package/lib/components/ui/hover-card.d.ts +0 -6
  142. package/lib/components/ui/hover-card.js +0 -18
  143. package/lib/components/ui/input-group.d.ts +0 -19
  144. package/lib/components/ui/input-group.js +0 -69
  145. package/lib/components/ui/input-otp.d.ts +0 -11
  146. package/lib/components/ui/input-otp.js +0 -25
  147. package/lib/components/ui/input.d.ts +0 -3
  148. package/lib/components/ui/input.js +0 -6
  149. package/lib/components/ui/item.d.ts +0 -23
  150. package/lib/components/ui/item.js +0 -66
  151. package/lib/components/ui/kbd.d.ts +0 -3
  152. package/lib/components/ui/kbd.js +0 -13
  153. package/lib/components/ui/label.d.ts +0 -4
  154. package/lib/components/ui/label.js +0 -12
  155. package/lib/components/ui/menubar.d.ts +0 -26
  156. package/lib/components/ui/menubar.js +0 -58
  157. package/lib/components/ui/navigation-menu.d.ts +0 -14
  158. package/lib/components/ui/navigation-menu.js +0 -31
  159. package/lib/components/ui/pagination.d.ts +0 -13
  160. package/lib/components/ui/pagination.js +0 -29
  161. package/lib/components/ui/popover.d.ts +0 -7
  162. package/lib/components/ui/popover.js +0 -21
  163. package/lib/components/ui/progress.d.ts +0 -4
  164. package/lib/components/ui/progress.js +0 -12
  165. package/lib/components/ui/radio-group.d.ts +0 -5
  166. package/lib/components/ui/radio-group.js +0 -16
  167. package/lib/components/ui/resizable.d.ts +0 -8
  168. package/lib/components/ui/resizable.js +0 -19
  169. package/lib/components/ui/scroll-area.d.ts +0 -5
  170. package/lib/components/ui/scroll-area.js +0 -17
  171. package/lib/components/ui/select.d.ts +0 -15
  172. package/lib/components/ui/select.js +0 -42
  173. package/lib/components/ui/separator.d.ts +0 -4
  174. package/lib/components/ui/separator.js +0 -12
  175. package/lib/components/ui/sheet.d.ts +0 -13
  176. package/lib/components/ui/sheet.js +0 -44
  177. package/lib/components/ui/sidebar.d.ts +0 -69
  178. package/lib/components/ui/sidebar.js +0 -216
  179. package/lib/components/ui/skeleton.d.ts +0 -2
  180. package/lib/components/ui/skeleton.js +0 -10
  181. package/lib/components/ui/slider.d.ts +0 -4
  182. package/lib/components/ui/slider.js +0 -18
  183. package/lib/components/ui/sonner.d.ts +0 -3
  184. package/lib/components/ui/sonner.js +0 -25
  185. package/lib/components/ui/spinner.d.ts +0 -2
  186. package/lib/components/ui/spinner.js +0 -11
  187. package/lib/components/ui/switch.d.ts +0 -4
  188. package/lib/components/ui/switch.js +0 -12
  189. package/lib/components/ui/table.d.ts +0 -10
  190. package/lib/components/ui/table.js +0 -32
  191. package/lib/components/ui/tabs.d.ts +0 -7
  192. package/lib/components/ui/tabs.js +0 -21
  193. package/lib/components/ui/textarea.d.ts +0 -3
  194. package/lib/components/ui/textarea.js +0 -6
  195. package/lib/components/ui/toast.d.ts +0 -15
  196. package/lib/components/ui/toast.js +0 -38
  197. package/lib/components/ui/toaster.d.ts +0 -1
  198. package/lib/components/ui/toaster.js +0 -14
  199. package/lib/components/ui/toggle-group.d.ts +0 -9
  200. package/lib/components/ui/toggle-group.js +0 -26
  201. package/lib/components/ui/toggle.d.ts +0 -9
  202. package/lib/components/ui/toggle.js +0 -30
  203. package/lib/components/ui/tooltip.d.ts +0 -7
  204. package/lib/components/ui/tooltip.js +0 -21
  205. package/lib/components/vercel-ai-elements/artifact.d.ts +0 -23
  206. package/lib/components/vercel-ai-elements/artifact.js +0 -24
  207. package/lib/components/vercel-ai-elements/code-block.d.ts +0 -17
  208. package/lib/components/vercel-ai-elements/code-block.js +0 -94
  209. package/lib/components/vercel-ai-elements/conversation.d.ts +0 -15
  210. package/lib/components/vercel-ai-elements/conversation.js +0 -21
  211. package/lib/components/vercel-ai-elements/loader.d.ts +0 -5
  212. package/lib/components/vercel-ai-elements/loader.js +0 -8
  213. package/lib/components/vercel-ai-elements/message.d.ts +0 -46
  214. package/lib/components/vercel-ai-elements/message.js +0 -109
  215. package/lib/components/vercel-ai-elements/model-selector.d.ts +0 -35
  216. package/lib/components/vercel-ai-elements/model-selector.js +0 -22
  217. package/lib/components/vercel-ai-elements/prompt-input.d.ts +0 -195
  218. package/lib/components/vercel-ai-elements/prompt-input.js +0 -589
  219. package/lib/components/vercel-ai-elements/reasoning.d.ts +0 -26
  220. package/lib/components/vercel-ai-elements/reasoning.js +0 -80
  221. package/lib/components/vercel-ai-elements/shimmer.d.ts +0 -9
  222. package/lib/components/vercel-ai-elements/shimmer.js +0 -22
  223. package/lib/components/vercel-ai-elements/sources.d.ts +0 -12
  224. package/lib/components/vercel-ai-elements/sources.js +0 -13
  225. package/lib/components/vercel-ai-elements/suggestion.d.ts +0 -10
  226. package/lib/components/vercel-ai-elements/suggestion.js +0 -16
  227. package/lib/components/vercel-ai-elements/tool.d.ts +0 -23
  228. package/lib/components/vercel-ai-elements/tool.js +0 -52
  229. package/lib/examples/components/MainContent.d.ts +0 -19
  230. package/lib/examples/components/index.d.ts +0 -10
  231. package/lib/examples/components/index.js +0 -13
  232. package/lib/examples/vercel-ai-elements/VercelAiElementsShowcase.d.ts +0 -12
  233. package/lib/examples/vercel-ai-elements/VercelAiElementsShowcase.js +0 -69
  234. package/lib/examples/vercel-ai-elements/components/ArtifactShowcase.d.ts +0 -1
  235. package/lib/examples/vercel-ai-elements/components/ArtifactShowcase.js +0 -85
  236. package/lib/examples/vercel-ai-elements/components/CodeBlockShowcase.d.ts +0 -1
  237. package/lib/examples/vercel-ai-elements/components/CodeBlockShowcase.js +0 -62
  238. package/lib/examples/vercel-ai-elements/components/ConversationShowcase.d.ts +0 -1
  239. package/lib/examples/vercel-ai-elements/components/ConversationShowcase.js +0 -51
  240. package/lib/examples/vercel-ai-elements/components/LoaderShowcase.d.ts +0 -1
  241. package/lib/examples/vercel-ai-elements/components/LoaderShowcase.js +0 -9
  242. package/lib/examples/vercel-ai-elements/components/MessageShowcase.d.ts +0 -1
  243. package/lib/examples/vercel-ai-elements/components/MessageShowcase.js +0 -56
  244. package/lib/examples/vercel-ai-elements/components/ModelSelectorShowcase.d.ts +0 -1
  245. package/lib/examples/vercel-ai-elements/components/ModelSelectorShowcase.js +0 -50
  246. package/lib/examples/vercel-ai-elements/components/PromptInputShowcase.d.ts +0 -1
  247. package/lib/examples/vercel-ai-elements/components/PromptInputShowcase.js +0 -16
  248. package/lib/examples/vercel-ai-elements/components/ReasoningShowcase.d.ts +0 -1
  249. package/lib/examples/vercel-ai-elements/components/ReasoningShowcase.js +0 -72
  250. package/lib/examples/vercel-ai-elements/components/ShimmerShowcase.d.ts +0 -1
  251. package/lib/examples/vercel-ai-elements/components/ShimmerShowcase.js +0 -9
  252. package/lib/examples/vercel-ai-elements/components/SourcesShowcase.d.ts +0 -1
  253. package/lib/examples/vercel-ai-elements/components/SourcesShowcase.js +0 -43
  254. package/lib/examples/vercel-ai-elements/components/SuggestionShowcase.d.ts +0 -1
  255. package/lib/examples/vercel-ai-elements/components/SuggestionShowcase.js +0 -31
  256. package/lib/examples/vercel-ai-elements/components/ToolShowcase.d.ts +0 -1
  257. package/lib/examples/vercel-ai-elements/components/ToolShowcase.js +0 -54
  258. package/lib/examples/vercel-ai-elements/index.d.ts +0 -13
  259. package/lib/examples/vercel-ai-elements/index.js +0 -17
  260. package/lib/examples/vercel-ai-elements/main.d.ts +0 -1
  261. package/lib/examples/vercel-ai-elements/main.js +0 -9
  262. package/lib/examples/vercel-ai-elements/showcase.css +0 -128
  263. package/lib/hooks/useToast.d.ts +0 -44
  264. package/lib/hooks/useToast.js +0 -128
  265. package/patches/@datalayer+jupyter-lexical+1.0.8.patch +0 -11628
  266. package/patches/@datalayer+jupyter-react+2.0.2.patch +0 -5338
  267. package/style/showcase-vercel-ai.css +0 -137
  268. /package/lib/{examples/components → components}/FooterMetrics.js +0 -0
  269. /package/lib/{examples/components → components}/MockFileBrowser.js +0 -0
  270. /package/lib/{examples/components → components}/SessionTabs.js +0 -0
  271. /package/lib/{examples/components → components}/TimeTravel.js +0 -0
  272. /package/lib/{models → types}/AIAgent.d.ts +0 -0
  273. /package/lib/{models → types}/AIAgent.js +0 -0
  274. /package/lib/{models → types}/index.d.ts +0 -0
  275. /package/lib/{models → types}/index.js +0 -0
package/README.md CHANGED
@@ -11,6 +11,7 @@
11
11
  # 🤖 Agent Runtimes
12
12
 
13
13
  [![Github Actions Status](https://github.com/datalayer/agent-runtimes/actions/workflows/build.yml/badge.svg)](https://github.com/datalayer/agent-runtimes/actions/workflows/build.yml)
14
+ [![Netlify Status](https://api.netlify.com/api/v1/badges/f7f9e08a-884f-4f76-b20d-666d5873716c/deploy-status)](https://app.netlify.com/projects/agent-runtimes/deploys)
14
15
  [![PyPI - Version](https://img.shields.io/pypi/v/agent-runtimes)](https://pypi.org/project/agent-runtimes)
15
16
 
16
17
  **Agent Runtimes** is a unified platform for deploying, managing, and interacting with AI agents across multiple protocols and frameworks. It provides both a Python server for hosting agents and React components for seamless integration into web and desktop applications.
@@ -40,7 +41,7 @@ Agent Runtimes solves the complexity of deploying AI agents by providing:
40
41
  - **MCP-UI**: Interactive UI resources protocol with React/Web Components
41
42
  - **A2A**: Agent-to-agent communication
42
43
 
43
- ### Multi-Agent Support
44
+ ### Multi-Agent Support
44
45
  - **Pydantic AI**: Type-safe agents (fully implemented)
45
46
  - **LangChain**: Complex workflows (adapter ready)
46
47
  - **Jupyter AI**: Notebook integration (adapter ready)
@@ -1,15 +1,13 @@
1
1
  import React from 'react';
2
- import type { Agent } from '../stores/examplesStore';
3
- import type { Transport, Extension } from '../../components/chat';
4
- import type { OAuthProvider, Identity } from '../../identity';
2
+ import type { Agent } from '../examples/stores/examplesStore';
3
+ import type { Transport, Extension } from './chat';
4
+ import type { McpServerSelection } from './McpServerManager';
5
+ import type { OAuthProvider, Identity } from '../identity';
6
+ import type { MCPServerTool as MCPServerToolType } from '../types';
5
7
  /**
6
- * MCP Server Tool type
8
+ * MCP Server Tool type (re-exported from types.ts)
7
9
  */
8
- export interface MCPServerTool {
9
- name: string;
10
- description?: string;
11
- enabled: boolean;
12
- }
10
+ export type MCPServerTool = MCPServerToolType;
13
11
  export interface SkillOption {
14
12
  id: string;
15
13
  name: string;
@@ -27,7 +25,12 @@ export interface MCPServerConfig {
27
25
  command?: string;
28
26
  args?: string[];
29
27
  isAvailable?: boolean;
28
+ isRunning?: boolean;
29
+ /** True if this server is from mcp.json config (vs catalog) */
30
+ isConfig?: boolean;
30
31
  transport?: string;
32
+ /** Required environment variables for this server */
33
+ requiredEnvVars?: string[];
31
34
  }
32
35
  type AgentLibrary = 'pydantic-ai' | 'langchain' | 'jupyter-ai';
33
36
  export type { AgentLibrary };
@@ -59,7 +62,7 @@ export interface AIModelConfig {
59
62
  requiredEnvVars?: string[];
60
63
  isAvailable?: boolean;
61
64
  }
62
- interface AgentConfigurationProps {
65
+ export interface AgentConfigurationProps {
63
66
  agentLibrary: AgentLibrary;
64
67
  transport: Transport;
65
68
  extensions: Extension[];
@@ -74,9 +77,11 @@ interface AgentConfigurationProps {
74
77
  enableCodemode?: boolean;
75
78
  allowDirectToolCalls?: boolean;
76
79
  enableToolReranker?: boolean;
80
+ useJupyterSandbox?: boolean;
77
81
  availableSkills?: SkillOption[];
78
82
  selectedSkills?: string[];
79
- selectedMcpServers?: string[];
83
+ /** Selected MCP servers */
84
+ selectedMcpServers?: McpServerSelection[];
80
85
  identityProviders?: {
81
86
  [K in OAuthProvider]?: {
82
87
  clientId: string;
@@ -97,8 +102,18 @@ interface AgentConfigurationProps {
97
102
  onEnableCodemodeChange?: (enabled: boolean) => void;
98
103
  onAllowDirectToolCallsChange?: (enabled: boolean) => void;
99
104
  onEnableToolRerankerChange?: (enabled: boolean) => void;
105
+ onUseJupyterSandboxChange?: (enabled: boolean) => void;
100
106
  onSelectedSkillsChange?: (skills: string[]) => void;
101
- onSelectedMcpServersChange?: (servers: string[]) => void;
107
+ /** Callback when MCP server selection changes */
108
+ onSelectedMcpServersChange?: (servers: McpServerSelection[]) => void;
109
+ /** Rich editor mode */
110
+ richEditor?: boolean;
111
+ /** Callback when rich editor changes */
112
+ onRichEditorChange?: (enabled: boolean) => void;
113
+ /** Durable mode */
114
+ durable?: boolean;
115
+ /** Callback when durable changes */
116
+ onDurableChange?: (enabled: boolean) => void;
102
117
  }
103
118
  /**
104
119
  * Agent Configuration Component
@@ -6,10 +6,10 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
6
6
  import { useMemo, useState, useCallback } from 'react';
7
7
  import { Text, TextInput, Button, FormControl, Select, Checkbox, Spinner, Flash, Label, IconButton, } from '@primer/react';
8
8
  import { ToolsIcon, KeyIcon, SyncIcon, PlusIcon, XIcon, LinkExternalIcon, } from '@primer/octicons-react';
9
- import { useQuery } from '@tanstack/react-query';
9
+ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
10
10
  import { Box } from '@datalayer/primer-addons';
11
- import { IdentityConnect, useIdentity } from '../../identity';
12
- import { IdentityCard } from '../../components/chat';
11
+ import { IdentityConnect, useIdentity } from '../identity';
12
+ import { IdentityCard } from './chat';
13
13
  /**
14
14
  * Token-based identity providers that can be connected via API key
15
15
  */
@@ -199,8 +199,8 @@ const EXTENSIONS = [
199
199
  *
200
200
  * Form for configuring agent connection settings.
201
201
  */
202
- export const AgentConfiguration = ({ agentLibrary, transport, extensions, wsUrl, baseUrl, agentName, model, agents, selectedAgentId, isCreatingAgent = false, createError = null, enableCodemode = false, allowDirectToolCalls = false, enableToolReranker = false, availableSkills = [], selectedSkills = [], selectedMcpServers = [], identityProviders, onIdentityConnect, onIdentityDisconnect, onAgentLibraryChange, onTransportChange, onExtensionsChange, onWsUrlChange, onBaseUrlChange, onAgentNameChange, onModelChange, onAgentSelect, onConnect, onEnableCodemodeChange, onAllowDirectToolCallsChange, onEnableToolRerankerChange, onSelectedSkillsChange, onSelectedMcpServersChange, }) => {
203
- // Fetch MCP servers configuration from the backend
202
+ export const AgentConfiguration = ({ agentLibrary, transport, extensions, wsUrl, baseUrl, agentName, model, agents, selectedAgentId, isCreatingAgent = false, createError = null, enableCodemode = false, allowDirectToolCalls = false, enableToolReranker = false, useJupyterSandbox = false, availableSkills = [], selectedSkills = [], selectedMcpServers = [], identityProviders, onIdentityConnect, onIdentityDisconnect, onAgentLibraryChange, onTransportChange, onExtensionsChange, onWsUrlChange, onBaseUrlChange, onAgentNameChange, onModelChange, onAgentSelect, onConnect, onEnableCodemodeChange, onAllowDirectToolCallsChange, onEnableToolRerankerChange, onUseJupyterSandboxChange, onSelectedSkillsChange, onSelectedMcpServersChange, }) => {
203
+ // Fetch general configuration from the backend (models, etc.)
204
204
  const configQuery = useQuery({
205
205
  queryKey: ['agent-config', baseUrl],
206
206
  queryFn: async () => {
@@ -214,6 +214,20 @@ export const AgentConfiguration = ({ agentLibrary, transport, extensions, wsUrl,
214
214
  staleTime: 1000 * 60 * 5, // 5 minutes
215
215
  retry: 1,
216
216
  });
217
+ // Fetch MCP Config servers from mcp.json (user-defined servers)
218
+ const mcpServersQuery = useQuery({
219
+ queryKey: ['mcp-config', baseUrl],
220
+ queryFn: async () => {
221
+ const response = await fetch(`${baseUrl}/api/v1/mcp/servers/config`);
222
+ if (!response.ok) {
223
+ throw new Error('Failed to fetch MCP config servers');
224
+ }
225
+ return response.json();
226
+ },
227
+ enabled: !!baseUrl,
228
+ staleTime: 1000 * 60 * 1, // 1 minute (refresh more often for running status)
229
+ retry: 1,
230
+ });
217
231
  // Fetch skills from the backend (only when codemode is enabled)
218
232
  const skillsQuery = useQuery({
219
233
  queryKey: ['agent-skills', baseUrl],
@@ -228,22 +242,102 @@ export const AgentConfiguration = ({ agentLibrary, transport, extensions, wsUrl,
228
242
  staleTime: 1000 * 60 * 5, // 5 minutes
229
243
  retry: 1,
230
244
  });
231
- const mcpServers = configQuery.data?.mcpServers || [];
245
+ // Fetch MCP Catalog servers (predefined servers that can be enabled on-demand)
246
+ const catalogServersQuery = useQuery({
247
+ queryKey: ['mcp-catalog', baseUrl],
248
+ queryFn: async () => {
249
+ const response = await fetch(`${baseUrl}/api/v1/mcp/servers/catalog`);
250
+ if (!response.ok) {
251
+ throw new Error('Failed to fetch MCP catalog servers');
252
+ }
253
+ return response.json();
254
+ },
255
+ enabled: !!baseUrl,
256
+ staleTime: 1000 * 60 * 5, // 5 minutes
257
+ retry: 1,
258
+ });
259
+ // Query client for invalidating queries
260
+ const queryClient = useQueryClient();
261
+ // Mutation to enable a catalog server
262
+ const enableCatalogServerMutation = useMutation({
263
+ mutationFn: async (serverName) => {
264
+ const response = await fetch(`${baseUrl}/api/v1/mcp/servers/catalog/${serverName}/enable`, { method: 'POST' });
265
+ if (!response.ok) {
266
+ const error = await response
267
+ .json()
268
+ .catch(() => ({ detail: 'Unknown error' }));
269
+ throw new Error(error.detail || 'Failed to enable server');
270
+ }
271
+ return response.json();
272
+ },
273
+ onSuccess: () => {
274
+ // Refresh both config and catalog queries to get updated running status
275
+ queryClient.invalidateQueries({ queryKey: ['mcp-config', baseUrl] });
276
+ queryClient.invalidateQueries({ queryKey: ['mcp-catalog', baseUrl] });
277
+ },
278
+ });
279
+ // Use MCP servers from dedicated query, fallback to configQuery for backwards compatibility
280
+ const configServers = mcpServersQuery.data || configQuery.data?.mcpServers || [];
281
+ const catalogServers = catalogServersQuery.data || [];
232
282
  const models = configQuery.data?.models || [];
233
283
  // Use fetched skills when codemode is enabled, otherwise use passed availableSkills (which may be empty)
234
284
  const fetchedSkills = skillsQuery.data?.skills || [];
235
285
  const displaySkills = enableCodemode ? fetchedSkills : availableSkills;
236
- const previewServers = selectedMcpServers.length
237
- ? mcpServers.filter(server => selectedMcpServers.includes(server.id))
238
- : [];
239
286
  const skillsEnabled = selectedSkills.length > 0;
240
- // Handle MCP server checkbox change
241
- const handleMcpServerChange = (serverId, checked) => {
287
+ const selectedConfigServers = selectedMcpServers
288
+ .filter(s => s.origin === 'config')
289
+ .map(s => s.id);
290
+ const selectedCatalogServers = selectedMcpServers
291
+ .filter(s => s.origin === 'catalog')
292
+ .map(s => s.id);
293
+ // Preview servers combines both config and catalog selections
294
+ const previewConfigServers = selectedConfigServers.length
295
+ ? configServers.filter(server => selectedConfigServers.includes(server.id))
296
+ : [];
297
+ const previewCatalogServers = selectedCatalogServers.length
298
+ ? catalogServers.filter(server => selectedCatalogServers.includes(server.id))
299
+ : [];
300
+ // Handle MCP Config server checkbox change
301
+ const handleConfigServerChange = (serverId, checked) => {
302
+ if (!onSelectedMcpServersChange)
303
+ return;
242
304
  if (checked) {
243
- onSelectedMcpServersChange?.([...selectedMcpServers, serverId]);
305
+ if (!selectedMcpServers.some(s => s.id === serverId && s.origin === 'config')) {
306
+ onSelectedMcpServersChange([
307
+ ...selectedMcpServers,
308
+ { id: serverId, origin: 'config' },
309
+ ]);
310
+ }
244
311
  }
245
312
  else {
246
- onSelectedMcpServersChange?.(selectedMcpServers.filter(id => id !== serverId));
313
+ onSelectedMcpServersChange(selectedMcpServers.filter(s => !(s.id === serverId && s.origin === 'config')));
314
+ }
315
+ };
316
+ // Handle MCP Catalog server checkbox change
317
+ // If selected and not running, enable (start) the server first
318
+ const handleCatalogServerChange = async (serverId, checked, isRunning) => {
319
+ if (!onSelectedMcpServersChange)
320
+ return;
321
+ if (checked) {
322
+ // If not running, start the server first
323
+ if (!isRunning) {
324
+ try {
325
+ await enableCatalogServerMutation.mutateAsync(serverId);
326
+ }
327
+ catch (error) {
328
+ console.error('Failed to enable catalog server:', error);
329
+ return; // Don't add to selection if enable failed
330
+ }
331
+ }
332
+ if (!selectedMcpServers.some(s => s.id === serverId && s.origin === 'catalog')) {
333
+ onSelectedMcpServersChange([
334
+ ...selectedMcpServers,
335
+ { id: serverId, origin: 'catalog' },
336
+ ]);
337
+ }
338
+ }
339
+ else {
340
+ onSelectedMcpServersChange(selectedMcpServers.filter(s => !(s.id === serverId && s.origin === 'catalog')));
247
341
  }
248
342
  };
249
343
  const handleSkillChange = (skillId, checked) => {
@@ -313,7 +407,7 @@ export const AgentConfiguration = ({ agentLibrary, transport, extensions, wsUrl,
313
407
  borderColor: 'border.default',
314
408
  borderRadius: 2,
315
409
  backgroundColor: 'canvas.default',
316
- }, children: [_jsx(Text, { sx: { fontSize: 1, fontWeight: 'bold', display: 'block', mb: 2 }, children: "Agent Capabilities" }), _jsx(Box, { sx: { display: 'flex', gap: 4 }, children: _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(Checkbox, { checked: enableCodemode, disabled: selectedAgentId !== 'new-agent', onChange: e => onEnableCodemodeChange?.(e.target.checked) }), _jsxs(Box, { children: [_jsx(Text, { sx: { fontSize: 1 }, children: "Codemode" }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted', display: 'block' }, children: "Execute code to compose tools" })] })] }) }), skillsEnabled && enableCodemode && (_jsx(Flash, { variant: "default", sx: { mt: 3 }, children: _jsx(Text, { sx: { fontSize: 0 }, children: "Skills provide curated capabilities; Codemode composes tools with Python for multi-step execution." }) })), enableCodemode && (_jsxs(Box, { sx: { mt: 3, display: 'flex', flexDirection: 'column', gap: 2 }, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(Checkbox, { checked: allowDirectToolCalls, disabled: selectedAgentId !== 'new-agent', onChange: e => onAllowDirectToolCallsChange?.(e.target.checked) }), _jsxs(Box, { children: [_jsx(Text, { sx: { fontSize: 1 }, children: "Allow direct tool calls" }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted', display: 'block' }, children: "Expose call_tool for simple, single-tool operations" })] })] }), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(Checkbox, { checked: enableToolReranker, disabled: selectedAgentId !== 'new-agent', onChange: e => onEnableToolRerankerChange?.(e.target.checked) }), _jsxs(Box, { children: [_jsx(Text, { sx: { fontSize: 1 }, children: "Enable tool reranker" }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted', display: 'block' }, children: "Reorder search results using the configured reranker" })] })] })] }))] }), _jsxs(Box, { sx: {
410
+ }, children: [_jsx(Text, { sx: { fontSize: 1, fontWeight: 'bold', display: 'block', mb: 2 }, children: "Agent Capabilities" }), _jsx(Box, { sx: { display: 'flex', gap: 4 }, children: _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(Checkbox, { checked: enableCodemode, disabled: selectedAgentId !== 'new-agent', onChange: e => onEnableCodemodeChange?.(e.target.checked) }), _jsxs(Box, { children: [_jsx(Text, { sx: { fontSize: 1 }, children: "Codemode" }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted', display: 'block' }, children: "Execute code to compose tools" })] })] }) }), skillsEnabled && enableCodemode && (_jsx(Flash, { variant: "default", sx: { mt: 3 }, children: _jsx(Text, { sx: { fontSize: 0 }, children: "Skills provide curated capabilities; Codemode composes tools with Python for multi-step execution." }) })), enableCodemode && (_jsxs(Box, { sx: { mt: 3, display: 'flex', flexDirection: 'column', gap: 2 }, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(Checkbox, { checked: allowDirectToolCalls, disabled: selectedAgentId !== 'new-agent', onChange: e => onAllowDirectToolCallsChange?.(e.target.checked) }), _jsxs(Box, { children: [_jsx(Text, { sx: { fontSize: 1 }, children: "Allow direct tool calls" }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted', display: 'block' }, children: "Expose call_tool for simple, single-tool operations" })] })] }), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(Checkbox, { checked: enableToolReranker, disabled: selectedAgentId !== 'new-agent', onChange: e => onEnableToolRerankerChange?.(e.target.checked) }), _jsxs(Box, { children: [_jsx(Text, { sx: { fontSize: 1 }, children: "Enable tool reranker" }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted', display: 'block' }, children: "Reorder search results using the configured reranker" })] })] }), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(Checkbox, { checked: useJupyterSandbox, disabled: selectedAgentId !== 'new-agent', onChange: e => onUseJupyterSandboxChange?.(e.target.checked) }), _jsxs(Box, { children: [_jsx(Text, { sx: { fontSize: 1 }, children: "Use Jupyter Sandbox" }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted', display: 'block' }, children: "Execute code in a Jupyter kernel instead of local-eval" })] })] })] }))] }), _jsxs(Box, { sx: {
317
411
  marginBottom: 3,
318
412
  padding: 3,
319
413
  border: '1px solid',
@@ -346,31 +440,85 @@ export const AgentConfiguration = ({ agentLibrary, transport, extensions, wsUrl,
346
440
  alignItems: 'center',
347
441
  gap: 2,
348
442
  marginBottom: 2,
349
- }, children: [_jsx(ToolsIcon, { size: 16 }), _jsx(Text, { sx: { fontSize: 1, fontWeight: 'bold' }, children: "MCP Servers" }), configQuery.isLoading && _jsx(Spinner, { size: "small" }), !configQuery.isLoading && (_jsx(Button, { variant: "invisible", size: "small", onClick: () => configQuery.refetch(), sx: { padding: 1 }, "aria-label": "Refresh MCP servers", children: _jsx(SyncIcon, { size: 14 }) }))] }), configQuery.isError && (_jsx(Flash, { variant: "warning", sx: { marginBottom: 2 }, children: _jsx(Text, { sx: { fontSize: 0 }, children: "Unable to fetch MCP servers. Check that the server is running." }) })), mcpServers.length === 0 &&
350
- !configQuery.isLoading &&
351
- !configQuery.isError && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "No MCP servers configured." })), enableCodemode && (_jsx(Flash, { variant: "default", sx: { marginBottom: 2 }, children: _jsx(Text, { sx: { fontSize: 0 }, children: "When Codemode is enabled, selected MCP servers are used to build the Codemode tool registry (tools are exposed via Codemode meta tools like search and execute_code)." }) })), enableCodemode && (_jsxs(Box, { sx: {
443
+ }, children: [_jsx(ToolsIcon, { size: 16 }), _jsx(Text, { sx: { fontSize: 1, fontWeight: 'bold' }, children: "MCP Config Servers" }), mcpServersQuery.isLoading && _jsx(Spinner, { size: "small" }), !mcpServersQuery.isLoading && (_jsx(Button, { variant: "invisible", size: "small", onClick: () => mcpServersQuery.refetch(), sx: { padding: 1 }, "aria-label": "Refresh MCP config servers", children: _jsx(SyncIcon, { size: 14 }) }))] }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted', marginBottom: 2 }, children: "Servers from your mcp.json configuration file. Started automatically." }), mcpServersQuery.isError && (_jsx(Flash, { variant: "warning", sx: { marginBottom: 2 }, children: _jsx(Text, { sx: { fontSize: 0 }, children: "Unable to fetch MCP config servers. Check that the server is running." }) })), configServers.length === 0 &&
444
+ !mcpServersQuery.isLoading &&
445
+ !mcpServersQuery.isError && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "No MCP config servers found. Add servers to ~/.datalayer/mcp.json" })), enableCodemode && (_jsx(Flash, { variant: "default", sx: { marginBottom: 2 }, children: _jsx(Text, { sx: { fontSize: 0 }, children: "When Codemode is enabled, selected MCP servers are used to build the Codemode tool registry (tools are exposed via Codemode meta tools like search and execute_code)." }) })), enableCodemode && (_jsxs(Box, { sx: {
352
446
  marginBottom: 2,
353
447
  padding: 2,
354
448
  borderRadius: 1,
355
449
  border: '1px solid',
356
450
  borderColor: 'border.default',
357
451
  backgroundColor: 'canvas.subtle',
358
- }, children: [_jsx(Text, { sx: { fontSize: 0, fontWeight: 'semibold', display: 'block' }, children: "Codemode registry preview" }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted', mb: 1 }, children: selectedMcpServers.length > 0
452
+ }, children: [_jsx(Text, { sx: { fontSize: 0, fontWeight: 'semibold', display: 'block' }, children: "Codemode registry preview" }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted', mb: 1 }, children: selectedConfigServers.length > 0 ||
453
+ selectedCatalogServers.length > 0
359
454
  ? 'Using selected MCP servers'
360
- : 'No servers selected — select servers to scope Codemode tools.' }), previewServers.length > 0 ? (_jsx(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 1 }, children: previewServers.map(server => (_jsxs(Text, { sx: { fontSize: 0 }, children: [server.name, " \u2014 ", server.tools.length, " tools"] }, server.id))) })) : (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "No servers selected." })), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted', mt: 2 }, children: "Exposed meta-tools: list_tool_names, search_tools, get_tool_details, list_servers, execute_code, call_tool (optional)" })] })), mcpServers.length > 0 && (_jsx(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 2 }, children: mcpServers.map(server => (_jsxs(Box, { sx: {
455
+ : 'No servers selected — select servers to scope Codemode tools.' }), previewConfigServers.length > 0 ||
456
+ previewCatalogServers.length > 0 ? (_jsxs(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 1 }, children: [previewConfigServers.map(server => (_jsxs(Text, { sx: { fontSize: 0 }, children: [server.name, " \u2014 ", server.tools.length, " tools (config)"] }, server.id))), previewCatalogServers.map(server => (_jsxs(Text, { sx: { fontSize: 0 }, children: [server.name, " \u2014 ", server.tools?.length || 0, " tools (catalog)"] }, server.id)))] })) : (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "No servers selected." })), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted', mt: 2 }, children: "Exposed meta-tools: list_tool_names, search_tools, get_tool_details, list_servers, execute_code, call_tool (optional)" })] })), configServers.length > 0 && (_jsx(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 2 }, children: configServers.map(server => (_jsxs(Box, { sx: {
361
457
  display: 'flex',
362
458
  alignItems: 'flex-start',
363
459
  gap: 2,
364
460
  padding: 2,
365
461
  borderRadius: 1,
366
462
  backgroundColor: 'canvas.subtle',
367
- opacity: mcpServersDisabled || !server.isAvailable ? 0.6 : 1,
368
- }, children: [_jsx(Checkbox, { checked: selectedMcpServers.includes(server.id), disabled: mcpServersDisabled || !server.isAvailable, onChange: e => handleMcpServerChange(server.id, e.target.checked) }), _jsxs(Box, { sx: {
463
+ opacity: mcpServersDisabled ? 0.6 : 1,
464
+ }, children: [_jsx(Checkbox, { checked: selectedConfigServers.includes(server.id), disabled: mcpServersDisabled, onChange: e => handleConfigServerChange(server.id, e.target.checked) }), _jsxs(Box, { sx: {
369
465
  display: 'flex',
370
466
  flexDirection: 'column',
371
467
  gap: 1,
372
468
  flex: 1,
373
- }, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(Text, { sx: { fontWeight: 'semibold' }, children: server.name }), _jsx(Label, { variant: server.isAvailable ? 'success' : 'secondary', size: "small", children: server.isAvailable ? 'Available' : 'Not Available' })] }), server.tools.length > 0 && (_jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: ["Tools: ", server.tools.map(t => t.name).join(', ')] }))] })] }, server.id))) }))] }), createError && (_jsx(Flash, { variant: "danger", sx: { marginBottom: 3 }, children: createError })), _jsx(Button, { variant: "primary", onClick: onConnect, disabled: isCreatingAgent ||
469
+ }, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(Text, { sx: { fontWeight: 'semibold' }, children: server.name }), _jsx(Label, { variant: "success", size: "small", children: "Running" })] }), server.tools.length > 0 && (_jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: ["Tools: ", server.tools.map(t => t.name).join(', ')] }))] })] }, server.id))) }))] }), catalogServers.length > 0 && (_jsxs(Box, { sx: {
470
+ marginBottom: 3,
471
+ padding: 3,
472
+ border: '1px solid',
473
+ borderColor: 'border.default',
474
+ borderRadius: 2,
475
+ backgroundColor: 'canvas.default',
476
+ }, children: [_jsxs(Box, { sx: {
477
+ display: 'flex',
478
+ alignItems: 'center',
479
+ gap: 2,
480
+ marginBottom: 2,
481
+ }, children: [_jsx(ToolsIcon, { size: 16 }), _jsx(Text, { sx: { fontSize: 1, fontWeight: 'bold' }, children: "MCP Catalog Servers" })] }), _jsx(Text, { sx: {
482
+ fontSize: 0,
483
+ color: 'fg.muted',
484
+ marginBottom: 2,
485
+ }, children: "Predefined servers that can be enabled on-demand. Select to start and add to your agent." }), _jsx(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 2 }, children: catalogServers.map(server => {
486
+ // If required env vars are not provided, treat as available
487
+ const hasRequiredEnvVars = (server.requiredEnvVars?.length || 0) > 0;
488
+ const envVarsAvailable = hasRequiredEnvVars
489
+ ? server.isAvailable === true
490
+ : true;
491
+ const isRunning = server.isRunning === true;
492
+ const canSelect = envVarsAvailable || isRunning;
493
+ return (_jsxs(Box, { sx: {
494
+ display: 'flex',
495
+ alignItems: 'flex-start',
496
+ gap: 2,
497
+ padding: 2,
498
+ borderRadius: 1,
499
+ backgroundColor: 'canvas.subtle',
500
+ opacity: mcpServersDisabled || !canSelect ? 0.6 : 1,
501
+ }, children: [_jsx(Checkbox, { checked: selectedCatalogServers.includes(server.id), disabled: mcpServersDisabled ||
502
+ enableCatalogServerMutation.isPending ||
503
+ !canSelect, onChange: e => handleCatalogServerChange(server.id, e.target.checked, isRunning) }), _jsxs(Box, { sx: {
504
+ display: 'flex',
505
+ flexDirection: 'column',
506
+ gap: 1,
507
+ flex: 1,
508
+ }, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(Text, { sx: { fontWeight: 'semibold' }, children: server.name }), enableCatalogServerMutation.isPending &&
509
+ enableCatalogServerMutation.variables === server.id ? (_jsx(Label, { variant: "accent", size: "small", children: "Starting..." })) : server.isRunning ? (_jsx(Label, { variant: "success", size: "small", children: "Running" })) : (_jsx(Label, { variant: "secondary", size: "small", children: "Not Started" })), server.isConfig && (_jsx(Label, { variant: "secondary", size: "small", children: "From Config" }))] }), hasRequiredEnvVars ? (_jsx(Box, { sx: { display: 'flex', flexWrap: 'wrap', gap: 1 }, children: server.requiredEnvVars?.map(envVar => (_jsx(Label, { variant: envVarsAvailable ? 'success' : 'danger', size: "small", children: envVar }, envVar))) })) : (_jsx(Box, { sx: { display: 'flex' }, children: _jsx(Label, { variant: "success", size: "small", children: "No env vars required" }) })), server.tools && server.tools.length > 0 && (_jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: ["Tools: ", server.tools.map(t => t.name).join(', ')] }))] })] }, server.id));
510
+ }) })] })), createError && (_jsx(Flash, { variant: "danger", sx: { marginBottom: 3 }, children: createError })), _jsxs(Box, { sx: {
511
+ display: 'flex',
512
+ flexDirection: 'column',
513
+ gap: 2,
514
+ marginBottom: 3,
515
+ padding: 3,
516
+ bg: 'canvas.subtle',
517
+ borderRadius: 2,
518
+ border: '1px solid',
519
+ borderColor: 'border.default',
520
+ opacity: 0.6,
521
+ }, children: [_jsx(Text, { sx: { fontSize: 1, fontWeight: 'semibold', color: 'fg.muted' }, children: "Coming Soon" }), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(Checkbox, { checked: false, disabled: true, onChange: () => { } }), _jsx(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: "Rich Editor" }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "\u2014 Enable rich text editing with formatting options" })] }), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(Checkbox, { checked: false, disabled: true, onChange: () => { } }), _jsx(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: "Durable" }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "\u2014 Persist agent state across sessions" })] })] }), _jsx(Button, { variant: "primary", onClick: onConnect, disabled: isCreatingAgent ||
374
522
  !agentName ||
375
523
  (transport === 'acp' ? !wsUrl : !baseUrl), sx: { width: '100%' }, children: isCreatingAgent ? (_jsxs(Box, { sx: {
376
524
  display: 'flex',
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- interface FooterMetricsProps {
2
+ export interface FooterMetricsProps {
3
3
  tokens: number;
4
4
  cost: number;
5
5
  }
@@ -9,4 +9,3 @@ interface FooterMetricsProps {
9
9
  * Displays token usage and cost.
10
10
  */
11
11
  export declare const FooterMetrics: React.FC<FooterMetricsProps>;
12
- export {};
@@ -1,17 +1,13 @@
1
1
  import React from 'react';
2
- interface HeaderProps {
2
+ export interface HeaderProps {
3
3
  activeSession: string;
4
4
  agentName?: string;
5
5
  agentDescription?: string;
6
6
  agentStatus?: 'running' | 'paused';
7
- richEditor: boolean;
8
- durable: boolean;
9
7
  showContextTree: boolean;
10
8
  isNewAgent?: boolean;
11
9
  isConfigured?: boolean;
12
10
  onSessionChange: (sessionId: string) => void;
13
- onRichEditorChange: (value: boolean) => void;
14
- onDurableChange: (value: boolean) => void;
15
11
  onToggleContextTree: () => void;
16
12
  onToggleStatus?: () => void;
17
13
  }
@@ -22,4 +18,3 @@ interface HeaderProps {
22
18
  * toggle switches, controls, and optional context treemap.
23
19
  */
24
20
  export declare const Header: React.FC<HeaderProps>;
25
- export {};
@@ -3,9 +3,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  * Copyright (c) 2025-2026 Datalayer, Inc.
4
4
  * Distributed under the terms of the Modified BSD License.
5
5
  */
6
- import { useState, useRef } from 'react';
7
- import { Text, Button, PageLayout, ToggleSwitch, AvatarStack, Avatar, Spinner, TextInput, FormControl, AnchoredOverlay, IconButton, } from '@primer/react';
8
- import { ZapIcon, ListUnorderedIcon, InfoIcon, PlayIcon, PauseIcon, } from '@primer/octicons-react';
6
+ import { useState } from 'react';
7
+ import { Text, Button, PageLayout, AvatarStack, Avatar, Spinner, TextInput, FormControl, IconButton, } from '@primer/react';
8
+ import { ZapIcon, ListUnorderedIcon, PlayIcon, PauseIcon, } from '@primer/octicons-react';
9
9
  import { Box } from '@datalayer/primer-addons';
10
10
  import ReactECharts from 'echarts-for-react';
11
11
  import { SessionTabs } from './SessionTabs';
@@ -112,15 +112,12 @@ const OPTIMIZED_CONTEXT_DATA = {
112
112
  * Main header for the agent runtime interface with session tabs,
113
113
  * toggle switches, controls, and optional context treemap.
114
114
  */
115
- export const Header = ({ activeSession, agentName, agentDescription, agentStatus, richEditor, durable, showContextTree, isNewAgent = false, isConfigured = false, onSessionChange, onRichEditorChange, onDurableChange, onToggleContextTree, onToggleStatus, }) => {
115
+ export const Header = ({ activeSession, agentName, agentDescription, agentStatus, showContextTree, isNewAgent = false, isConfigured = false, onSessionChange, onToggleContextTree, onToggleStatus, }) => {
116
116
  const [isOptimizing, setIsOptimizing] = useState(false);
117
117
  const [contextData, setContextData] = useState(MOCK_CONTEXT_DATA);
118
118
  const [totalTokens, setTotalTokens] = useState('1.52M');
119
119
  const [showDetails, setShowDetails] = useState(false);
120
120
  const [showAvatarView, setShowAvatarView] = useState(false);
121
- const [openOverlay, setOpenOverlay] = useState(null);
122
- const richEditorRef = useRef(null);
123
- const durableRef = useRef(null);
124
121
  const handleOptimize = () => {
125
122
  setIsOptimizing(true);
126
123
  setTimeout(() => {
@@ -136,38 +133,7 @@ export const Header = ({ activeSession, agentName, agentDescription, agentStatus
136
133
  py: 2,
137
134
  }, children: [agentName && (_jsx(SessionTabs, { sessions: MOCK_SESSIONS, activeSession: activeSession, agentName: agentName, agentDescription: agentDescription, onSessionChange: onSessionChange, onAddSession: () => {
138
135
  /* Add session */
139
- } })), _jsxs(Box, { sx: {
140
- display: 'flex',
141
- alignItems: 'center',
142
- gap: 3,
143
- marginLeft: 'auto',
144
- }, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(ToggleSwitch, { size: "small", checked: richEditor, onClick: () => onRichEditorChange(!richEditor), "aria-labelledby": "rich-editor-label", disabled: isNewAgent || !isConfigured }), _jsx(Text, { id: "rich-editor-label", sx: { fontSize: 0 }, children: "Rich Editor" }), _jsx(IconButton, { ref: richEditorRef, icon: InfoIcon, size: "small", variant: "invisible", "aria-label": "Rich Editor info", onClick: () => setOpenOverlay(openOverlay === 'richEditor' ? null : 'richEditor') }), _jsx(AnchoredOverlay, { open: openOverlay === 'richEditor', onOpen: () => setOpenOverlay('richEditor'), onClose: () => setOpenOverlay(null), renderAnchor: () => _jsx("span", {}), anchorRef: richEditorRef, children: _jsxs(Box, { sx: {
145
- p: 3,
146
- maxWidth: '300px',
147
- bg: 'canvas.overlay',
148
- border: '1px solid',
149
- borderColor: 'border.default',
150
- borderRadius: 2,
151
- boxShadow: 'shadow.large',
152
- }, children: [_jsx(Text, { sx: {
153
- fontSize: 0,
154
- display: 'block',
155
- mb: 1,
156
- fontWeight: 'bold',
157
- }, children: "Rich Editor" }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Enable rich text editing with formatting options, markdown support, and visual enhancements for a better editing experience." })] }) })] }), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(ToggleSwitch, { size: "small", checked: durable, onClick: () => onDurableChange(!durable), "aria-labelledby": "durable-label", disabled: isNewAgent || !isConfigured }), _jsx(Text, { id: "durable-label", sx: { fontSize: 0 }, children: "Durable" }), _jsx(IconButton, { ref: durableRef, icon: InfoIcon, size: "small", variant: "invisible", "aria-label": "Durable info", onClick: () => setOpenOverlay(openOverlay === 'durable' ? null : 'durable') }), _jsx(AnchoredOverlay, { open: openOverlay === 'durable', onOpen: () => setOpenOverlay('durable'), onClose: () => setOpenOverlay(null), renderAnchor: () => _jsx("span", {}), anchorRef: durableRef, children: _jsxs(Box, { sx: {
158
- p: 3,
159
- maxWidth: '300px',
160
- bg: 'canvas.overlay',
161
- border: '1px solid',
162
- borderColor: 'border.default',
163
- borderRadius: 2,
164
- boxShadow: 'shadow.large',
165
- }, children: [_jsx(Text, { sx: {
166
- fontSize: 0,
167
- display: 'block',
168
- mb: 1,
169
- fontWeight: 'bold',
170
- }, children: "Durable" }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Persist agent state and conversation history across sessions. Your work is automatically saved and restored when you return." })] }) })] })] }), agentName && (_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [agentStatus && onToggleStatus && (_jsx(IconButton, { "aria-label": agentStatus === 'running' ? 'Pause agent' : 'Play agent', icon: agentStatus === 'running' ? PauseIcon : PlayIcon, onClick: onToggleStatus, variant: "invisible", size: "small", sx: {
136
+ } })), agentName && (_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [agentStatus && onToggleStatus && (_jsx(IconButton, { "aria-label": agentStatus === 'running' ? 'Pause agent' : 'Play agent', icon: agentStatus === 'running' ? PauseIcon : PlayIcon, onClick: onToggleStatus, variant: "invisible", size: "small", sx: {
171
137
  color: agentStatus === 'running' ? 'attention.fg' : 'success.fg',
172
138
  } })), _jsx(HeaderControls, { onToggleContextTree: onToggleContextTree })] })), agentName && (_jsx(Box, { onClick: () => setShowAvatarView(!showAvatarView), sx: { cursor: 'pointer' }, children: _jsxs(AvatarStack, { size: 24, disableExpand: true, children: [_jsx(Avatar, { alt: "Primer logo", src: "https://avatars.githubusercontent.com/primer" }), _jsx(Avatar, { alt: "GitHub logo", src: "https://avatars.githubusercontent.com/github" }), _jsx(Avatar, { alt: "Atom logo", src: "https://avatars.githubusercontent.com/atom" }), _jsx(Avatar, { alt: "GitHub Desktop logo", src: "https://avatars.githubusercontent.com/desktop" })] }) }))] }), agentName && showContextTree && (_jsxs(Box, { sx: {
173
139
  mt: 2,
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- interface HeaderControlsProps {
2
+ export interface HeaderControlsProps {
3
3
  onToggleContextTree: () => void;
4
4
  }
5
5
  /**
@@ -8,4 +8,3 @@ interface HeaderControlsProps {
8
8
  * Contains the context toggle sparkline.
9
9
  */
10
10
  export declare const HeaderControls: React.FC<HeaderControlsProps>;
11
- export {};
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Box } from '@datalayer/primer-addons';
3
- import { Sparklines, SparklinesLine } from '../../components/sparklines';
3
+ import { Sparklines, SparklinesLine } from './sparklines';
4
4
  /**
5
5
  * Header Controls Component
6
6
  *
@@ -13,8 +13,8 @@ import 'prismjs/components/prism-swift';
13
13
  import React from 'react';
14
14
  import type { ServiceManager } from '@jupyterlab/services';
15
15
  import '@datalayer/jupyter-lexical/style/index.css';
16
- import '../lexical/lexical-theme.css';
17
- interface LexicalEditorProps {
16
+ import '../examples/lexical/lexical-theme.css';
17
+ export interface LexicalEditorProps {
18
18
  content?: string;
19
19
  serviceManager?: ServiceManager.IManager;
20
20
  }
@@ -24,4 +24,3 @@ interface LexicalEditorProps {
24
24
  * Rich text editor with Simple integration.
25
25
  */
26
26
  export declare const LexicalEditor: React.FC<LexicalEditorProps>;
27
- export {};
@@ -34,9 +34,9 @@ import { LinkPlugin } from '@lexical/react/LexicalLinkPlugin';
34
34
  import { Box } from '@datalayer/primer-addons';
35
35
  import { JupyterReactTheme, useJupyter } from '@datalayer/jupyter-react';
36
36
  import { ComponentPickerMenuPlugin, JupyterCellPlugin, JupyterInputOutputPlugin, DraggableBlockPlugin, ImagesPlugin, HorizontalRulePlugin, EquationsPlugin, YouTubePlugin, AutoLinkPlugin, AutoEmbedPlugin, LexicalConfigProvider, LexicalStatePlugin, FloatingTextFormatToolbarPlugin, CodeActionMenuPlugin, ListMaxIndentLevelPlugin, } from '@datalayer/jupyter-lexical';
37
- import { editorConfig } from '../lexical/editorConfig';
37
+ import { editorConfig } from '../examples/lexical/editorConfig';
38
38
  import '@datalayer/jupyter-lexical/style/index.css';
39
- import '../lexical/lexical-theme.css';
39
+ import '../examples/lexical/lexical-theme.css';
40
40
  const LEXICAL_ID = 'agent-runtime-lexical-editor';
41
41
  const INITIAL_CONTENT = undefined;
42
42
  /**
@@ -0,0 +1,34 @@
1
+ import React from 'react';
2
+ import type { ServiceManager } from '@jupyterlab/services';
3
+ import { type McpServerSelection } from './McpServerManager';
4
+ export interface MainContentProps {
5
+ showNotebook: boolean;
6
+ timeTravel: number;
7
+ onTimeTravelChange: (value: number) => void;
8
+ richEditor: boolean;
9
+ notebookFile?: string;
10
+ lexicalFile?: string;
11
+ isNewAgent?: boolean;
12
+ serviceManager?: ServiceManager.IManager;
13
+ /** Base URL for MCP API */
14
+ baseUrl?: string;
15
+ /** Agent ID for updating the running agent */
16
+ agentId?: string;
17
+ /** Whether codemode is enabled */
18
+ enableCodemode?: boolean;
19
+ /** Currently selected MCP servers */
20
+ selectedMcpServers?: McpServerSelection[];
21
+ /** Callback when MCP server selection changes */
22
+ onSelectedMcpServersChange?: (servers: McpServerSelection[]) => void;
23
+ /** Callback when MCP servers are added/removed (for codemode regeneration) */
24
+ onMcpServersChange?: () => void;
25
+ /** Whether the agent is configured and running */
26
+ isConfigured?: boolean;
27
+ }
28
+ /**
29
+ * Main Content Component
30
+ *
31
+ * Displays the main content area with Simple notebook viewer or Lexical editor and time travel.
32
+ * When an agent is running (isConfigured=true), also shows the MCP Server Manager for runtime management.
33
+ */
34
+ export declare const MainContent: React.FC<MainContentProps>;
@@ -7,16 +7,18 @@ import React from 'react';
7
7
  import { Text } from '@primer/react';
8
8
  import { Box } from '@datalayer/primer-addons';
9
9
  import { JupyterReactTheme, Viewer } from '@datalayer/jupyter-react';
10
- import matplotlib from '../stores/notebooks/Matplotlib.ipynb.json';
11
- import emptyNotebook from '../stores/notebooks/Empty.ipynb.json';
12
10
  import { TimeTravel } from './TimeTravel';
13
11
  import { LexicalEditor } from './LexicalEditor';
12
+ import { McpServerManager } from './McpServerManager';
13
+ import matplotlib from '../examples/stores/notebooks/NotebookExample2.ipynb.json';
14
+ import emptyNotebook from '../examples/stores/notebooks/Empty.ipynb.json';
14
15
  /**
15
16
  * Main Content Component
16
17
  *
17
18
  * Displays the main content area with Simple notebook viewer or Lexical editor and time travel.
19
+ * When an agent is running (isConfigured=true), also shows the MCP Server Manager for runtime management.
18
20
  */
19
- export const MainContent = ({ showNotebook, timeTravel, onTimeTravelChange, richEditor, notebookFile, lexicalFile, isNewAgent, serviceManager, }) => {
21
+ export const MainContent = ({ showNotebook, timeTravel, onTimeTravelChange, richEditor, notebookFile, lexicalFile, isNewAgent, serviceManager, baseUrl, agentId, enableCodemode, selectedMcpServers, onSelectedMcpServersChange, onMcpServersChange, isConfigured, }) => {
20
22
  // Use the provided notebook or fall back to matplotlib demo
21
23
  const [notebookData, setNotebookData] = React.useState(matplotlib);
22
24
  const [lexicalContent, setLexicalContent] = React.useState(undefined);
@@ -59,10 +61,17 @@ export const MainContent = ({ showNotebook, timeTravel, onTimeTravelChange, rich
59
61
  setLexicalContent(undefined);
60
62
  }
61
63
  }, [lexicalFile, isNewAgent]);
62
- return (_jsx(Box, { sx: { height: '100%', overflow: 'auto', padding: 3 }, children: showNotebook ? (_jsxs(_Fragment, { children: [richEditor ? (_jsx(LexicalEditor, { serviceManager: serviceManager, content: lexicalContent })) : (_jsx(JupyterReactTheme, { children: _jsx(Viewer, { nbformat: notebookData, outputs: true }) })), !isNewAgent && (_jsx(TimeTravel, { value: timeTravel, onChange: onTimeTravelChange }))] })) : (_jsx(Box, { sx: {
63
- display: 'flex',
64
- alignItems: 'center',
65
- justifyContent: 'center',
66
- height: '100%',
67
- }, children: _jsx(Text, { sx: { color: 'fg.muted' }, children: "Select a file to view or create a new notebook" }) })) }));
64
+ return (_jsxs(Box, { sx: { height: '100%', overflow: 'auto', padding: 3 }, children: [isConfigured && baseUrl && (_jsx(Box, { sx: {
65
+ mb: 4,
66
+ p: 3,
67
+ bg: 'canvas.subtle',
68
+ borderRadius: 2,
69
+ border: '1px solid',
70
+ borderColor: 'border.default',
71
+ }, children: _jsx(McpServerManager, { baseUrl: baseUrl, agentId: agentId, enableCodemode: enableCodemode, selectedServers: selectedMcpServers, onSelectedServersChange: onSelectedMcpServersChange, onServersChange: onMcpServersChange, disabled: false }) })), showNotebook ? (_jsxs(_Fragment, { children: [richEditor ? (_jsx(LexicalEditor, { serviceManager: serviceManager, content: lexicalContent })) : (_jsx(JupyterReactTheme, { children: _jsx(Viewer, { nbformat: notebookData, outputs: true }) })), !isNewAgent && (_jsx(TimeTravel, { value: timeTravel, onChange: onTimeTravelChange }))] })) : (_jsx(Box, { sx: {
72
+ display: 'flex',
73
+ alignItems: 'center',
74
+ justifyContent: 'center',
75
+ height: '100%',
76
+ }, children: _jsx(Text, { sx: { color: 'fg.muted' }, children: "Select a file to view or create a new notebook" }) }))] }));
68
77
  };