@datalayer/agent-runtimes 0.0.10 → 0.0.12

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 (138) hide show
  1. package/README.md +2 -2
  2. package/lib/Agent.d.ts +29 -0
  3. package/lib/Agent.js +131 -0
  4. package/lib/AgentLexical.d.ts +34 -0
  5. package/lib/AgentLexical.js +296 -0
  6. package/lib/AgentNotebook.d.ts +19 -0
  7. package/lib/AgentNotebook.js +192 -0
  8. package/lib/agent-lexical-main.d.ts +1 -0
  9. package/lib/agent-lexical-main.js +11 -0
  10. package/lib/agent-main.d.ts +1 -0
  11. package/lib/agent-main.js +11 -0
  12. package/lib/agent-notebook-main.d.ts +1 -0
  13. package/lib/agent-notebook-main.js +12 -0
  14. package/lib/components/AgentConfiguration.d.ts +33 -21
  15. package/lib/components/AgentConfiguration.js +76 -21
  16. package/lib/components/chat/components/AgentDetails.d.ts +3 -1
  17. package/lib/components/chat/components/AgentDetails.js +164 -6
  18. package/lib/components/chat/components/Chat.d.ts +29 -3
  19. package/lib/components/chat/components/Chat.js +64 -59
  20. package/lib/components/chat/components/ChatFloating.d.ts +34 -12
  21. package/lib/components/chat/components/ChatFloating.js +54 -21
  22. package/lib/components/chat/components/ChatInline.d.ts +5 -1
  23. package/lib/components/chat/components/ChatInline.js +8 -1
  24. package/lib/components/chat/components/ChatSidebar.d.ts +6 -1
  25. package/lib/components/chat/components/ChatSidebar.js +2 -2
  26. package/lib/components/chat/components/ChatStandalone.d.ts +6 -1
  27. package/lib/components/chat/components/ChatStandalone.js +2 -2
  28. package/lib/components/chat/components/ContextDistribution.js +2 -2
  29. package/lib/components/chat/components/ContextInspector.js +4 -2
  30. package/lib/components/chat/components/ContextPanel.js +1 -6
  31. package/lib/components/chat/components/base/ChatBase.d.ts +49 -8
  32. package/lib/components/chat/components/base/ChatBase.js +544 -149
  33. package/lib/components/chat/components/base/InputPrompt.d.ts +42 -0
  34. package/lib/components/chat/components/base/InputPrompt.js +131 -0
  35. package/lib/components/chat/components/index.d.ts +3 -3
  36. package/lib/components/chat/components/index.js +1 -1
  37. package/lib/components/chat/components/parts/ReasoningPart.js +2 -4
  38. package/lib/components/chat/components/parts/TextPart.js +2 -70
  39. package/lib/components/chat/components/styles/streamdownStyles.d.ts +23 -0
  40. package/lib/components/chat/components/styles/streamdownStyles.js +319 -0
  41. package/lib/components/chat/index.d.ts +1 -1
  42. package/lib/components/chat/index.js +1 -1
  43. package/lib/components/chat/inference/DatalayerInferenceProvider.js +16 -12
  44. package/lib/components/chat/inference/SelfHostedInferenceProvider.js +16 -12
  45. package/lib/components/chat/protocols/AGUIAdapter.d.ts +10 -3
  46. package/lib/components/chat/protocols/AGUIAdapter.js +123 -44
  47. package/lib/components/chat/types/tool.d.ts +5 -2
  48. package/lib/components/index.d.ts +2 -19
  49. package/lib/components/index.js +1 -10
  50. package/lib/config/index.d.ts +0 -3
  51. package/lib/config/index.js +0 -3
  52. package/lib/examples/A2UiRestaurantExample.js +1 -1
  53. package/lib/examples/AgentRuntimeChatExample.d.ts +15 -0
  54. package/lib/examples/AgentRuntimeChatExample.js +126 -0
  55. package/lib/examples/{AgentSpaceFormExample.d.ts → AgentRuntimeFormExample.d.ts} +3 -3
  56. package/lib/examples/{AgentSpaceFormExample.js → AgentRuntimeFormExample.js} +61 -17
  57. package/lib/examples/AgentRuntimeLexicalExample.js +6 -3
  58. package/lib/examples/AgentRuntimeLexicalSidebarExample.js +8 -1
  59. package/lib/examples/AgentRuntimeNotebookExample.js +6 -5
  60. package/lib/examples/CopilotKitNotebookExample.js +2 -2
  61. package/lib/examples/JupyterNotebookExample.js +2 -2
  62. package/lib/{components → examples/components}/Header.d.ts +2 -1
  63. package/lib/{components → examples/components}/HeaderControls.js +1 -1
  64. package/lib/{components → examples/components}/LexicalEditor.d.ts +6 -1
  65. package/lib/{components → examples/components}/LexicalEditor.js +4 -4
  66. package/lib/{components → examples/components}/MainContent.d.ts +1 -1
  67. package/lib/{components → examples/components}/MainContent.js +7 -5
  68. package/lib/examples/components/index.d.ts +16 -0
  69. package/lib/examples/components/index.js +13 -0
  70. package/lib/examples/example-selector.js +2 -1
  71. package/lib/examples/index.d.ts +1 -1
  72. package/lib/examples/index.js +1 -1
  73. package/lib/examples/main.js +2 -2
  74. package/lib/examples/stores/examplesStore.d.ts +2 -23
  75. package/lib/index.d.ts +2 -1
  76. package/lib/index.js +1 -0
  77. package/lib/lexical/ChatInlinePlugin.d.ts +13 -2
  78. package/lib/lexical/ChatInlinePlugin.js +41 -179
  79. package/lib/lexical/index.d.ts +1 -0
  80. package/lib/lexical/index.js +1 -0
  81. package/lib/lexical/useChatInlineToolbarItems.d.ts +28 -0
  82. package/lib/lexical/useChatInlineToolbarItems.js +163 -0
  83. package/lib/runtime/useAgentRuntime.d.ts +1 -1
  84. package/lib/runtime/useAgentRuntime.js +1 -1
  85. package/lib/specs/agents/codeai/agents.d.ts +28 -0
  86. package/lib/specs/agents/codeai/agents.js +151 -0
  87. package/lib/specs/agents/codeai/index.d.ts +1 -0
  88. package/lib/specs/agents/codeai/index.js +5 -0
  89. package/lib/{config → specs/agents/codemode-paper}/agents.d.ts +4 -6
  90. package/lib/specs/agents/codemode-paper/agents.js +308 -0
  91. package/lib/specs/agents/codemode-paper/index.d.ts +1 -0
  92. package/lib/specs/agents/codemode-paper/index.js +5 -0
  93. package/lib/specs/agents/datalayer-ai/agents.d.ts +31 -0
  94. package/lib/{config → specs/agents/datalayer-ai}/agents.js +42 -184
  95. package/lib/specs/agents/datalayer-ai/index.d.ts +1 -0
  96. package/lib/specs/agents/datalayer-ai/index.js +5 -0
  97. package/lib/specs/agents/index.d.ts +21 -0
  98. package/lib/specs/agents/index.js +47 -0
  99. package/lib/specs/envvars.d.ts +29 -0
  100. package/lib/specs/envvars.js +125 -0
  101. package/lib/specs/index.d.ts +5 -0
  102. package/lib/specs/index.js +9 -0
  103. package/lib/{config → specs}/mcpServers.d.ts +2 -1
  104. package/lib/{config → specs}/mcpServers.js +47 -1
  105. package/lib/specs/models.d.ts +68 -0
  106. package/lib/specs/models.js +239 -0
  107. package/lib/{config → specs}/skills.d.ts +2 -0
  108. package/lib/{config → specs}/skills.js +6 -0
  109. package/lib/state/substates/AIAgentState.d.ts +0 -1
  110. package/lib/tools/adapters/agent-runtimes/AgentRuntimesToolAdapter.d.ts +11 -22
  111. package/lib/tools/adapters/agent-runtimes/AgentRuntimesToolAdapter.js +5 -5
  112. package/lib/tools/adapters/agent-runtimes/lexicalHooks.d.ts +6 -6
  113. package/lib/tools/adapters/agent-runtimes/lexicalHooks.js +4 -4
  114. package/lib/tools/adapters/agent-runtimes/notebookHooks.d.ts +6 -6
  115. package/lib/tools/adapters/agent-runtimes/notebookHooks.js +4 -4
  116. package/lib/{types.d.ts → types/Types.d.ts} +42 -8
  117. package/lib/types/index.d.ts +1 -0
  118. package/lib/types/index.js +1 -0
  119. package/package.json +11 -5
  120. package/scripts/codegen/generate_agents.py +608 -157
  121. package/scripts/codegen/generate_envvars.py +302 -0
  122. package/scripts/codegen/generate_mcp_servers.py +33 -21
  123. package/scripts/codegen/generate_models.py +486 -0
  124. package/scripts/codegen/generate_skills.py +21 -8
  125. package/style/primer-primitives.css +22 -0
  126. package/lib/components/chat/components/elements/ChatInputPrompt.d.ts +0 -37
  127. package/lib/components/chat/components/elements/ChatInputPrompt.js +0 -150
  128. /package/lib/{components → examples/components}/FooterMetrics.d.ts +0 -0
  129. /package/lib/{components → examples/components}/FooterMetrics.js +0 -0
  130. /package/lib/{components → examples/components}/Header.js +0 -0
  131. /package/lib/{components → examples/components}/HeaderControls.d.ts +0 -0
  132. /package/lib/{components → examples/components}/MockFileBrowser.d.ts +0 -0
  133. /package/lib/{components → examples/components}/MockFileBrowser.js +0 -0
  134. /package/lib/{components → examples/components}/SessionTabs.d.ts +0 -0
  135. /package/lib/{components → examples/components}/SessionTabs.js +0 -0
  136. /package/lib/{components → examples/components}/TimeTravel.d.ts +0 -0
  137. /package/lib/{components → examples/components}/TimeTravel.js +0 -0
  138. /package/lib/{types.js → types/Types.js} +0 -0
@@ -0,0 +1,192 @@
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
+ * AgentNotebook
8
+ *
9
+ * Standalone notebook + chat interface served at /static/agent-notebook.html.
10
+ * Connects to the agent-runtimes AG-UI endpoint and provides a Jupyter
11
+ * notebook alongside the Chat component with notebook tools registered.
12
+ *
13
+ * The page is opened by codeai with a URL like:
14
+ * http://127.0.0.1:<port>/static/agent-notebook.html?agentId=<id>
15
+ *
16
+ * Query parameters:
17
+ * - agentId: the agent identifier (required, set by codeai)
18
+ * - jupyterBaseUrl: base URL for the Jupyter server (optional, falls back to jupyter-config-data)
19
+ * - jupyterToken: token for the Jupyter server (optional, falls back to jupyter-config-data)
20
+ */
21
+ import { useEffect, useState } from 'react';
22
+ import { Text, Spinner } from '@primer/react';
23
+ import { AlertIcon } from '@primer/octicons-react';
24
+ import { Box, setupPrimerPortals } from '@datalayer/primer-addons';
25
+ import { DatalayerThemeProvider } from '@datalayer/core';
26
+ import { Notebook, JupyterReactTheme, loadJupyterConfig, createServerSettings, getJupyterServerUrl, getJupyterServerToken, setJupyterServerUrl, setJupyterServerToken, } from '@datalayer/jupyter-react';
27
+ import { ServiceManager } from '@jupyterlab/services';
28
+ import { Chat } from './components/chat';
29
+ import { useNotebookTools } from './tools/adapters/agent-runtimes/notebookHooks';
30
+ import { DEFAULT_MODEL } from './specs';
31
+ import MatplotlibNotebook from './examples/stores/notebooks/Matplotlib.ipynb.json';
32
+ import '../style/primer-primitives.css';
33
+ setupPrimerPortals();
34
+ const BASE_URL = window.location.origin;
35
+ const NOTEBOOK_ID = 'agent-notebook';
36
+ function getQueryParam(name) {
37
+ return new URLSearchParams(window.location.search).get(name);
38
+ }
39
+ function getAgentId() {
40
+ return getQueryParam('agentId') || 'default';
41
+ }
42
+ /**
43
+ * Initialise Jupyter configuration.
44
+ *
45
+ * Priority:
46
+ * 1. Query parameters (jupyterBaseUrl / jupyterToken)
47
+ * 2. <script id="jupyter-config-data"> block in the HTML page
48
+ */
49
+ function initJupyterConfig() {
50
+ // Load embedded config first
51
+ loadJupyterConfig();
52
+ // Override with query parameters when supplied by codeai
53
+ const qBaseUrl = getQueryParam('jupyterBaseUrl');
54
+ const qToken = getQueryParam('jupyterToken');
55
+ if (qBaseUrl)
56
+ setJupyterServerUrl(qBaseUrl);
57
+ if (qToken)
58
+ setJupyterServerToken(qToken);
59
+ // Also check for jupyter-config-data embedded in the page (may contain
60
+ // values injected at build/serve time)
61
+ const el = document.getElementById('jupyter-config-data');
62
+ if (el?.textContent) {
63
+ try {
64
+ const cfg = JSON.parse(el.textContent);
65
+ if (!qBaseUrl && cfg.baseUrl)
66
+ setJupyterServerUrl(cfg.baseUrl);
67
+ if (!qToken && cfg.token)
68
+ setJupyterServerToken(cfg.token);
69
+ }
70
+ catch {
71
+ // ignore
72
+ }
73
+ }
74
+ }
75
+ const NotebookPanel = ({ serviceManager }) => (_jsx(Box, { sx: {
76
+ flex: 1,
77
+ display: 'flex',
78
+ flexDirection: 'column',
79
+ overflow: 'hidden',
80
+ borderRight: '1px solid',
81
+ borderColor: 'border.default',
82
+ }, children: _jsx(JupyterReactTheme, { children: _jsx(Box, { sx: { height: '100vh' }, children: _jsx(Notebook, { nbformat: MatplotlibNotebook, id: NOTEBOOK_ID, serviceManager: serviceManager, height: "100vh", cellSidebarMargin: 120, startDefaultKernel: true }) }) }) }));
83
+ const ChatPanel = ({ agentId }) => {
84
+ // Register notebook tools so the agent can manipulate cells
85
+ const notebookTools = useNotebookTools(NOTEBOOK_ID);
86
+ return (_jsx(Box, { sx: {
87
+ width: '420px',
88
+ minWidth: '320px',
89
+ display: 'flex',
90
+ flexDirection: 'column',
91
+ overflow: 'hidden',
92
+ }, children: _jsx(Chat, { transport: "ag-ui", baseUrl: BASE_URL, agentId: agentId, title: "Agent Notebook", placeholder: "Ask about the notebook...", description: "Chat with the agent to manipulate the notebook", showHeader: true, height: "100vh", showModelSelector: true, showToolsMenu: true, showSkillsMenu: true, showTokenUsage: true, showInformation: true, frontendTools: notebookTools, autoFocus: true, runtimeId: agentId, historyEndpoint: `${BASE_URL}/api/v1/history`, suggestions: [
93
+ {
94
+ title: 'Add a cell',
95
+ message: 'Insert a new code cell into the notebook',
96
+ },
97
+ {
98
+ title: 'Run first cell',
99
+ message: 'Run the first cell in the notebook',
100
+ },
101
+ {
102
+ title: 'Show cells',
103
+ message: 'Show the notebook cells content and compute the number of cells',
104
+ },
105
+ ], submitOnSuggestionClick: true }) }));
106
+ };
107
+ // ─── Main component ─────────────────────────────────────────────────────────
108
+ export const AgentNotebook = () => {
109
+ const [agentId] = useState(getAgentId);
110
+ const [isReady, setIsReady] = useState(false);
111
+ const [error, setError] = useState(null);
112
+ const [serviceManager, setServiceManager] = useState(null);
113
+ // Verify the agent exists AND initialise the Jupyter service manager
114
+ useEffect(() => {
115
+ let cancelled = false;
116
+ const init = async () => {
117
+ try {
118
+ // 1. Ensure agent exists — create if missing
119
+ const getResp = await fetch(`${BASE_URL}/api/v1/agents/${encodeURIComponent(agentId)}`);
120
+ if (!getResp.ok) {
121
+ const createResp = await fetch(`${BASE_URL}/api/v1/agents`, {
122
+ method: 'POST',
123
+ headers: { 'Content-Type': 'application/json' },
124
+ body: JSON.stringify({
125
+ name: agentId,
126
+ description: 'Agent created by Agent Notebook page',
127
+ agent_library: 'pydantic-ai',
128
+ transport: 'ag-ui',
129
+ model: DEFAULT_MODEL,
130
+ system_prompt: 'You are a helpful AI assistant that helps users work with Jupyter notebooks. You can help with code, explanations, and data analysis.',
131
+ }),
132
+ });
133
+ if (!createResp.ok && createResp.status !== 400) {
134
+ const d = await createResp.json().catch(() => ({}));
135
+ throw new Error(d.detail || `Failed to create agent: ${createResp.status}`);
136
+ }
137
+ }
138
+ // 2. Initialise Jupyter
139
+ initJupyterConfig();
140
+ const serverSettings = createServerSettings(getJupyterServerUrl(), getJupyterServerToken());
141
+ const manager = new ServiceManager({ serverSettings });
142
+ await manager.ready;
143
+ if (!cancelled) {
144
+ setServiceManager(manager);
145
+ setIsReady(true);
146
+ }
147
+ }
148
+ catch (err) {
149
+ if (!cancelled) {
150
+ setError(err instanceof Error ? err.message : 'Failed to initialise');
151
+ }
152
+ }
153
+ };
154
+ init();
155
+ return () => {
156
+ cancelled = true;
157
+ };
158
+ }, [agentId]);
159
+ // Loading
160
+ if (!isReady && !error) {
161
+ return (_jsx(DatalayerThemeProvider, { children: _jsxs(Box, { sx: {
162
+ display: 'flex',
163
+ flexDirection: 'column',
164
+ alignItems: 'center',
165
+ justifyContent: 'center',
166
+ height: '100vh',
167
+ gap: 3,
168
+ bg: 'canvas.default',
169
+ }, children: [_jsx(Spinner, { size: "large" }), _jsxs(Text, { sx: { color: 'fg.muted' }, children: ["Connecting to agent ", agentId, "\u2026"] })] }) }));
170
+ }
171
+ // Error
172
+ if (error) {
173
+ return (_jsx(DatalayerThemeProvider, { children: _jsxs(Box, { sx: {
174
+ display: 'flex',
175
+ flexDirection: 'column',
176
+ alignItems: 'center',
177
+ justifyContent: 'center',
178
+ height: '100vh',
179
+ gap: 3,
180
+ bg: 'canvas.default',
181
+ }, children: [_jsx(AlertIcon, { size: 48 }), _jsx(Text, { sx: { color: 'danger.fg', fontSize: 2 }, children: "Failed to connect" }), _jsx(Text, { sx: { color: 'fg.muted', fontSize: 1 }, children: error })] }) }));
182
+ }
183
+ // Ready — notebook + chat side-by-side
184
+ return (_jsx(DatalayerThemeProvider, { children: _jsxs(Box, { sx: {
185
+ display: 'flex',
186
+ height: '100vh',
187
+ width: '100vw',
188
+ overflow: 'hidden',
189
+ bg: 'canvas.default',
190
+ }, children: [serviceManager && _jsx(NotebookPanel, { serviceManager: serviceManager }), _jsx(ChatPanel, { agentId: agentId })] }) }));
191
+ };
192
+ export default AgentNotebook;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,11 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /*
3
+ * Copyright (c) 2025-2026 Datalayer, Inc.
4
+ * Distributed under the terms of the Modified BSD License.
5
+ */
6
+ import { createRoot } from 'react-dom/client';
7
+ import { AgentLexical } from './AgentLexical';
8
+ const rootElement = document.getElementById('root');
9
+ if (rootElement) {
10
+ createRoot(rootElement).render(_jsx(AgentLexical, {}));
11
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,11 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /*
3
+ * Copyright (c) 2025-2026 Datalayer, Inc.
4
+ * Distributed under the terms of the Modified BSD License.
5
+ */
6
+ import { createRoot } from 'react-dom/client';
7
+ import { Agent } from './Agent';
8
+ const rootElement = document.getElementById('root');
9
+ if (rootElement) {
10
+ createRoot(rootElement).render(_jsx(Agent, {}));
11
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,12 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /*
3
+ * Copyright (c) 2025-2026 Datalayer, Inc.
4
+ * Distributed under the terms of the Modified BSD License.
5
+ */
6
+ import { createRoot } from 'react-dom/client';
7
+ // import { Agent as AgentNotebook } from './Agent';
8
+ import { AgentNotebook } from './AgentNotebook';
9
+ const rootElement = document.getElementById('root');
10
+ if (rootElement) {
11
+ createRoot(rootElement).render(_jsx(AgentNotebook, {}));
12
+ }
@@ -1,36 +1,48 @@
1
1
  import React from 'react';
2
- import type { Agent } from '../examples/stores/examplesStore';
3
- import type { Transport, Extension } from './chat';
2
+ import type { Agent } from '../types/Types';
3
+ import type { Transport } from './chat/components';
4
+ import type { Extension } from './chat/types';
4
5
  import type { McpServerSelection } from './McpServerManager';
5
6
  import type { OAuthProvider, Identity } from '../identity';
6
- import type { MCPServerTool as MCPServerToolType } from '../types';
7
+ import type { MCPServerTool as MCPServerToolType } from '../types/Types';
7
8
  /**
8
- * MCP Server Tool type (re-exported from types.ts)
9
+ * Agent spec entry from the library endpoint.
9
10
  */
10
- export type MCPServerTool = MCPServerToolType;
11
- export interface SkillOption {
11
+ export interface LibraryAgentSpec {
12
12
  id: string;
13
13
  name: string;
14
- description?: string;
14
+ description: string;
15
+ tags: string[];
16
+ enabled: boolean;
17
+ emoji?: string | null;
18
+ icon?: string | null;
19
+ color?: string | null;
20
+ skills: string[];
21
+ systemPrompt?: string | null;
22
+ systemPromptCodemodeAddons?: string | null;
23
+ suggestions: string[];
24
+ welcomeMessage?: string | null;
25
+ mcpServers: {
26
+ name: string;
27
+ id: string;
28
+ }[];
15
29
  }
16
30
  /**
17
- * MCP Server configuration from backend
31
+ * Helper: is the selected agent id a library spec?
32
+ */
33
+ export declare const isSpecSelection: (id: string) => boolean;
34
+ /**
35
+ * Helper: extract the spec id from a spec selection value.
18
36
  */
19
- export interface MCPServerConfig {
37
+ export declare const getSpecId: (id: string) => string;
38
+ /**
39
+ * MCP Server Tool type (re-exported from types.ts)
40
+ */
41
+ export type MCPServerTool = MCPServerToolType;
42
+ export interface SkillOption {
20
43
  id: string;
21
44
  name: string;
22
- url?: string;
23
- enabled: boolean;
24
- tools: MCPServerTool[];
25
- command?: string;
26
- args?: string[];
27
- isAvailable?: boolean;
28
- isRunning?: boolean;
29
- /** True if this server is from mcp.json config (vs catalog) */
30
- isConfig?: boolean;
31
- transport?: string;
32
- /** Required environment variables for this server */
33
- requiredEnvVars?: string[];
45
+ description?: string;
34
46
  }
35
47
  type AgentLibrary = 'pydantic-ai' | 'langchain' | 'jupyter-ai';
36
48
  export type { AgentLibrary };
@@ -8,8 +8,16 @@ import { Text, TextInput, Button, FormControl, Select, Checkbox, Spinner, Flash,
8
8
  import { ToolsIcon, KeyIcon, SyncIcon, PlusIcon, XIcon, LinkExternalIcon, } from '@primer/octicons-react';
9
9
  import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
10
10
  import { Box } from '@datalayer/primer-addons';
11
+ import { IdentityCard } from './chat/components';
11
12
  import { IdentityConnect, useIdentity } from '../identity';
12
- import { IdentityCard } from './chat';
13
+ /**
14
+ * Helper: is the selected agent id a library spec?
15
+ */
16
+ export const isSpecSelection = (id) => id.startsWith('spec:');
17
+ /**
18
+ * Helper: extract the spec id from a spec selection value.
19
+ */
20
+ export const getSpecId = (id) => id.replace(/^spec:/, '');
13
21
  /**
14
22
  * Token-based identity providers that can be connected via API key
15
23
  */
@@ -228,7 +236,33 @@ export const AgentConfiguration = ({ agentLibrary, transport, extensions, wsUrl,
228
236
  staleTime: 1000 * 60 * 1, // 1 minute (refresh more often for running status)
229
237
  retry: 1,
230
238
  });
231
- // Fetch skills from the backend (only when codemode is enabled)
239
+ // Fetch agent specs from library
240
+ const libraryQuery = useQuery({
241
+ queryKey: ['agent-library', baseUrl],
242
+ queryFn: async () => {
243
+ const response = await fetch(`${baseUrl}/api/v1/agents/library`);
244
+ if (!response.ok) {
245
+ throw new Error('Failed to fetch agent library');
246
+ }
247
+ return response.json();
248
+ },
249
+ enabled: !!baseUrl,
250
+ staleTime: 1000 * 60 * 5, // 5 minutes
251
+ retry: 1,
252
+ });
253
+ const librarySpecs = libraryQuery.data || [];
254
+ // The currently selected library spec (if any)
255
+ const selectedSpec = useMemo(() => {
256
+ if (!isSpecSelection(selectedAgentId))
257
+ return null;
258
+ const specId = getSpecId(selectedAgentId);
259
+ return librarySpecs.find(s => s.id === specId) || null;
260
+ }, [selectedAgentId, librarySpecs]);
261
+ // When a spec is selected, form behaves like new-agent but with pre-filled values
262
+ const isNewAgentMode = selectedAgentId === 'new-agent' || isSpecSelection(selectedAgentId);
263
+ // True when a library spec is selected (fields locked down except Name, URL, Library, Model, Transport, Extensions)
264
+ const isSpecMode = isSpecSelection(selectedAgentId);
265
+ // Fetch skills from the backend (always available, independent of codemode)
232
266
  const skillsQuery = useQuery({
233
267
  queryKey: ['agent-skills', baseUrl],
234
268
  queryFn: async () => {
@@ -238,7 +272,7 @@ export const AgentConfiguration = ({ agentLibrary, transport, extensions, wsUrl,
238
272
  }
239
273
  return response.json();
240
274
  },
241
- enabled: !!baseUrl && enableCodemode,
275
+ enabled: !!baseUrl,
242
276
  staleTime: 1000 * 60 * 5, // 5 minutes
243
277
  retry: 1,
244
278
  });
@@ -280,9 +314,9 @@ export const AgentConfiguration = ({ agentLibrary, transport, extensions, wsUrl,
280
314
  const configServers = mcpServersQuery.data || configQuery.data?.mcpServers || [];
281
315
  const catalogServers = catalogServersQuery.data || [];
282
316
  const models = configQuery.data?.models || [];
283
- // Use fetched skills when codemode is enabled, otherwise use passed availableSkills (which may be empty)
317
+ // Use fetched skills when available, otherwise use passed availableSkills (which may be empty)
284
318
  const fetchedSkills = skillsQuery.data?.skills || [];
285
- const displaySkills = enableCodemode ? fetchedSkills : availableSkills;
319
+ const displaySkills = fetchedSkills.length > 0 ? fetchedSkills : availableSkills;
286
320
  const skillsEnabled = selectedSkills.length > 0;
287
321
  const selectedConfigServers = selectedMcpServers
288
322
  .filter(s => s.origin === 'config')
@@ -348,11 +382,11 @@ export const AgentConfiguration = ({ agentLibrary, transport, extensions, wsUrl,
348
382
  onSelectedSkillsChange?.(selectedSkills.filter(id => id !== skillId));
349
383
  }
350
384
  };
351
- // MCP servers are disabled for existing agents (new-agent only)
352
- const mcpServersDisabled = selectedAgentId !== 'new-agent';
385
+ // MCP servers are disabled for existing agents and when a spec is selected
386
+ const mcpServersDisabled = !isNewAgentMode || isSpecMode;
353
387
  // Determine which extensions are enabled based on transport
354
388
  const isExtensionEnabled = (ext) => {
355
- if (selectedAgentId !== 'new-agent')
389
+ if (!isNewAgentMode)
356
390
  return false;
357
391
  if (transport === 'ag-ui')
358
392
  return true; // Both mcp-ui and a2ui enabled
@@ -380,55 +414,71 @@ export const AgentConfiguration = ({ agentLibrary, transport, extensions, wsUrl,
380
414
  fontWeight: 'bold',
381
415
  display: 'block',
382
416
  marginBottom: 3,
383
- }, children: "Create a new Agent" }), _jsxs(FormControl, { sx: { marginBottom: 3 }, children: [_jsx(FormControl.Label, { children: "Available Agents" }), _jsxs(Select, { value: selectedAgentId, onChange: e => onAgentSelect(e.target.value), sx: { width: '100%' }, children: [_jsx(Select.Option, { value: "new-agent", children: "+ New Agent..." }), agents.map(agent => (_jsxs(Select.Option, { value: agent.id, children: [agent.status === 'running' && '● ', agent.name] }, agent.id)))] }), _jsx(FormControl.Caption, { children: selectedAgentId === 'new-agent'
384
- ? 'Configure a new custom agent'
385
- : 'Selected agent - form fields below are disabled' })] }), _jsxs(FormControl, { sx: { marginBottom: 3 }, children: [_jsx(FormControl.Label, { children: "Agent Name" }), _jsx(TextInput, { value: agentName, onChange: e => onAgentNameChange(e.target.value), disabled: selectedAgentId !== 'new-agent', placeholder: "demo-agent", sx: { width: '100%' } }), _jsx(FormControl.Caption, { children: "The name of the agent to connect to" })] }), _jsxs(FormControl, { sx: { marginBottom: 3 }, children: [_jsx(FormControl.Label, { children: transport === 'acp' ? 'WebSocket URL' : 'Base URL' }), _jsx(TextInput, { value: transport === 'acp' ? wsUrl : baseUrl, onChange: e => transport === 'acp'
417
+ }, children: "Create a new Agent" }), _jsxs(FormControl, { sx: { marginBottom: 3 }, children: [_jsx(FormControl.Label, { children: "Available Agents" }), _jsxs(Select, { value: selectedAgentId, onChange: e => onAgentSelect(e.target.value), sx: { width: '100%' }, children: [_jsx(Select.Option, { value: "new-agent", children: "+ New Agent..." }), librarySpecs
418
+ .filter(s => s.enabled)
419
+ .map(spec => (_jsxs(Select.Option, { value: `spec:${spec.id}`, children: [spec.emoji ? `${spec.emoji} ` : '', spec.name] }, `spec:${spec.id}`))), agents.map(agent => (_jsxs(Select.Option, { value: agent.id, children: [agent.status === 'running' && ' ', agent.name] }, agent.id)))] }), _jsx(FormControl.Caption, { children: isNewAgentMode
420
+ ? selectedSpec
421
+ ? `Creating from spec: ${selectedSpec.name} — capabilities are locked`
422
+ : 'Configure a new custom agent'
423
+ : 'Selected agent - form fields below are disabled' })] }), _jsxs(FormControl, { sx: { marginBottom: 3 }, children: [_jsx(FormControl.Label, { children: "Agent Name" }), _jsx(TextInput, { value: agentName, onChange: e => onAgentNameChange(e.target.value), disabled: !isNewAgentMode, placeholder: "demo-agent", sx: { width: '100%' } }), _jsx(FormControl.Caption, { children: "The name of the agent to connect to" })] }), _jsxs(FormControl, { sx: { marginBottom: 3 }, children: [_jsx(FormControl.Label, { children: transport === 'acp' ? 'WebSocket URL' : 'Base URL' }), _jsx(TextInput, { value: transport === 'acp' ? wsUrl : baseUrl, onChange: e => transport === 'acp'
386
424
  ? onWsUrlChange(e.target.value)
387
- : onBaseUrlChange(e.target.value), disabled: selectedAgentId !== 'new-agent', placeholder: transport === 'acp'
425
+ : onBaseUrlChange(e.target.value), disabled: !isNewAgentMode, placeholder: transport === 'acp'
388
426
  ? 'ws://localhost:8000/api/v1/acp/ws'
389
427
  : 'http://localhost:8000', sx: { width: '100%' } }), _jsx(FormControl.Caption, { children: transport === 'acp'
390
428
  ? 'The WebSocket endpoint of your agent-runtimes server'
391
- : 'The base URL of your agent-runtimes server' })] }), _jsxs(Box, { sx: { display: 'flex', gap: 3, marginBottom: 3 }, children: [_jsxs(FormControl, { sx: { flex: 1 }, children: [_jsx(FormControl.Label, { children: "Agent Library" }), _jsx(Select, { value: agentLibrary, onChange: e => onAgentLibraryChange(e.target.value), disabled: selectedAgentId !== 'new-agent', sx: { width: '100%' }, children: AGENT_LIBRARIES.map(lib => (_jsxs(Select.Option, { value: lib.value, disabled: lib.disabled, children: [lib.label, lib.disabled && ' (Coming Soon)'] }, lib.value))) })] }), _jsxs(FormControl, { sx: { flex: 1 }, children: [_jsx(FormControl.Label, { children: "Model" }), _jsx(Select, { value: model, onChange: e => onModelChange(e.target.value), disabled: selectedAgentId !== 'new-agent' || models.length === 0, sx: { width: '100%' }, children: models.length === 0 ? (_jsx(Select.Option, { value: "", children: "Loading models..." })) : (models.map(m => (_jsxs(Select.Option, { value: m.id, disabled: !m.isAvailable, children: [m.name, !m.isAvailable && ' (API key required)'] }, m.id)))) })] }), _jsxs(FormControl, { sx: { flex: 1 }, children: [_jsx(FormControl.Label, { children: "Transport" }), _jsx(Select, { value: transport, onChange: e => onTransportChange(e.target.value), disabled: selectedAgentId !== 'new-agent', sx: { width: '100%' }, children: TRANSPORTS.map(t => (_jsx(Select.Option, { value: t.value, children: t.label }, t.value))) })] }), _jsxs(FormControl, { sx: { flex: 1 }, children: [_jsx(FormControl.Label, { children: "Extensions" }), _jsx(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 2 }, children: EXTENSIONS.map(ext => (_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(Checkbox, { value: ext.value, checked: extensions.includes(ext.value), disabled: !isExtensionEnabled(ext.value), onChange: e => handleExtensionChange(ext.value, e.target.checked) }), _jsx(Text, { children: ext.label })] }, ext.value))) })] })] }), _jsxs(Box, { sx: {
429
+ : 'The base URL of your agent-runtimes server' })] }), _jsxs(Box, { sx: { display: 'flex', gap: 3, marginBottom: 3 }, children: [_jsxs(FormControl, { sx: { flex: 1 }, children: [_jsx(FormControl.Label, { children: "Agent Library" }), _jsx(Select, { value: agentLibrary, onChange: e => onAgentLibraryChange(e.target.value), disabled: !isNewAgentMode, sx: { width: '100%' }, children: AGENT_LIBRARIES.map(lib => (_jsxs(Select.Option, { value: lib.value, disabled: lib.disabled, children: [lib.label, lib.disabled && ' (Coming Soon)'] }, lib.value))) })] }), _jsxs(FormControl, { sx: { flex: 1 }, children: [_jsx(FormControl.Label, { children: "Model" }), _jsx(Select, { value: model, onChange: e => onModelChange(e.target.value), disabled: !isNewAgentMode || models.length === 0, sx: { width: '100%' }, children: models.length === 0 ? (_jsx(Select.Option, { value: "", children: "Loading models..." })) : (models.map(m => (_jsxs(Select.Option, { value: m.id, disabled: !m.isAvailable, children: [m.name, !m.isAvailable && ' (API key required)'] }, m.id)))) })] }), _jsxs(FormControl, { sx: { flex: 1 }, children: [_jsx(FormControl.Label, { children: "Transport" }), _jsx(Select, { value: transport, onChange: e => onTransportChange(e.target.value), disabled: !isNewAgentMode, sx: { width: '100%' }, children: TRANSPORTS.map(t => (_jsx(Select.Option, { value: t.value, children: t.label }, t.value))) })] }), _jsxs(FormControl, { sx: { flex: 1 }, children: [_jsx(FormControl.Label, { children: "Extensions" }), _jsx(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 2 }, children: EXTENSIONS.map(ext => (_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(Checkbox, { value: ext.value, checked: extensions.includes(ext.value), disabled: !isExtensionEnabled(ext.value), onChange: e => handleExtensionChange(ext.value, e.target.checked) }), _jsx(Text, { children: ext.label })] }, ext.value))) })] })] }), _jsxs(Box, { sx: {
392
430
  marginBottom: 3,
393
431
  padding: 3,
394
432
  border: '1px solid',
395
433
  borderColor: 'border.default',
396
434
  borderRadius: 2,
397
435
  backgroundColor: 'canvas.default',
436
+ opacity: isSpecMode ? 0.6 : 1,
398
437
  }, children: [_jsxs(Box, { sx: {
399
438
  display: 'flex',
400
439
  alignItems: 'center',
401
440
  gap: 2,
402
441
  marginBottom: 2,
403
- }, children: [_jsx(KeyIcon, { size: 16 }), _jsx(Text, { sx: { fontSize: 1, fontWeight: 'bold' }, children: "Connected Accounts" })] }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted', display: 'block', mb: 3 }, children: "Connect your accounts to give the agent access to external services like GitHub repositories, Google services, or Kaggle datasets." }), _jsx(IdentityConnectWithStatus, { identityProviders: identityProviders, disabled: selectedAgentId !== 'new-agent', onConnect: onIdentityConnect, onDisconnect: onIdentityDisconnect })] }), _jsxs(Box, { sx: {
442
+ }, children: [_jsx(KeyIcon, { size: 16 }), _jsx(Text, { sx: { fontSize: 1, fontWeight: 'bold' }, children: "Connected Accounts" })] }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted', display: 'block', mb: 3 }, children: "Connect your accounts to give the agent access to external services like GitHub repositories, Google services, or Kaggle datasets." }), _jsx(IdentityConnectWithStatus, { identityProviders: identityProviders, disabled: !isNewAgentMode || isSpecMode, onConnect: onIdentityConnect, onDisconnect: onIdentityDisconnect })] }), _jsxs(Box, { sx: {
404
443
  marginBottom: 3,
405
444
  padding: 3,
406
445
  border: '1px solid',
407
446
  borderColor: 'border.default',
408
447
  borderRadius: 2,
409
448
  backgroundColor: 'canvas.default',
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: {
449
+ opacity: isSpecMode ? 0.6 : 1,
450
+ }, children: [_jsxs(Text, { sx: { fontSize: 1, fontWeight: 'bold', display: 'block', mb: 2 }, children: ["Agent Capabilities", isSpecMode && (_jsx(Text, { as: "span", sx: {
451
+ fontSize: 0,
452
+ color: 'fg.muted',
453
+ fontWeight: 'normal',
454
+ ml: 2,
455
+ }, children: "\u2014 defined by spec" }))] }), _jsx(Box, { sx: { display: 'flex', gap: 4, opacity: isSpecMode ? 0.6 : 1 }, children: _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(Checkbox, { checked: enableCodemode, disabled: !isNewAgentMode || isSpecMode, 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." }) })), skillsEnabled && !enableCodemode && (_jsx(Flash, { variant: "default", sx: { mt: 3 }, children: _jsx(Text, { sx: { fontSize: 0 }, children: "Skills will run with a standalone code sandbox for script execution. Enable Codemode to compose skills with other tools." }) })), 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: !isNewAgentMode || isSpecMode, 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: !isNewAgentMode || isSpecMode, 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: !isNewAgentMode || isSpecMode, 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: {
411
456
  marginBottom: 3,
412
457
  padding: 3,
413
458
  border: '1px solid',
414
459
  borderColor: 'border.default',
415
460
  borderRadius: 2,
416
461
  backgroundColor: 'canvas.default',
417
- opacity: enableCodemode ? 1 : 0.5,
462
+ opacity: isSpecMode ? 0.6 : 1,
418
463
  }, children: [_jsxs(Box, { sx: {
419
464
  display: 'flex',
420
465
  alignItems: 'center',
421
466
  gap: 2,
422
467
  marginBottom: 2,
423
- }, children: [_jsx(Text, { sx: { fontSize: 1, fontWeight: 'bold' }, children: "Skills" }), skillsQuery.isLoading && _jsx(Spinner, { size: "small" }), enableCodemode && !skillsQuery.isLoading && (_jsx(Button, { variant: "invisible", size: "small", onClick: () => skillsQuery.refetch(), sx: { padding: 1 }, "aria-label": "Refresh skills", children: _jsx(SyncIcon, { size: 14 }) }))] }), !enableCodemode ? (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Enable Codemode to use skills." })) : skillsQuery.isError ? (_jsx(Flash, { variant: "warning", sx: { marginBottom: 2 }, children: _jsx(Text, { sx: { fontSize: 0 }, children: "Unable to fetch skills. Check that the server is running." }) })) : displaySkills.length === 0 && !skillsQuery.isLoading ? (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "No skills available." })) : (_jsx(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 2 }, children: displaySkills.map(skill => (_jsxs(Box, { sx: {
468
+ }, children: [_jsxs(Text, { sx: { fontSize: 1, fontWeight: 'bold' }, children: ["Skills", isSpecMode && (_jsx(Text, { as: "span", sx: {
469
+ fontSize: 0,
470
+ color: 'fg.muted',
471
+ fontWeight: 'normal',
472
+ ml: 2,
473
+ }, children: "\u2014 defined by spec" }))] }), skillsQuery.isLoading && _jsx(Spinner, { size: "small" }), !skillsQuery.isLoading && (_jsx(Button, { variant: "invisible", size: "small", onClick: () => skillsQuery.refetch(), sx: { padding: 1 }, "aria-label": "Refresh skills", children: _jsx(SyncIcon, { size: 14 }) }))] }), skillsQuery.isError ? (_jsx(Flash, { variant: "warning", sx: { marginBottom: 2 }, children: _jsx(Text, { sx: { fontSize: 0 }, children: "Unable to fetch skills. Check that the server is running." }) })) : displaySkills.length === 0 && !skillsQuery.isLoading ? (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "No skills available." })) : (_jsx(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 2 }, children: displaySkills.map(skill => (_jsxs(Box, { sx: {
424
474
  display: 'flex',
425
475
  alignItems: 'center',
426
476
  gap: 2,
427
477
  padding: 2,
428
478
  borderRadius: 1,
429
479
  backgroundColor: 'canvas.subtle',
430
- opacity: selectedAgentId !== 'new-agent' ? 0.6 : 1,
431
- }, children: [_jsx(Checkbox, { checked: selectedSkills.includes(skill.id), disabled: selectedAgentId !== 'new-agent', onChange: e => handleSkillChange(skill.id, e.target.checked) }), _jsxs(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 1 }, children: [_jsx(Text, { sx: { fontWeight: 'semibold' }, children: skill.name }), skill.description && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: skill.description }))] })] }, skill.id))) }))] }), _jsxs(Box, { sx: {
480
+ opacity: !isNewAgentMode || isSpecMode ? 0.6 : 1,
481
+ }, children: [_jsx(Checkbox, { checked: selectedSkills.includes(skill.id), disabled: !isNewAgentMode || isSpecMode, onChange: e => handleSkillChange(skill.id, e.target.checked) }), _jsxs(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 1 }, children: [_jsx(Text, { sx: { fontWeight: 'semibold' }, children: skill.name }), skill.description && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: skill.description }))] })] }, skill.id))) }))] }), _jsxs(Box, { sx: {
432
482
  marginBottom: 3,
433
483
  padding: 3,
434
484
  border: '1px solid',
@@ -440,7 +490,12 @@ export const AgentConfiguration = ({ agentLibrary, transport, extensions, wsUrl,
440
490
  alignItems: 'center',
441
491
  gap: 2,
442
492
  marginBottom: 2,
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 &&
493
+ }, children: [_jsx(ToolsIcon, { size: 16 }), _jsxs(Text, { sx: { fontSize: 1, fontWeight: 'bold' }, children: ["MCP Config Servers", isSpecMode && (_jsx(Text, { as: "span", sx: {
494
+ fontSize: 0,
495
+ color: 'fg.muted',
496
+ fontWeight: 'normal',
497
+ ml: 2,
498
+ }, children: "\u2014 defined by spec" }))] }), 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
499
  !mcpServersQuery.isLoading &&
445
500
  !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: {
446
501
  marginBottom: 2,
@@ -525,6 +580,6 @@ export const AgentConfiguration = ({ agentLibrary, transport, extensions, wsUrl,
525
580
  alignItems: 'center',
526
581
  justifyContent: 'center',
527
582
  gap: 2,
528
- }, children: [_jsx(Spinner, { size: "small" }), _jsx("span", { children: "Creating Agent..." })] })) : selectedAgentId === 'new-agent' ? ('Create the Agent') : agents.find(a => a.id === selectedAgentId)?.status === 'running' ? ('Connect to the Agent') : ('Start and Connect to the Agent') })] }));
583
+ }, children: [_jsx(Spinner, { size: "small" }), _jsx("span", { children: "Creating Agent..." })] })) : isNewAgentMode ? (selectedSpec ? (`Create from "${selectedSpec.name}"`) : ('Create the Agent')) : agents.find(a => a.id === selectedAgentId)?.status === 'running' ? ('Connect to the Agent') : ('Start and Connect to the Agent') })] }));
529
584
  };
530
585
  export { AGENT_LIBRARIES, TRANSPORTS, EXTENSIONS };
@@ -26,9 +26,11 @@ export interface AgentDetailsProps {
26
26
  onIdentityDisconnect?: (provider: OAuthProvider) => void;
27
27
  /** Callback to go back to chat view */
28
28
  onBack: () => void;
29
+ /** Whether to show the header with back button (default: true) */
30
+ showBackHeader?: boolean;
29
31
  }
30
32
  /**
31
33
  * AgentDetails component displays comprehensive information about the agent.
32
34
  */
33
- export declare function AgentDetails({ name, protocol, url, messageCount, agentId, apiBase, identityProviders, onIdentityConnect, onIdentityDisconnect, onBack, }: AgentDetailsProps): import("react/jsx-runtime").JSX.Element;
35
+ export declare function AgentDetails({ name, protocol, url, messageCount, agentId, apiBase, identityProviders, onIdentityConnect, onIdentityDisconnect, onBack, showBackHeader, }: AgentDetailsProps): import("react/jsx-runtime").JSX.Element;
34
36
  export default AgentDetails;