@datalayer/agent-runtimes 1.0.5 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/README.md +157 -10
  2. package/lib/AgentNode.d.ts +3 -0
  3. package/lib/AgentNode.js +676 -0
  4. package/lib/agent-node/themeStore.d.ts +3 -0
  5. package/lib/agent-node/themeStore.js +156 -0
  6. package/lib/agent-node-main.d.ts +1 -0
  7. package/lib/agent-node-main.js +14 -0
  8. package/lib/chat/Chat.js +16 -10
  9. package/lib/chat/ChatFloating.js +1 -1
  10. package/lib/chat/ChatSidebar.js +81 -49
  11. package/lib/chat/base/ChatBase.js +388 -74
  12. package/lib/chat/display/FloatingBrandButton.js +8 -1
  13. package/lib/chat/header/ChatHeader.d.ts +3 -1
  14. package/lib/chat/header/ChatHeader.js +15 -12
  15. package/lib/chat/header/ChatHeaderBase.d.ts +29 -9
  16. package/lib/chat/header/ChatHeaderBase.js +26 -3
  17. package/lib/chat/indicators/SandboxStatusIndicator.js +82 -47
  18. package/lib/chat/messages/ChatMessageList.js +46 -1
  19. package/lib/chat/messages/ChatMessages.js +6 -2
  20. package/lib/chat/prompt/InputFooter.d.ts +3 -1
  21. package/lib/chat/prompt/InputFooter.js +8 -5
  22. package/lib/chat/prompt/InputPrompt.d.ts +3 -1
  23. package/lib/chat/prompt/InputPrompt.js +2 -2
  24. package/lib/chat/prompt/InputPromptFooter.d.ts +3 -1
  25. package/lib/chat/prompt/InputPromptFooter.js +3 -3
  26. package/lib/client/AgentsMixin.js +14 -0
  27. package/lib/config/AgentConfiguration.d.ts +22 -0
  28. package/lib/config/AgentConfiguration.js +319 -64
  29. package/lib/examples/AgUiSharedStateExample.js +2 -1
  30. package/lib/examples/AgentCheckpointsExample.js +3 -3
  31. package/lib/examples/AgentCodemodeExample.d.ts +3 -3
  32. package/lib/examples/AgentCodemodeExample.js +24 -12
  33. package/lib/examples/AgentEvalsExample.js +330 -40
  34. package/lib/examples/AgentGuardrailsExample.js +16 -5
  35. package/lib/examples/AgentHooksExample.js +27 -9
  36. package/lib/examples/AgentInferenceProviderExample.d.ts +3 -0
  37. package/lib/examples/AgentInferenceProviderExample.js +329 -0
  38. package/lib/examples/AgentMCPExample.js +6 -5
  39. package/lib/examples/AgentMemoryExample.d.ts +1 -2
  40. package/lib/examples/AgentMemoryExample.js +71 -22
  41. package/lib/examples/AgentMonitoringExample.js +5 -5
  42. package/lib/examples/AgentNotificationsExample.d.ts +1 -2
  43. package/lib/examples/AgentNotificationsExample.js +71 -22
  44. package/lib/examples/AgentOtelExample.js +31 -40
  45. package/lib/examples/AgentOutputsExample.d.ts +1 -1
  46. package/lib/examples/AgentOutputsExample.js +67 -16
  47. package/lib/examples/AgentParametersExample.js +10 -8
  48. package/lib/examples/AgentSandboxExample.d.ts +1 -1
  49. package/lib/examples/AgentSandboxExample.js +7 -6
  50. package/lib/examples/AgentSkillsExample.js +6 -6
  51. package/lib/examples/AgentSubagentsExample.d.ts +1 -1
  52. package/lib/examples/AgentSubagentsExample.js +6 -6
  53. package/lib/examples/AgentToolApprovalsExample.js +27 -11
  54. package/lib/examples/AgentTriggersExample.js +5 -5
  55. package/lib/examples/{AgentSpecsExample.d.ts → AgentspecsExample.d.ts} +2 -2
  56. package/lib/examples/AgentspecsExample.js +1096 -0
  57. package/lib/examples/ChatCustomExample.js +6 -5
  58. package/lib/examples/ChatExample.js +6 -5
  59. package/lib/examples/Lexical2Example.js +1 -1
  60. package/lib/examples/LexicalAgentExample.js +1 -1
  61. package/lib/examples/NotebookAgentExample.js +3 -3
  62. package/lib/examples/components/ExampleWrapper.d.ts +6 -7
  63. package/lib/examples/components/ExampleWrapper.js +27 -10
  64. package/lib/examples/example-selector.js +2 -1
  65. package/lib/examples/index.d.ts +2 -1
  66. package/lib/examples/index.js +2 -1
  67. package/lib/examples/lexical/initial-content.json +6 -6
  68. package/lib/examples/main.js +56 -16
  69. package/lib/examples/utils/agentId.d.ts +1 -1
  70. package/lib/examples/utils/agentId.js +1 -1
  71. package/lib/examples/utils/useExampleAgentRuntimesUrl.d.ts +5 -0
  72. package/lib/examples/utils/useExampleAgentRuntimesUrl.js +19 -0
  73. package/lib/hooks/useAIAgentsWebSocket.js +35 -0
  74. package/lib/hooks/useAgentRuntimes.d.ts +32 -3
  75. package/lib/hooks/useAgentRuntimes.js +114 -19
  76. package/lib/index.d.ts +1 -1
  77. package/lib/specs/agents/agents.d.ts +20 -13
  78. package/lib/specs/agents/agents.js +1267 -581
  79. package/lib/specs/benchmarks.d.ts +20 -0
  80. package/lib/specs/benchmarks.js +205 -0
  81. package/lib/specs/envvars.d.ts +0 -1
  82. package/lib/specs/envvars.js +0 -11
  83. package/lib/specs/evals.d.ts +10 -9
  84. package/lib/specs/evals.js +128 -88
  85. package/lib/specs/index.d.ts +0 -1
  86. package/lib/specs/index.js +0 -1
  87. package/lib/specs/models.d.ts +0 -2
  88. package/lib/specs/models.js +0 -15
  89. package/lib/specs/skills.d.ts +0 -1
  90. package/lib/specs/skills.js +0 -18
  91. package/lib/stores/agentRuntimeStore.d.ts +5 -1
  92. package/lib/stores/agentRuntimeStore.js +22 -8
  93. package/lib/stores/conversationStore.js +2 -2
  94. package/lib/types/agents-lifecycle.d.ts +18 -0
  95. package/lib/types/agents.d.ts +6 -0
  96. package/lib/types/agentspecs.d.ts +4 -0
  97. package/lib/types/benchmarks.d.ts +43 -0
  98. package/lib/types/benchmarks.js +5 -0
  99. package/lib/types/chat.d.ts +16 -0
  100. package/lib/types/evals.d.ts +26 -17
  101. package/lib/types/index.d.ts +1 -0
  102. package/lib/types/index.js +1 -0
  103. package/package.json +9 -5
  104. package/scripts/codegen/__pycache__/generate_agents.cpython-313.pyc +0 -0
  105. package/scripts/codegen/__pycache__/generate_benchmarks.cpython-313.pyc +0 -0
  106. package/scripts/codegen/__pycache__/generate_evals.cpython-313.pyc +0 -0
  107. package/scripts/codegen/generate_agents.py +89 -43
  108. package/scripts/codegen/generate_benchmarks.py +441 -0
  109. package/scripts/codegen/generate_evals.py +94 -16
  110. package/scripts/codegen/generate_events.py +0 -1
  111. package/lib/examples/AgentSpecsExample.js +0 -694
@@ -34,8 +34,8 @@ import { useCoreStore } from '@datalayer/core/lib/state';
34
34
  const queryClient = new QueryClient();
35
35
  import { useSimpleAuthStore } from '@datalayer/core/lib/views/otel';
36
36
  import { Chat } from '../chat';
37
- const AGENT_NAME = 'monitoring-demo-agent';
38
- const AGENT_SPEC_ID = 'demo-monitoring';
37
+ const AGENT_NAME = 'monitoring-example-agent';
38
+ const AGENT_SPEC_ID = 'example-monitoring';
39
39
  const DEFAULT_LOCAL_BASE_URL = import.meta.env.VITE_BASE_URL || 'http://localhost:8765';
40
40
  const OTEL_BASE_URL_ENV = import.meta.env.VITE_OTEL_BASE_URL;
41
41
  const DATALAYER_RUN_URL_ENV = import.meta.env.DATALAYER_RUN_URL;
@@ -87,7 +87,7 @@ const AgentMonitoringInner = ({ onLogout, }) => {
87
87
  method: 'POST',
88
88
  body: JSON.stringify({
89
89
  name: agentName,
90
- description: 'MCP monitoring demo – web crawling via Tavily with live cost/token metrics',
90
+ description: 'MCP monitoring example – web crawling via Tavily with live cost/token metrics',
91
91
  agent_library: 'pydantic-ai',
92
92
  transport: 'vercel-ai',
93
93
  agent_spec_id: AGENT_SPEC_ID,
@@ -215,7 +215,7 @@ const AgentMonitoringInner = ({ onLogout, }) => {
215
215
  justifyContent: 'center',
216
216
  height: '100vh',
217
217
  gap: 3,
218
- }, children: [_jsx(Spinner, { size: "large" }), _jsx(Text, { sx: { color: 'fg.muted' }, children: "Launching local monitoring demo agent..." })] }));
218
+ }, children: [_jsx(Spinner, { size: "large" }), _jsx(Text, { sx: { color: 'fg.muted' }, children: "Launching local monitoring example agent..." })] }));
219
219
  }
220
220
  if (runtimeStatus === 'error' || hookError) {
221
221
  return _jsx(ErrorView, { error: hookError, onLogout: onLogout });
@@ -267,7 +267,7 @@ const AgentMonitoringInner = ({ onLogout, }) => {
267
267
  fontSize: 0,
268
268
  mt: 1,
269
269
  display: 'block',
270
- }, children: ["Last close: ", monitorSocket.lastClose.detail] }))] }))] })] }), _jsx(Box, { sx: { flex: 1, minWidth: 0 }, children: _jsx(Chat, { protocol: "vercel-ai", baseUrl: agentBaseUrl, agentId: agentId, authToken: chatAuthToken, title: "Monitoring Agent", placeholder: "Ask for cost, token usage, and turn-level monitoring insights...", description: `${alerts.length} active alert${alerts.length !== 1 ? 's' : ''}`, showHeader: true, showTokenUsage: true, showToolsMenu: true, showSkillsMenu: true, autoFocus: true, height: "100%", runtimeId: agentId, historyEndpoint: `${agentBaseUrl}/api/v1/history`, suggestions: [
270
+ }, children: ["Last close: ", monitorSocket.lastClose.detail] }))] }))] })] }), _jsx(Box, { sx: { flex: 1, minWidth: 0 }, children: _jsx(Chat, { protocol: "vercel-ai", baseUrl: agentBaseUrl, agentId: agentId, authToken: chatAuthToken, title: "Monitoring Agent", brandIcon: _jsx(GraphIcon, { size: 16 }), placeholder: "Ask for cost, token usage, and turn-level monitoring insights...", description: `${alerts.length} active alert${alerts.length !== 1 ? 's' : ''}`, showHeader: true, showTokenUsage: true, showToolsMenu: true, showSkillsMenu: true, autoFocus: true, height: "100%", runtimeId: agentId, historyEndpoint: `${agentBaseUrl}/api/v1/history`, suggestions: [
271
271
  {
272
272
  title: '▶ No-tool turn',
273
273
  message: 'Briefly introduce yourself without calling any tool or skill — produces a linear Start → Model → Decision → End graph.',
@@ -4,8 +4,7 @@
4
4
  * Demonstrates notification channels for agents: in-app toasts, email digests,
5
5
  * Slack webhook integrations, and notification preference management.
6
6
  *
7
- * - Creates a cloud agent runtime (environment: 'ai-agents-env') via the Datalayer
8
- * Runtimes API and deploys an agent on its sidecar
7
+ * - Creates a local agent-runtimes agent using the `example-notifications` spec
9
8
  * - Shows a notification center alongside the chat where users can configure
10
9
  * channels and review recent notifications
11
10
  */
@@ -9,8 +9,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
9
9
  * Demonstrates notification channels for agents: in-app toasts, email digests,
10
10
  * Slack webhook integrations, and notification preference management.
11
11
  *
12
- * - Creates a cloud agent runtime (environment: 'ai-agents-env') via the Datalayer
13
- * Runtimes API and deploys an agent on its sidecar
12
+ * - Creates a local agent-runtimes agent using the `example-notifications` spec
14
13
  * - Shows a notification center alongside the chat where users can configure
15
14
  * channels and review recent notifications
16
15
  */
@@ -23,13 +22,13 @@ import { Box } from '@datalayer/primer-addons';
23
22
  import { AuthRequiredView, ErrorView } from './components';
24
23
  import { ThemedProvider } from './utils/themedProvider';
25
24
  import { uniqueAgentId } from './utils/agentId';
25
+ import { useExampleAgentRuntimesUrl } from './utils/useExampleAgentRuntimesUrl';
26
26
  import { useSimpleAuthStore } from '@datalayer/core/lib/views/otel';
27
27
  import { Chat } from '../chat';
28
- import { useAgentRuntimes } from '../hooks/useAgentRuntimes';
29
28
  const queryClient = new QueryClient();
30
29
  // ─── Constants ─────────────────────────────────────────────────────────────
31
- const AGENT_NAME = 'notification-demo-agent';
32
- const AGENT_SPEC_ID = 'monitor-sales-kpis';
30
+ const AGENT_NAME = 'notification-example-agent';
31
+ const AGENT_SPEC_ID = 'example-notifications';
33
32
  const alertVariant = (severity) => {
34
33
  if (severity === 'critical')
35
34
  return 'danger';
@@ -41,16 +40,11 @@ const alertVariant = (severity) => {
41
40
  const AgentNotificationsInner = ({ onLogout, }) => {
42
41
  const { token } = useSimpleAuthStore();
43
42
  const agentName = useRef(uniqueAgentId(AGENT_NAME)).current;
44
- const { runtime, status: runtimeStatus, isReady, error: hookError, } = useAgentRuntimes({
45
- agentSpecId: AGENT_SPEC_ID,
46
- autoStart: true,
47
- agentConfig: {
48
- name: agentName,
49
- model: 'bedrock:us.anthropic.claude-3-5-haiku-20241022-v1:0',
50
- protocol: 'vercel-ai',
51
- description: 'Agent with multi-channel notification support',
52
- },
53
- });
43
+ const agentBaseUrl = useExampleAgentRuntimesUrl();
44
+ const [runtimeStatus, setRuntimeStatus] = useState('launching');
45
+ const [isReady, setIsReady] = useState(false);
46
+ const [hookError, setHookError] = useState(null);
47
+ const [agentId, setAgentId] = useState(agentName);
54
48
  const [notifications, setNotifications] = useState([]);
55
49
  const [channels, setChannels] = useState([
56
50
  { channel: 'in-app', enabled: true },
@@ -60,9 +54,7 @@ const AgentNotificationsInner = ({ onLogout, }) => {
60
54
  const [editTargets, setEditTargets] = useState({});
61
55
  const [isSaving, setIsSaving] = useState(false);
62
56
  const [flash, setFlash] = useState(null);
63
- const agentBaseUrl = runtime?.agentBaseUrl || '';
64
- const agentId = runtime?.agentId || AGENT_NAME;
65
- const podName = runtime?.podName || '(launching…)';
57
+ const podName = isReady ? `local:${agentId}` : '(launching…)';
66
58
  // Authenticated fetch helper
67
59
  const authFetch = useCallback((url, opts = {}) => fetch(url, {
68
60
  ...opts,
@@ -72,6 +64,65 @@ const AgentNotificationsInner = ({ onLogout, }) => {
72
64
  ...(opts.headers ?? {}),
73
65
  },
74
66
  }), [token]);
67
+ useEffect(() => {
68
+ let isCancelled = false;
69
+ const createLocalAgent = async () => {
70
+ setRuntimeStatus('launching');
71
+ setIsReady(false);
72
+ setHookError(null);
73
+ try {
74
+ const response = await authFetch(`${agentBaseUrl}/api/v1/agents`, {
75
+ method: 'POST',
76
+ body: JSON.stringify({
77
+ name: agentName,
78
+ description: 'Agent with multi-channel notification support',
79
+ agent_library: 'pydantic-ai',
80
+ transport: 'vercel-ai',
81
+ agent_spec_id: AGENT_SPEC_ID,
82
+ enable_skills: true,
83
+ tools: [],
84
+ }),
85
+ });
86
+ let resolvedAgentId = agentName;
87
+ if (response.ok) {
88
+ const data = await response.json();
89
+ resolvedAgentId = data?.id || agentName;
90
+ }
91
+ else {
92
+ const contentType = response.headers.get('content-type') || '';
93
+ let detail = '';
94
+ if (contentType.includes('application/json')) {
95
+ const data = await response.json().catch(() => null);
96
+ detail =
97
+ (typeof data?.detail === 'string' && data.detail) ||
98
+ (typeof data?.message === 'string' && data.message) ||
99
+ '';
100
+ }
101
+ else {
102
+ detail = await response.text();
103
+ }
104
+ if (!(response.status === 409 || /already exists/i.test(detail))) {
105
+ throw new Error(detail || `Failed to create local agent: ${response.status}`);
106
+ }
107
+ }
108
+ if (!isCancelled) {
109
+ setAgentId(resolvedAgentId);
110
+ setIsReady(true);
111
+ setRuntimeStatus('ready');
112
+ }
113
+ }
114
+ catch (error) {
115
+ if (!isCancelled) {
116
+ setHookError(error instanceof Error ? error.message : 'Agent failed to start');
117
+ setRuntimeStatus('error');
118
+ }
119
+ }
120
+ };
121
+ void createLocalAgent();
122
+ return () => {
123
+ isCancelled = true;
124
+ };
125
+ }, [agentBaseUrl, agentName, authFetch]);
75
126
  // ── Poll notifications ────────────────────────────────────────────────
76
127
  useEffect(() => {
77
128
  if (!isReady || !agentBaseUrl)
@@ -164,9 +215,7 @@ const AgentNotificationsInner = ({ onLogout, }) => {
164
215
  justifyContent: 'center',
165
216
  height: '100vh',
166
217
  gap: 3,
167
- }, children: [_jsx(Spinner, { size: "large" }), _jsx(Text, { sx: { color: 'fg.muted' }, children: runtimeStatus === 'launching'
168
- ? 'Launching runtime for notification agent…'
169
- : 'Creating notification demo agent…' })] }));
218
+ }, children: [_jsx(Spinner, { size: "large" }), _jsx(Text, { sx: { color: 'fg.muted' }, children: "Launching local notification agent\u2026" })] }));
170
219
  }
171
220
  if (runtimeStatus === 'error' || hookError) {
172
221
  return _jsx(ErrorView, { error: hookError, onLogout: onLogout });
@@ -201,7 +250,7 @@ const AgentNotificationsInner = ({ onLogout, }) => {
201
250
  borderBottom: '1px solid',
202
251
  borderColor: 'border.default',
203
252
  flexShrink: 0,
204
- }, children: [_jsx(BellIcon, { size: 16 }), _jsxs(Heading, { as: "h3", sx: { fontSize: 2, flex: 1 }, children: ["Notifications \u2014 ", podName] }), unreadCount > 0 && (_jsxs(Label, { variant: "accent", size: "small", children: [unreadCount, " unread"] }))] }), _jsxs(Box, { sx: { flex: 1, minHeight: 0, display: 'flex' }, children: [_jsx(Box, { sx: { flex: 1, minWidth: 0 }, children: _jsx(Chat, { protocol: "vercel-ai", baseUrl: agentBaseUrl, agentId: agentId, title: "Notification Agent", placeholder: "Ask the agent to send you notifications\u2026", description: `${unreadCount} unread notification${unreadCount !== 1 ? 's' : ''}`, showHeader: true, autoFocus: true, height: "100%", runtimeId: podName, historyEndpoint: `${agentBaseUrl}/api/v1/history`, suggestions: [
253
+ }, children: [_jsx(BellIcon, { size: 16 }), _jsxs(Heading, { as: "h3", sx: { fontSize: 2, flex: 1 }, children: ["Notifications \u2014 ", podName] }), unreadCount > 0 && (_jsxs(Label, { variant: "accent", size: "small", children: [unreadCount, " unread"] }))] }), _jsxs(Box, { sx: { flex: 1, minHeight: 0, display: 'flex' }, children: [_jsx(Box, { sx: { flex: 1, minWidth: 0 }, children: _jsx(Chat, { protocol: "vercel-ai", baseUrl: agentBaseUrl, agentId: agentId, title: "Notification Agent", brandIcon: _jsx(BellIcon, { size: 16 }), placeholder: "Ask the agent to send you notifications\u2026", description: `${unreadCount} unread notification${unreadCount !== 1 ? 's' : ''}`, showHeader: true, autoFocus: true, height: "100%", runtimeId: podName, historyEndpoint: `${agentBaseUrl}/api/v1/history`, suggestions: [
205
254
  {
206
255
  title: 'Alert me',
207
256
  message: 'Notify me when KPIs drop below threshold',
@@ -24,7 +24,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
24
24
  */
25
25
  /// <reference types="vite/client" />
26
26
  import { useState, useEffect, useCallback, useRef, useMemo, } from 'react';
27
- import { Text, Button, Select, FormControl } from '@primer/react';
27
+ import { Text, Button, Spinner } from '@primer/react';
28
28
  import { TelescopeIcon, PlugIcon, XIcon } from '@primer/octicons-react';
29
29
  import { Box } from '@datalayer/primer-addons';
30
30
  import { OtelHeader, DashboardView, SqlView, SystemView, useSimpleAuthStore, } from '@datalayer/core/lib/views/otel';
@@ -32,7 +32,6 @@ import { useCoreStore } from '@datalayer/core';
32
32
  import { ThemedProvider } from './utils/themedProvider';
33
33
  import { AuthRequiredView } from './components';
34
34
  import { ChatSidebar } from '../chat';
35
- import { DEFAULT_MODEL } from '../specs';
36
35
  // ─── Environment / defaults ────────────────────────────────────────────────
37
36
  const OTEL_BASE_URL_ENV = import.meta.env.VITE_OTEL_BASE_URL ?? '';
38
37
  const DATALAYER_RUN_URL_ENV = import.meta.env.VITE_DATALAYER_RUN_URL ?? '';
@@ -43,69 +42,62 @@ const DATALAYER_RUN_URL_ENV = import.meta.env.VITE_DATALAYER_RUN_URL ?? '';
43
42
  const AGENT_BASE_URL_ENV = import.meta.env.VITE_BASE_URL || '';
44
43
  const DEFAULT_AGENT_PROTOCOL = 'vercel-ai';
45
44
  const DEFAULT_AGENT_LIBRARY = 'pydantic-ai';
45
+ /** Spec id this example always launches. */
46
+ const AGENT_SPEC_ID = 'example-otel';
46
47
  /**
47
48
  * Small form for picking an agent spec and launching it.
48
49
  * Renders as the `children` of the ChatSidebar so it appears above the chat.
49
50
  */
50
- const AgentSelectorPanel = ({ baseUrl, onConnected, onDisconnected, isConnected, connectedAgentName, }) => {
51
- const [specs, setSpecs] = useState([]);
52
- const [selectedSpecId, setSelectedSpecId] = useState('');
51
+ const AgentLaunchPanel = ({ baseUrl, onConnected, onDisconnected, isConnected, connectedAgentName, }) => {
53
52
  const [loading, setLoading] = useState(false);
54
53
  const [error, setError] = useState(null);
55
- // Fetch library specs on mount
56
- useEffect(() => {
57
- const load = async () => {
58
- try {
59
- const res = await fetch(`${baseUrl}/api/v1/agents/library`);
60
- if (!res.ok)
61
- throw new Error(`HTTP ${res.status}`);
62
- const data = await res.json();
63
- setSpecs(data);
64
- if (data.length > 0)
65
- setSelectedSpecId(data[0].id);
66
- }
67
- catch (e) {
68
- setError('Could not load agent specs from the backend.');
69
- console.warn('[AgentOtelExample] Failed to load library specs:', e);
70
- }
71
- };
72
- void load();
73
- }, [baseUrl]);
54
+ const launchedRef = useRef(false);
74
55
  const handleLaunch = useCallback(async () => {
75
- if (!selectedSpecId)
76
- return;
77
56
  setLoading(true);
78
57
  setError(null);
79
58
  try {
80
- const spec = specs.find(s => s.id === selectedSpecId);
81
- const transport = spec?.transport ?? DEFAULT_AGENT_PROTOCOL;
59
+ const transport = DEFAULT_AGENT_PROTOCOL;
82
60
  const res = await fetch(`${baseUrl}/api/v1/agents`, {
83
61
  method: 'POST',
84
62
  headers: { 'Content-Type': 'application/json' },
85
63
  body: JSON.stringify({
86
- name: selectedSpecId,
64
+ name: AGENT_SPEC_ID,
87
65
  description: `Launched from AgentOtelExample`,
88
66
  agent_library: DEFAULT_AGENT_LIBRARY,
89
67
  transport,
90
- model: DEFAULT_MODEL,
91
- system_prompt: 'You are a helpful AI assistant observing OTEL telemetry data.',
92
- agent_spec_id: selectedSpecId,
68
+ agent_spec_id: AGENT_SPEC_ID,
93
69
  }),
94
70
  });
95
71
  if (!res.ok) {
96
72
  const err = await res.json().catch(() => ({ detail: 'Unknown error' }));
97
- throw new Error(err.detail || `Failed to create agent: ${res.status}`);
73
+ const detail = typeof err?.detail === 'string' ? err.detail : 'Unknown error';
74
+ // Reuse existing agent when backend reports duplicate creation.
75
+ if (res.status === 409 || /already exists/i.test(detail)) {
76
+ const idMatch = detail.match(/Agent with ID '([^']+)' already exists/i);
77
+ const existingId = idMatch?.[1] || AGENT_SPEC_ID;
78
+ onConnected(existingId, transport);
79
+ return;
80
+ }
81
+ throw new Error(detail || `Failed to create agent: ${res.status}`);
98
82
  }
99
83
  const data = await res.json();
100
84
  onConnected(data.id, transport);
101
85
  }
102
86
  catch (e) {
103
87
  setError(e instanceof Error ? e.message : 'Failed to launch agent');
88
+ console.warn('[AgentOtelExample] Failed to launch agent:', e);
104
89
  }
105
90
  finally {
106
91
  setLoading(false);
107
92
  }
108
- }, [selectedSpecId, specs, baseUrl, onConnected]);
93
+ }, [baseUrl, onConnected]);
94
+ // Auto-launch the example-otel agent on mount.
95
+ useEffect(() => {
96
+ if (launchedRef.current || isConnected)
97
+ return;
98
+ launchedRef.current = true;
99
+ void handleLaunch();
100
+ }, [handleLaunch, isConnected]);
109
101
  if (isConnected) {
110
102
  return (_jsxs(Box, { sx: {
111
103
  px: 3,
@@ -129,7 +121,7 @@ const AgentSelectorPanel = ({ baseUrl, onConnected, onDisconnected, isConnected,
129
121
  gap: 2,
130
122
  flexShrink: 0,
131
123
  bg: 'canvas.subtle',
132
- }, children: [_jsx(Text, { sx: { fontSize: 0, fontWeight: 'bold', color: 'fg.muted' }, children: "SELECT AGENT" }), specs.length > 0 ? (_jsxs(_Fragment, { children: [_jsxs(FormControl, { children: [_jsx(FormControl.Label, { visuallyHidden: true, children: "Agent spec" }), _jsx(Select, { value: selectedSpecId, onChange: e => setSelectedSpecId(e.target.value), block: true, size: "small", disabled: loading, children: specs.map(s => (_jsx(Select.Option, { value: s.id, children: s.name ?? s.id }, s.id))) })] }), _jsx(Button, { variant: "primary", size: "small", onClick: handleLaunch, disabled: loading || !selectedSpecId, leadingVisual: PlugIcon, sx: { width: '100%' }, children: loading ? 'Launching…' : 'Launch Agent' })] })) : error ? (_jsx(Text, { sx: { fontSize: 1, color: 'danger.fg' }, children: error })) : (_jsx(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: "Loading specs\u2026" })), error && specs.length > 0 && (_jsx(Text, { sx: { fontSize: 1, color: 'danger.fg' }, children: error }))] }));
124
+ }, children: [_jsx(Text, { sx: { fontSize: 0, fontWeight: 'bold', color: 'fg.muted' }, children: "AGENT" }), loading ? (_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(Spinner, { size: "small" }), _jsxs(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: ["Launching ", AGENT_SPEC_ID, "\u2026"] })] })) : error ? (_jsxs(_Fragment, { children: [_jsx(Text, { sx: { fontSize: 1, color: 'danger.fg' }, children: error }), _jsx(Button, { variant: "primary", size: "small", onClick: handleLaunch, leadingVisual: PlugIcon, sx: { width: '100%' }, children: "Retry" })] })) : (_jsxs(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: ["Launching ", AGENT_SPEC_ID, "\u2026"] }))] }));
133
125
  };
134
126
  const TAB_SX = (active) => ({
135
127
  px: 3,
@@ -142,7 +134,7 @@ const TAB_SX = (active) => ({
142
134
  borderColor: active ? 'accent.fg' : 'transparent',
143
135
  '&:hover': { color: 'fg.default' },
144
136
  });
145
- const AgentOtelExampleInner = ({ token, onSignOut }) => {
137
+ const AgentOtelExampleInner = ({ token }) => {
146
138
  const { configuration } = useCoreStore();
147
139
  const resolvedRunUrl = configuration?.otelRunUrl ||
148
140
  configuration?.runUrl ||
@@ -220,7 +212,7 @@ const AgentOtelExampleInner = ({ token, onSignOut }) => {
220
212
  overflow: 'hidden',
221
213
  bg: 'canvas.default',
222
214
  color: 'fg.default',
223
- }, children: [_jsx(OtelHeader, { baseUrl: otelBaseUrl, token: token, onNavigate: handleNavigate, onSignOut: onSignOut, showGenerateButtons: false, trailing: _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(TelescopeIcon, { size: 16 }), _jsx(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: otelBaseUrl })] }) }), _jsxs(Box, { sx: {
215
+ }, children: [_jsx(OtelHeader, { baseUrl: otelBaseUrl, token: token, onNavigate: handleNavigate, showGenerateButtons: true, showAccountControls: false, trailing: _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(TelescopeIcon, { size: 16 }), _jsx(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: otelBaseUrl })] }) }), _jsxs(Box, { sx: {
224
216
  display: 'flex',
225
217
  flex: 1,
226
218
  minHeight: 0,
@@ -267,14 +259,13 @@ const AgentOtelExampleInner = ({ token, onSignOut }) => {
267
259
  },
268
260
  ],
269
261
  }
270
- : { useStore: true }, children: _jsx(AgentSelectorPanel, { baseUrl: agentBaseUrl, onConnected: handleAgentConnected, onDisconnected: handleAgentDisconnected, isConnected: !!connectedAgentId, connectedAgentName: connectedAgentId ?? undefined }) })] })] }));
262
+ : { useStore: true }, children: _jsx(AgentLaunchPanel, { baseUrl: agentBaseUrl, onConnected: handleAgentConnected, onDisconnected: handleAgentDisconnected, isConnected: !!connectedAgentId, connectedAgentName: connectedAgentId ?? undefined }) })] })] }));
271
263
  };
272
264
  /**
273
265
  * AgentOtelExample – themed root with auth gate.
274
266
  */
275
267
  const AgentOtelExample = () => {
276
268
  const token = useSimpleAuthStore(s => s.token);
277
- const clearAuth = useSimpleAuthStore(s => s.clearAuth);
278
- return (_jsx(ThemedProvider, { children: !token ? (_jsx(AuthRequiredView, {})) : (_jsx(AgentOtelExampleInner, { token: token, onSignOut: clearAuth })) }));
269
+ return (_jsx(ThemedProvider, { children: !token ? _jsx(AuthRequiredView, {}) : _jsx(AgentOtelExampleInner, { token: token }) }));
279
270
  };
280
271
  export default AgentOtelExample;
@@ -2,7 +2,7 @@
2
2
  * AgentOutputsExample
3
3
  *
4
4
  * Demonstrates rich output rendering for agent responses. The agent (spec
5
- * `demo-outputs`) is prompted to return exactly one of four output types per
5
+ * `example-outputs`) is prompted to return exactly one of four output types per
6
6
  * response:
7
7
  * - TABLE → GitHub-flavored Markdown table
8
8
  * - JSON → ```json fenced block
@@ -7,7 +7,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
7
7
  * AgentOutputsExample
8
8
  *
9
9
  * Demonstrates rich output rendering for agent responses. The agent (spec
10
- * `demo-outputs`) is prompted to return exactly one of four output types per
10
+ * `example-outputs`) is prompted to return exactly one of four output types per
11
11
  * response:
12
12
  * - TABLE → GitHub-flavored Markdown table
13
13
  * - JSON → ```json fenced block
@@ -33,12 +33,27 @@ import { Chat } from '../chat';
33
33
  import { useChatStore } from '../stores/chatStore';
34
34
  const queryClient = new QueryClient();
35
35
  // ─── Constants ─────────────────────────────────────────────────────────────
36
- const AGENT_NAME = 'outputs-demo-agent';
36
+ const AGENT_NAME = 'outputs-example-agent';
37
37
  const AGENT_SPEC_ID = 'demo-outputs';
38
38
  const DEFAULT_LOCAL_BASE_URL = import.meta.env.VITE_BASE_URL || 'http://localhost:8765';
39
39
  // ─── Output detection ──────────────────────────────────────────────────────
40
40
  const FENCE_RE = /```([a-zA-Z0-9_+-]*)\n([\s\S]*?)```/g;
41
41
  const MD_TABLE_RE = /(^|\n)\s*\|[^\n]+\|\s*\n\s*\|[\s:|-]+\|\s*\n(\s*\|[^\n]+\|\s*\n?)+/;
42
+ /**
43
+ * Some agents emit a markdown table compressed onto a single logical line by
44
+ * joining row separators with `||`. Expand that form back to one row per line
45
+ * so the markdown table renderer can parse it. Idempotent: any pre-existing
46
+ * `|\n|` boundaries are unaffected.
47
+ */
48
+ const expandCompactMarkdownTable = (text) => {
49
+ if (!text)
50
+ return text;
51
+ if (!/\|\s*[-:| ]{3,}\|/.test(text))
52
+ return text;
53
+ if (!text.includes('||'))
54
+ return text;
55
+ return text.replace(/\|\|/g, '|\n|');
56
+ };
42
57
  const EXT_LIKE_INFOS = new Set([
43
58
  'csv',
44
59
  'tsv',
@@ -70,8 +85,28 @@ const detectOutput = (m) => {
70
85
  const match = FENCE_RE.exec(text);
71
86
  if (match) {
72
87
  const info = (match[1] || '').toLowerCase();
73
- const body = match[2] ?? '';
88
+ const rawBody = match[2] ?? '';
89
+ const body = expandCompactMarkdownTable(rawBody);
74
90
  const firstLine = body.split('\n', 1)[0]?.trim() ?? '';
91
+ // Markdown fenced table should render in the table panel, not as a file.
92
+ if ((info === 'markdown' || info === 'md') && MD_TABLE_RE.test(body)) {
93
+ const tableMatch = body.match(MD_TABLE_RE);
94
+ return {
95
+ tab: 'table',
96
+ payload: tableMatch ? tableMatch[0].trim() : body.trim(),
97
+ messageId: m.id,
98
+ };
99
+ }
100
+ // Bare/unlabeled fence around a markdown table — route to Table tab too.
101
+ if ((!info || info === 'text' || info === 'plain') &&
102
+ MD_TABLE_RE.test(body)) {
103
+ const tableMatch = body.match(MD_TABLE_RE);
104
+ return {
105
+ tab: 'table',
106
+ payload: tableMatch ? tableMatch[0].trim() : body.trim(),
107
+ messageId: m.id,
108
+ };
109
+ }
75
110
  // Chart: ```json with `// chart` marker on first line.
76
111
  if (info === 'json' && /^\/\/\s*chart\b/i.test(firstLine)) {
77
112
  return {
@@ -137,11 +172,12 @@ const detectOutput = (m) => {
137
172
  }
138
173
  }
139
174
  // 2) Markdown table (no fences).
140
- if (MD_TABLE_RE.test(text)) {
141
- const tableMatch = text.match(MD_TABLE_RE);
175
+ const expandedText = expandCompactMarkdownTable(text.trim());
176
+ if (MD_TABLE_RE.test(expandedText)) {
177
+ const tableMatch = expandedText.match(MD_TABLE_RE);
142
178
  return {
143
179
  tab: 'table',
144
- payload: tableMatch ? tableMatch[0].trim() : text,
180
+ payload: tableMatch ? tableMatch[0].trim() : expandedText,
145
181
  messageId: m.id,
146
182
  };
147
183
  }
@@ -150,7 +186,10 @@ const detectOutput = (m) => {
150
186
  // ─── Table renderer (parses the Markdown pipe syntax) ──────────────────────
151
187
  const MarkdownTable = ({ source }) => {
152
188
  const { headers, rows } = useMemo(() => {
153
- const lines = source
189
+ // Some model responses compress table rows into one line using `||`.
190
+ // Normalize that form back to one table row per line.
191
+ const normalized = expandCompactMarkdownTable(source).trim();
192
+ const lines = normalized
154
193
  .split('\n')
155
194
  .map(l => l.trim())
156
195
  .filter(l => l.startsWith('|'));
@@ -175,6 +214,7 @@ const MarkdownTable = ({ source }) => {
175
214
  }
176
215
  return (_jsx(Box, { sx: { overflowX: 'auto' }, children: _jsxs(Box, { as: "table", sx: {
177
216
  width: '100%',
217
+ tableLayout: 'auto',
178
218
  borderCollapse: 'collapse',
179
219
  fontSize: 0,
180
220
  'th, td': {
@@ -184,6 +224,8 @@ const MarkdownTable = ({ source }) => {
184
224
  py: 1,
185
225
  textAlign: 'left',
186
226
  verticalAlign: 'top',
227
+ whiteSpace: 'normal',
228
+ wordBreak: 'break-word',
187
229
  },
188
230
  th: { bg: 'canvas.subtle', fontWeight: 'bold' },
189
231
  }, children: [_jsx("thead", { children: _jsx("tr", { children: headers.map((h, i) => (_jsx("th", { children: h }, i))) }) }), _jsx("tbody", { children: rows.map((r, i) => (_jsx("tr", { children: r.map((c, j) => (_jsx("td", { children: c }, j))) }, i))) })] }) }));
@@ -316,24 +358,33 @@ const AgentOutputsInner = ({ onLogout, }) => {
316
358
  }, [agentBaseUrl, agentName, authFetch]);
317
359
  const [activeTab, setActiveTab] = useState('table');
318
360
  const [detected, setDetected] = useState([]);
319
- const lastProcessedIdRef = useRef(null);
361
+ const lastTextByIdRef = useRef(new Map());
320
362
  // Subscribe to chat store messages and detect outputs in assistant replies.
363
+ // We re-detect on every change because messages stream incrementally — the
364
+ // first chunk may only contain a header + one row, and later chunks add the
365
+ // remaining rows; we always want to keep the latest, most complete output.
321
366
  useEffect(() => {
322
367
  const process = (messages) => {
323
368
  const assistants = messages.filter(m => m.role === 'assistant');
324
369
  if (assistants.length === 0)
325
370
  return;
326
371
  const last = assistants[assistants.length - 1];
327
- if (last.id === lastProcessedIdRef.current)
372
+ const currentText = messageText(last);
373
+ if (lastTextByIdRef.current.get(last.id) === currentText)
328
374
  return;
375
+ lastTextByIdRef.current.set(last.id, currentText);
329
376
  const out = detectOutput(last);
330
377
  if (!out)
331
378
  return;
332
- lastProcessedIdRef.current = last.id;
333
379
  setDetected(prev => {
334
- if (prev.some(d => d.messageId === out.messageId))
335
- return prev;
336
- return [out, ...prev].slice(0, 20);
380
+ const idx = prev.findIndex(d => d.messageId === out.messageId);
381
+ if (idx === -1)
382
+ return [out, ...prev].slice(0, 20);
383
+ // Replace the existing detection in place so the panel keeps up with
384
+ // streaming content.
385
+ const next = prev.slice();
386
+ next[idx] = out;
387
+ return next;
337
388
  });
338
389
  setActiveTab(out.tab);
339
390
  };
@@ -351,8 +402,8 @@ const AgentOutputsInner = ({ onLogout, }) => {
351
402
  height: '100vh',
352
403
  gap: 3,
353
404
  }, children: [_jsx(Spinner, { size: "large" }), _jsx(Text, { sx: { color: 'fg.muted' }, children: runtimeStatus === 'launching'
354
- ? 'Launching outputs demo agent...'
355
- : 'Creating outputs demo agent...' })] }));
405
+ ? 'Launching outputs example agent...'
406
+ : 'Creating outputs example agent...' })] }));
356
407
  }
357
408
  if (runtimeStatus === 'error' || hookError) {
358
409
  return _jsx(ErrorView, { error: hookError, onLogout: onLogout });
@@ -388,7 +439,7 @@ const AgentOutputsInner = ({ onLogout, }) => {
388
439
  borderBottom: '1px solid',
389
440
  borderColor: 'border.default',
390
441
  flexShrink: 0,
391
- }, children: [_jsx(TableIcon, { size: 16 }), _jsx(Heading, { as: "h3", sx: { fontSize: 2, flex: 1 }, children: "Agent Outputs \u2014 Local Runtime" })] }), _jsxs(Box, { sx: { flex: 1, minHeight: 0, display: 'flex' }, children: [_jsx(Box, { sx: { flex: 1, minWidth: 0 }, children: _jsx(Chat, { protocol: "vercel-ai", baseUrl: agentBaseUrl, agentId: agentId, authToken: chatAuthToken, title: "Outputs Demo Agent", placeholder: "Ask for a Table, JSON, Chart, or File\u2026", description: `${detected.length} detected output${detected.length !== 1 ? 's' : ''}`, showHeader: true, showToolsMenu: true, showSkillsMenu: true, autoFocus: true, height: "100%", runtimeId: agentId, historyEndpoint: `${agentBaseUrl}/api/v1/history`, suggestions: [
442
+ }, children: [_jsx(TableIcon, { size: 16 }), _jsx(Heading, { as: "h3", sx: { fontSize: 2, flex: 1 }, children: "Agent Outputs \u2014 Local Runtime" })] }), _jsxs(Box, { sx: { flex: 1, minHeight: 0, display: 'flex' }, children: [_jsx(Box, { sx: { flex: 1, minWidth: 0 }, children: _jsx(Chat, { protocol: "vercel-ai", baseUrl: agentBaseUrl, agentId: agentId, authToken: chatAuthToken, title: "Outputs Demo Agent", brandIcon: _jsx(FileIcon, { size: 16 }), placeholder: "Ask for a Table, JSON, Chart, or File\u2026", description: `${detected.length} detected output${detected.length !== 1 ? 's' : ''}`, showHeader: true, showToolsMenu: true, showSkillsMenu: true, autoFocus: true, height: "100%", runtimeId: agentId, historyEndpoint: `${agentBaseUrl}/api/v1/history`, suggestions: [
392
443
  {
393
444
  title: 'Table',
394
445
  message: 'Generate a Markdown table of the top 5 US cities by population, with columns City, State, Population.',
@@ -6,15 +6,16 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
6
6
  import { useEffect, useMemo, useState } from 'react';
7
7
  import { Box, setupPrimerPortals } from '@datalayer/primer-addons';
8
8
  import { Button, Heading, Label, Spinner, Text } from '@primer/react';
9
+ import { FileIcon } from '@primer/octicons-react';
9
10
  import validator from '@rjsf/validator-ajv8';
10
11
  import { Form, yamlSchemaToJsonSchema } from '@datalayer/primer-rjsf';
11
12
  import { ThemedProvider } from './utils/themedProvider';
12
13
  import { uniqueAgentId } from './utils/agentId';
14
+ import { useExampleAgentRuntimesUrl } from './utils/useExampleAgentRuntimesUrl';
13
15
  import { ErrorView } from './components';
14
16
  import { Chat } from '../chat';
15
17
  setupPrimerPortals();
16
- const BASE_URL = 'http://localhost:8765';
17
- const AGENT_SPEC_ID = 'demo-parameters';
18
+ const AGENT_SPEC_ID = 'example-parameters';
18
19
  const AGENT_NAME = 'parameters-demo';
19
20
  function isRecord(value) {
20
21
  return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
@@ -101,6 +102,7 @@ function hasRequiredValues(schema, formData) {
101
102
  });
102
103
  }
103
104
  const AgentParametersExample = () => {
105
+ const baseUrl = useExampleAgentRuntimesUrl();
104
106
  const [showSchemaForm, setShowSchemaForm] = useState(false);
105
107
  const [isSchemaLoading, setIsSchemaLoading] = useState(false);
106
108
  const [schema, setSchema] = useState(null);
@@ -121,7 +123,7 @@ const AgentParametersExample = () => {
121
123
  setIsSchemaLoading(true);
122
124
  setError(null);
123
125
  try {
124
- const response = await fetch(`${BASE_URL}/api/v1/agents/library/${AGENT_SPEC_ID}`);
126
+ const response = await fetch(`${baseUrl}/api/v1/agents/library/${AGENT_SPEC_ID}`);
125
127
  if (!response.ok) {
126
128
  throw new Error(`Failed to load schema: ${response.status}`);
127
129
  }
@@ -147,7 +149,7 @@ const AgentParametersExample = () => {
147
149
  setError(null);
148
150
  try {
149
151
  const name = uniqueAgentId(AGENT_NAME);
150
- const response = await fetch(`${BASE_URL}/api/v1/agents`, {
152
+ const response = await fetch(`${baseUrl}/api/v1/agents`, {
151
153
  method: 'POST',
152
154
  headers: { 'Content-Type': 'application/json' },
153
155
  body: JSON.stringify({
@@ -178,13 +180,13 @@ const AgentParametersExample = () => {
178
180
  if (!agentId) {
179
181
  return;
180
182
  }
181
- void fetch(`${BASE_URL}/api/v1/agents/${encodeURIComponent(agentId)}`, {
183
+ void fetch(`${baseUrl}/api/v1/agents/${encodeURIComponent(agentId)}`, {
182
184
  method: 'DELETE',
183
185
  }).catch(() => {
184
186
  // Ignore teardown failures in example mode.
185
187
  });
186
188
  };
187
- }, [agentId]);
189
+ }, [agentId, baseUrl]);
188
190
  if (!agentId) {
189
191
  return (_jsx(ThemedProvider, { children: _jsxs(Box, { sx: {
190
192
  maxWidth: 760,
@@ -199,7 +201,7 @@ const AgentParametersExample = () => {
199
201
  flexDirection: 'column',
200
202
  gap: 2,
201
203
  bg: 'canvas.subtle',
202
- }, children: [_jsx(Text, { sx: { fontSize: 0, fontWeight: 'bold', color: 'fg.muted' }, children: "CONFIGURE AGENT" }), _jsx(Heading, { as: "h2", sx: { fontSize: 2 }, children: "Launch Parameterized Agent" }), _jsx(Text, { sx: { color: 'fg.muted', fontSize: 1, maxWidth: 620 }, children: "Load the runtime schema directly from demo-parameters, fill the generated form, then launch with validated parameters." }), _jsxs(Box, { sx: {
204
+ }, children: [_jsx(Text, { sx: { fontSize: 0, fontWeight: 'bold', color: 'fg.muted' }, children: "CONFIGURE AGENT" }), _jsx(Heading, { as: "h2", sx: { fontSize: 2 }, children: "Launch Parameterized Agent" }), _jsx(Text, { sx: { color: 'fg.muted', fontSize: 1, maxWidth: 620 }, children: "Load the runtime schema directly from example-parameters, fill the generated form, then launch with validated parameters." }), _jsxs(Box, { sx: {
203
205
  display: 'flex',
204
206
  alignItems: 'center',
205
207
  gap: 2,
@@ -232,7 +234,7 @@ const AgentParametersExample = () => {
232
234
  // Prevent implicit form submission; launching is click-only.
233
235
  }, noHtml5Validate: true }) })), _jsx(Button, { variant: "primary", size: "small", type: "button", onClick: launchAgent, disabled: !canLaunch || isCreating, sx: { width: '100%' }, children: isCreating ? (_jsxs(_Fragment, { children: [_jsx(Spinner, { size: "small" }), " Launching..."] })) : ('Launch Agent') }), schema && formTouched && (_jsx(Text, { sx: { color: 'fg.muted', fontSize: 1 }, children: "Parameters are sent as agent_parameters in the create-agent request." })), error && _jsx(ErrorView, { error: "Launch failed", detail: error })] }) }));
234
236
  }
235
- return (_jsx(Chat, { protocol: "vercel-ai", baseUrl: BASE_URL, agentId: agentId, title: `Parameterized Agent: ${String(formData.project ?? 'Project')}`, placeholder: "Ask something about your configured project...", description: `Role: ${String(formData.role ?? 'n/a')} · Tone: ${String(formData.tone ?? 'n/a')}`, showHeader: true, showModelSelector: true, showToolsMenu: true, showSkillsMenu: true, showTokenUsage: true, showInformation: true, autoFocus: true, height: "100vh", runtimeId: agentId, historyEndpoint: `${BASE_URL}/api/v1/history`, suggestions: [
237
+ return (_jsx(Chat, { protocol: "vercel-ai", baseUrl: baseUrl, agentId: agentId, title: `Parameterized Agent: ${String(formData.project ?? 'Project')}`, brandIcon: _jsx(FileIcon, { size: 16 }), placeholder: "Ask something about your configured project...", description: `Role: ${String(formData.role ?? 'n/a')} · Tone: ${String(formData.tone ?? 'n/a')}`, showHeader: true, showModelSelector: true, showToolsMenu: true, showSkillsMenu: true, showTokenUsage: true, showInformation: true, autoFocus: true, height: "100vh", runtimeId: agentId, historyEndpoint: `${baseUrl}/api/v1/history`, suggestions: [
236
238
  {
237
239
  title: 'Print demo_params',
238
240
  message: 'Use execute_code to print(demo_params) from the sandbox, then explain what it is.',
@@ -5,7 +5,7 @@
5
5
  * sidebar that streams WebSocket messages to and from the
6
6
  * `/configure/sandbox/ws` endpoint.
7
7
  *
8
- * - Creates a local agent (spec: demo-full) with codemode enabled
8
+ * - Creates a local agent (spec: example-full) with codemode enabled
9
9
  * - SegmentedControl toggles between "eval" and "jupyter" variants
10
10
  * - Sidebar shows live sandbox status, WebSocket event log, and an
11
11
  * interrupt button