@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
@@ -9,6 +9,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
9
9
  import { Box } from '@datalayer/primer-addons';
10
10
  import { ThemedProvider } from './utils/themedProvider';
11
11
  import { uniqueAgentId } from './utils/agentId';
12
+ import { useExampleAgentRuntimesUrl } from './utils/useExampleAgentRuntimesUrl';
12
13
  import { Chat } from '../chat';
13
14
  // Create a query client for React Query
14
15
  const queryClient = new QueryClient({
@@ -22,19 +23,18 @@ const queryClient = new QueryClient({
22
23
  },
23
24
  });
24
25
  const AGENT_NAME = 'datalayer-assistant';
25
- const BASE_URL = 'http://localhost:8765';
26
26
  /**
27
27
  * Hook to ensure the agent exists on the server
28
28
  * Creates the agent if it doesn't exist
29
29
  */
30
- function useEnsureAgent() {
30
+ function useEnsureAgent(baseUrl) {
31
31
  const agentName = useRef(uniqueAgentId(AGENT_NAME)).current;
32
32
  const [agentId, setAgentId] = useState(null);
33
33
  const [isLoading, setIsLoading] = useState(true);
34
34
  const [error, setError] = useState(null);
35
35
  const createAgent = useCallback(async () => {
36
36
  try {
37
- const response = await fetch(`${BASE_URL}/api/v1/agents`, {
37
+ const response = await fetch(`${baseUrl}/api/v1/agents`, {
38
38
  method: 'POST',
39
39
  headers: {
40
40
  'Content-Type': 'application/json',
@@ -71,7 +71,7 @@ Be concise, helpful, and provide working code examples when appropriate.`,
71
71
  console.error('[AgentRuntimeCustomExample] Error creating agent:', err);
72
72
  throw err;
73
73
  }
74
- }, [agentName]);
74
+ }, [agentName, baseUrl]);
75
75
  const initAgent = useCallback(async () => {
76
76
  setIsLoading(true);
77
77
  setError(null);
@@ -107,7 +107,8 @@ Be concise, helpful, and provide working code examples when appropriate.`,
107
107
  * - Auto-creates agent on the server if it doesn't exist
108
108
  */
109
109
  const AgentRuntimeCustomExample = () => {
110
- const { agentId, isLoading, error, retry } = useEnsureAgent();
110
+ const baseUrl = useExampleAgentRuntimesUrl();
111
+ const { agentId, isLoading, error, retry } = useEnsureAgent(baseUrl);
111
112
  return (_jsx(QueryClientProvider, { client: queryClient, children: _jsx(ThemedProvider, { children: _jsxs(Box, { sx: {
112
113
  display: 'flex',
113
114
  flexDirection: 'column',
@@ -20,13 +20,14 @@ import { Text, Spinner } from '@primer/react';
20
20
  import { Box, setupPrimerPortals } from '@datalayer/primer-addons';
21
21
  import { ThemedProvider } from './utils/themedProvider';
22
22
  import { uniqueAgentId } from './utils/agentId';
23
+ import { useExampleAgentRuntimesUrl } from './utils/useExampleAgentRuntimesUrl';
23
24
  import { ErrorView } from './components';
24
25
  import { Chat } from '../chat';
25
26
  setupPrimerPortals();
26
- const BASE_URL = 'http://localhost:8765';
27
- const AGENT_SPEC_ID = 'demo-simple';
27
+ const AGENT_SPEC_ID = 'example-simple';
28
28
  const AGENT_NAME = 'simple';
29
29
  const AgentRuntimeChatExample = () => {
30
+ const baseUrl = useExampleAgentRuntimesUrl();
30
31
  const [agentId, setAgentId] = useState(null);
31
32
  const [error, setError] = useState(null);
32
33
  const [isCreating, setIsCreating] = useState(true);
@@ -37,7 +38,7 @@ const AgentRuntimeChatExample = () => {
37
38
  const name = uniqueAgentId(AGENT_NAME);
38
39
  const createAgent = async () => {
39
40
  try {
40
- const response = await fetch(`${BASE_URL}/api/v1/agents`, {
41
+ const response = await fetch(`${baseUrl}/api/v1/agents`, {
41
42
  method: 'POST',
42
43
  headers: { 'Content-Type': 'application/json' },
43
44
  body: JSON.stringify({
@@ -69,7 +70,7 @@ const AgentRuntimeChatExample = () => {
69
70
  return () => {
70
71
  cancelled = true;
71
72
  };
72
- }, []);
73
+ }, [baseUrl]);
73
74
  // Loading state while agent is being created
74
75
  if (isCreating) {
75
76
  return (_jsx(ThemedProvider, { children: _jsxs(Box, { sx: {
@@ -87,7 +88,7 @@ const AgentRuntimeChatExample = () => {
87
88
  return (_jsx(ThemedProvider, { children: _jsx(ErrorView, { error: "Failed to start agent", detail: error || 'No agent ID returned' }) }));
88
89
  }
89
90
  // Agent is ready — render the Chat component
90
- return (_jsx(Chat, { protocol: "ag-ui", baseUrl: BASE_URL, agentId: agentId, title: "Simple Agent", placeholder: "Send a message...", description: "Chat with a simple AI assistant", 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: [
91
+ return (_jsx(Chat, { protocol: "ag-ui", baseUrl: baseUrl, agentId: agentId, title: "Simple Agent", placeholder: "Send a message...", description: "Chat with a simple AI assistant", showHeader: true, showModelSelector: true, showToolsMenu: true, showSkillsMenu: true, showTokenUsage: true, showInformation: true, autoFocus: true, height: "100vh", runtimeId: agentId, historyEndpoint: `${baseUrl}/api/v1/history`, suggestions: [
91
92
  {
92
93
  title: 'Hello',
93
94
  message: 'Hello, what can you do?',
@@ -158,7 +158,7 @@ export function ChatLexicalExampleInner({ serviceManager, }) {
158
158
  apiBaseUrl: import.meta.env.VITE_DATALAYER_API_URL ||
159
159
  'https://oss.datalayer.run/api',
160
160
  apiKey: import.meta.env.VITE_DATALAYER_API_KEY,
161
- defaultModel: AIModels.BEDROCK_US_ANTHROPIC_CLAUDE_3_5_HAIKU_20241022_V1_0,
161
+ defaultModel: AIModels.BEDROCK_US_ANTHROPIC_CLAUDE_SONNET_4_5_20250929_V1_0,
162
162
  enableStreaming: true,
163
163
  requireToolApproval: false,
164
164
  debug: import.meta.env.DEV,
@@ -72,7 +72,7 @@ function getJupyterSandboxUrl(serviceManager) {
72
72
  return `${baseUrl}${separator}token=${encodeURIComponent(token)}`;
73
73
  }
74
74
  /**
75
- * Hook to ensure the demo-agent exists on the server.
75
+ * Hook to ensure the example-agent exists on the server.
76
76
  * Creates it if it doesn't exist.
77
77
  */
78
78
  function useEnsureAgent(agentId, baseUrl, jupyterSandboxUrl) {
@@ -54,7 +54,7 @@ function getJupyterSandboxUrl(serviceManager) {
54
54
  return `${baseUrl}${separator}token=${encodeURIComponent(token)}`;
55
55
  }
56
56
  /**
57
- * Hook to ensure the demo-agent is aligned with the active notebook runtime.
57
+ * Hook to ensure the example-agent is aligned with the active notebook runtime.
58
58
  * Recreates the agent with jupyter sandbox settings from the Notebook UI.
59
59
  */
60
60
  function useEnsureAgent(agentId, baseUrl, jupyterSandboxUrl) {
@@ -154,8 +154,8 @@ function NotebookWithChat({ serviceManager, }) {
154
154
  // Get notebook tools for ChatFloating
155
155
  const frontendTools = useNotebookTools(NOTEBOOK_ID);
156
156
  return (_jsxs(Box, { sx: {
157
- height: '100vh',
158
- width: '100vw',
157
+ height: '100%',
158
+ width: '100%',
159
159
  display: 'flex',
160
160
  overflow: 'hidden',
161
161
  }, children: [_jsx(NotebookUI, { serviceManager: serviceManager }), error && (_jsxs(Box, { sx: {
@@ -2,16 +2,15 @@ import React from 'react';
2
2
  /**
3
3
  * ExampleWrapper
4
4
  *
5
- * Wraps every example in a fixed-height container that accounts for
6
- * the 60 px header bar. Examples inside can use `100vh` or `100%`
7
- * freely the wrapper clips and scrolls as needed.
5
+ * Provides every example with a definite-height, scroll-clipped container
6
+ * that fills the parent content area exactly. Examples mounted inside
7
+ * should treat this as their viewport: use `height: '100%'` on their
8
+ * root, then own their internal flex/grid layout (and place any internal
9
+ * scrollers on dedicated panels with `minHeight: 0` + `overflow: 'auto'`).
8
10
  *
9
11
  * Also clears the shared chat + conversation stores synchronously as the
10
12
  * new example mounts, so switching examples never leaks messages from the
11
- * previously-mounted chat (``handleExampleChange`` in ``main.tsx`` already
12
- * resets these, but a last-millisecond WebSocket callback from the old
13
- * example can repopulate them between reset and the new mount — this
14
- * ``useLayoutEffect`` closes that race).
13
+ * previously-mounted chat.
15
14
  */
16
15
  export declare const ExampleWrapper: React.FC<{
17
16
  children: React.ReactNode;
@@ -9,16 +9,15 @@ import { useChatStore, useConversationStore } from '../../stores';
9
9
  /**
10
10
  * ExampleWrapper
11
11
  *
12
- * Wraps every example in a fixed-height container that accounts for
13
- * the 60 px header bar. Examples inside can use `100vh` or `100%`
14
- * freely the wrapper clips and scrolls as needed.
12
+ * Provides every example with a definite-height, scroll-clipped container
13
+ * that fills the parent content area exactly. Examples mounted inside
14
+ * should treat this as their viewport: use `height: '100%'` on their
15
+ * root, then own their internal flex/grid layout (and place any internal
16
+ * scrollers on dedicated panels with `minHeight: 0` + `overflow: 'auto'`).
15
17
  *
16
18
  * Also clears the shared chat + conversation stores synchronously as the
17
19
  * new example mounts, so switching examples never leaks messages from the
18
- * previously-mounted chat (``handleExampleChange`` in ``main.tsx`` already
19
- * resets these, but a last-millisecond WebSocket callback from the old
20
- * example can repopulate them between reset and the new mount — this
21
- * ``useLayoutEffect`` closes that race).
20
+ * previously-mounted chat.
22
21
  */
23
22
  export const ExampleWrapper = ({ children, }) => {
24
23
  useLayoutEffect(() => {
@@ -26,10 +25,28 @@ export const ExampleWrapper = ({ children, }) => {
26
25
  useConversationStore.getState().clearAll();
27
26
  }, []);
28
27
  return (_jsx(Box, { sx: {
29
- height: 'calc(100vh - 60px)',
30
- width: '100%',
31
- overflow: 'auto',
32
28
  position: 'relative',
29
+ height: '100%',
30
+ width: '100%',
31
+ minHeight: 0,
32
+ overflow: 'hidden',
33
+ display: 'flex',
34
+ flexDirection: 'column',
35
+ // Generic constraint: every example's root child fills the wrapper
36
+ // exactly and cannot exceed it. This neutralises stray `100vh`/
37
+ // `calc(100vh - Npx)` heights inside individual examples so the
38
+ // chat footer (or any bottom UI) always remains in the viewport.
39
+ '& > *': {
40
+ flex: '1 1 0',
41
+ minHeight: 0,
42
+ maxHeight: '100%',
43
+ width: '100%',
44
+ // Default scroll behaviour for plain content pages. Examples
45
+ // that manage their own internal scrollers can override this
46
+ // by setting `overflow: 'hidden'` (or another value) on their
47
+ // root element \u2014 the child rule wins on specificity.
48
+ overflow: 'auto',
49
+ },
33
50
  }, children: children }));
34
51
  };
35
52
  export default ExampleWrapper;
@@ -74,7 +74,7 @@ export const EXAMPLE_ENTRIES = [
74
74
  makeEntry('AgUiHumanInTheLoopExample', () => import('./AgUiHumanInTheLoopExample'), 'AG-UI human-in-the-loop approvals example.'),
75
75
  makeEntry('AgUiSharedStateExample', () => import('./AgUiSharedStateExample'), 'AG-UI shared state synchronization example.'),
76
76
  makeEntry('AgUiToolsBasedGenUiExample', () => import('./AgUiToolsBasedGenUiExample'), 'AG-UI tool-based generative UI example.'),
77
- makeEntry('AgentSpecsExample', () => import('./AgentSpecsExample'), 'Configure and run agents from specs and transports.'),
77
+ makeEntry('AgentspecsExample', () => import('./AgentspecsExample'), 'Configure and run agents from specs and transports.'),
78
78
  makeEntry('CellSimpleExample', () => import('./CellSimpleExample'), 'Simple Jupyter cell integration example.'),
79
79
  makeEntry('ChatCustomExample', () => import('./ChatCustomExample'), 'Custom chat experience composition example.'),
80
80
  makeEntry('ChatExample', () => import('./ChatExample'), 'Baseline chat integration example.'),
@@ -86,6 +86,7 @@ export const EXAMPLE_ENTRIES = [
86
86
  makeEntry('AgentEvalsExample', () => import('./AgentEvalsExample'), 'Evaluation workflows for agent outputs.'),
87
87
  makeEntry('AgentGuardrailsExample', () => import('./AgentGuardrailsExample'), 'Guardrails and safety checks for agent runs.'),
88
88
  makeEntry('AgentHooksExample', () => import('./AgentHooksExample'), 'Pre-hooks and post-hooks lifecycle execution example.'),
89
+ makeEntry('AgentInferenceProviderExample', () => import('./AgentInferenceProviderExample'), 'Switch local and datalayer inference providers with live low-level provider events.', ['example', 'agent', 'inference', 'provider', 'runtime']),
89
90
  makeEntry('AgentToolApprovalsExample', () => import('./AgentToolApprovalsExample'), 'Tool approval workflows and manual decisions.'),
90
91
  makeEntry('AgentMemoryExample', () => import('./AgentMemoryExample'), 'Memory-aware conversation and retrieval example.'),
91
92
  makeEntry('AgentSkillsExample', () => import('./AgentSkillsExample'), 'Skills discovery, execution, and monitoring example.'),
@@ -1,4 +1,4 @@
1
- export { default as AgentSpecsExample } from './AgentSpecsExample';
1
+ export { default as AgentspecsExample } from './AgentspecsExample';
2
2
  export { default as A2UiComponentGalleryExample } from './A2UiComponentGalleryExample';
3
3
  export { default as A2UiContactCardExample } from './A2UiContactCardExample';
4
4
  export { default as A2UiRestaurantExample } from './A2UiRestaurantExample';
@@ -20,6 +20,7 @@ export { default as AgentCodemodeExample } from './AgentCodemodeExample';
20
20
  export { default as AgentEvalsExample } from './AgentEvalsExample';
21
21
  export { default as AgentGuardrailsExample } from './AgentGuardrailsExample';
22
22
  export { default as AgentHooksExample } from './AgentHooksExample';
23
+ export { default as AgentInferenceProviderExample } from './AgentInferenceProviderExample';
23
24
  export { default as AgentToolApprovalsExample } from './AgentToolApprovalsExample';
24
25
  export { default as AgentMemoryExample } from './AgentMemoryExample';
25
26
  export { default as AgentOtelExample } from './AgentOtelExample';
@@ -2,7 +2,7 @@
2
2
  * Copyright (c) 2025-2026 Datalayer, Inc.
3
3
  * Distributed under the terms of the Modified BSD License.
4
4
  */
5
- export { default as AgentSpecsExample } from './AgentSpecsExample';
5
+ export { default as AgentspecsExample } from './AgentspecsExample';
6
6
  export { default as A2UiComponentGalleryExample } from './A2UiComponentGalleryExample';
7
7
  export { default as A2UiContactCardExample } from './A2UiContactCardExample';
8
8
  export { default as A2UiRestaurantExample } from './A2UiRestaurantExample';
@@ -24,6 +24,7 @@ export { default as AgentCodemodeExample } from './AgentCodemodeExample';
24
24
  export { default as AgentEvalsExample } from './AgentEvalsExample';
25
25
  export { default as AgentGuardrailsExample } from './AgentGuardrailsExample';
26
26
  export { default as AgentHooksExample } from './AgentHooksExample';
27
+ export { default as AgentInferenceProviderExample } from './AgentInferenceProviderExample';
27
28
  export { default as AgentToolApprovalsExample } from './AgentToolApprovalsExample';
28
29
  export { default as AgentMemoryExample } from './AgentMemoryExample';
29
30
  export { default as AgentOtelExample } from './AgentOtelExample';
@@ -1605,7 +1605,7 @@
1605
1605
  "type": "jupyter-input",
1606
1606
  "version": 1,
1607
1607
  "language": "python",
1608
- "jupyterInputNodeUuid": "collapsible-demo-uuid"
1608
+ "jupyterInputNodeUuid": "collapsible-example-uuid"
1609
1609
  },
1610
1610
  {
1611
1611
  "format": "",
@@ -1619,8 +1619,8 @@
1619
1619
  "output_type": "stream"
1620
1620
  }
1621
1621
  ],
1622
- "jupyterInputNodeUuid": "collapsible-demo-uuid",
1623
- "jupyterOutputNodeUuid": "collapsible-demo-output-uuid"
1622
+ "jupyterInputNodeUuid": "collapsible-example-uuid",
1623
+ "jupyterOutputNodeUuid": "collapsible-example-output-uuid"
1624
1624
  }
1625
1625
  ],
1626
1626
  "direction": "ltr",
@@ -2074,7 +2074,7 @@
2074
2074
  "type": "jupyter-input",
2075
2075
  "version": 1,
2076
2076
  "language": "python",
2077
- "jupyterInputNodeUuid": "plot-demo-uuid"
2077
+ "jupyterInputNodeUuid": "plot-example-uuid"
2078
2078
  },
2079
2079
  {
2080
2080
  "format": "",
@@ -2091,8 +2091,8 @@
2091
2091
  "output_type": "execute_result"
2092
2092
  }
2093
2093
  ],
2094
- "jupyterInputNodeUuid": "plot-demo-uuid",
2095
- "jupyterOutputNodeUuid": "plot-demo-output-uuid"
2094
+ "jupyterInputNodeUuid": "plot-example-uuid",
2095
+ "jupyterOutputNodeUuid": "plot-example-output-uuid"
2096
2096
  },
2097
2097
  {
2098
2098
  "type": "horizontalrule",
@@ -123,6 +123,34 @@ const getDefaultExampleName = () => {
123
123
  }
124
124
  return 'NotebookExample';
125
125
  };
126
+ const parseJwtPayload = (token) => {
127
+ const parts = token.split('.');
128
+ if (parts.length !== 3 || !parts[1]) {
129
+ return null;
130
+ }
131
+ try {
132
+ const base64 = parts[1].replace(/-/g, '+').replace(/_/g, '/');
133
+ const padded = base64.padEnd(Math.ceil(base64.length / 4) * 4, '=');
134
+ const decoded = atob(padded);
135
+ return JSON.parse(decoded);
136
+ }
137
+ catch {
138
+ return null;
139
+ }
140
+ };
141
+ const isExpiredJwt = (token) => {
142
+ const payload = parseJwtPayload(token);
143
+ if (!payload) {
144
+ // Non-JWT tokens (for example API keys) should not be treated as expired.
145
+ return false;
146
+ }
147
+ const exp = payload.exp;
148
+ if (typeof exp !== 'number') {
149
+ return false;
150
+ }
151
+ const nowSeconds = Math.floor(Date.now() / 1000);
152
+ return nowSeconds >= exp;
153
+ };
126
154
  // Notebook-only component for iframe display - renders ONLY the notebook without any UI chrome
127
155
  const NotebookOnlyApp = () => {
128
156
  const [serviceManager, setServiceManager] = useState(null);
@@ -352,7 +380,7 @@ export const ExampleApp = () => {
352
380
  }));
353
381
  // 3) Wipe every piece of in-process agent state so the next example boots
354
382
  // with a clean slate (no leftover messages, threads, pending tool
355
- // calls, runtime snapshots, monitoring caches, or sockets).
383
+ // calls, code sandbox snapshots, monitoring caches, or sockets).
356
384
  useChatStore.getState().reset();
357
385
  useConversationStore.getState().clearAll();
358
386
  agentRuntimeStore.getState().reset();
@@ -402,6 +430,7 @@ const ExampleAppThemed = ({ selectedExample, isChangingExample, error, ExampleCo
402
430
  const logoColors = getLogoColors(themeVariant, colorMode);
403
431
  const { token, setAuth, clearAuth } = useSimpleAuthStore();
404
432
  const [showSignIn, setShowSignIn] = useState(false);
433
+ const shouldShowAuthScreen = showSignIn && !token;
405
434
  const syncTokenToIamStore = useCallback((newToken) => {
406
435
  import('@datalayer/core/lib/state').then(({ iamStore: coreIamStore }) => {
407
436
  coreIamStore.setState({ token: newToken });
@@ -411,6 +440,17 @@ const ExampleAppThemed = ({ selectedExample, isChangingExample, error, ExampleCo
411
440
  // Keep iamStore aligned with persisted auth token on app load/refresh.
412
441
  syncTokenToIamStore(token || undefined);
413
442
  }, [token, syncTokenToIamStore]);
443
+ useEffect(() => {
444
+ if (!token) {
445
+ setShowSignIn(true);
446
+ return;
447
+ }
448
+ if (isExpiredJwt(token)) {
449
+ clearAuth();
450
+ syncTokenToIamStore(undefined);
451
+ setShowSignIn(true);
452
+ }
453
+ }, [token, clearAuth, syncTokenToIamStore]);
414
454
  const handleHeaderSignIn = useCallback((newToken, handle) => {
415
455
  setAuth(newToken, handle);
416
456
  syncTokenToIamStore(newToken);
@@ -419,6 +459,7 @@ const ExampleAppThemed = ({ selectedExample, isChangingExample, error, ExampleCo
419
459
  const handleHeaderLogout = useCallback(() => {
420
460
  clearAuth();
421
461
  syncTokenToIamStore(undefined);
462
+ setShowSignIn(true);
422
463
  }, [clearAuth, syncTokenToIamStore]);
423
464
  return (_jsx(DatalayerThemeProvider, { colorMode: colorMode, theme: cfg.primerTheme, themeStyles: cfg.themeStyles, children: _jsxs(Box, { sx: {
424
465
  width: '100vw',
@@ -474,7 +515,7 @@ const ExampleAppThemed = ({ selectedExample, isChangingExample, error, ExampleCo
474
515
  const rest = availableExamples.filter(e => e.id !== 'HomeExample');
475
516
  // Classify each example into a named group.
476
517
  const groupOf = (id) => {
477
- if (id === 'AgentSpecsExample')
518
+ if (id === 'AgentspecsExample')
478
519
  return 'Personas';
479
520
  if (id.startsWith('A2Ui'))
480
521
  return 'A2UI';
@@ -516,7 +557,7 @@ const ExampleAppThemed = ({ selectedExample, isChangingExample, error, ExampleCo
516
557
  }
517
558
  const nodes = [];
518
559
  if (home) {
519
- nodes.push(_jsx("option", { value: home.id, children: home.title }, home.id));
560
+ nodes.push(_jsx("option", { value: home.id, disabled: home.id === selectedExample, children: home.title }, home.id));
520
561
  }
521
562
  let sepIndex = 0;
522
563
  for (const g of groupOrder) {
@@ -525,25 +566,24 @@ const ExampleAppThemed = ({ selectedExample, isChangingExample, error, ExampleCo
525
566
  continue;
526
567
  nodes.push(_jsxs("option", { disabled: true, value: `__sep_${sepIndex}`, children: ["\u2500\u2500\u2500\u2500\u2500\u2500 ", g, " \u2500\u2500\u2500\u2500\u2500\u2500"] }, `__sep_${sepIndex++}`));
527
568
  for (const example of items) {
528
- nodes.push(_jsx("option", { value: example.id, children: example.title }, example.id));
569
+ nodes.push(_jsx("option", { value: example.id, disabled: example.id === selectedExample, children: example.title }, example.id));
529
570
  }
530
571
  }
531
572
  return _jsx(_Fragment, { children: nodes });
532
- })() }), isChangingExample && (_jsx(Box, { as: "span", sx: { color: 'fg.muted', fontSize: 0 }, children: "Loading\u2026" })), error && (_jsxs(Box, { as: "span", sx: { color: 'danger.fg', fontSize: 0 }, children: ["Error: ", error] }))] }), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 3 }, children: [_jsx(AppearanceControlsWithStore, { useStore: useExampleThemeStore }), _jsx(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: token ? (_jsxs(_Fragment, { children: [_jsx(UserBadge, { token: token, variant: "small" }), _jsx(Button, { size: "small", variant: "invisible", onClick: handleHeaderLogout, leadingVisual: SignOutIcon, sx: { color: 'fg.muted' }, children: "Sign out" })] })) : (_jsx(Button, { size: "small", variant: "invisible", onClick: () => setShowSignIn(true), leadingVisual: SignInIcon, sx: { color: 'fg.muted' }, children: "Sign in" })) }), _jsx(Box, { as: "a", href: "https://datalayer.ai", target: "_blank", rel: "noopener noreferrer", "aria-label": "Open Datalayer website", sx: { display: 'inline-flex', alignItems: 'center' }, children: _jsx(DatalayerLogoText, { size: 24, variant: themeVariant, colorMode: colorMode, primaryColor: logoColors.primary, secondaryColor: logoColors.secondary, textColor: logoColors.textColor, primaryGradient: logoColors.primaryGradient, secondaryGradient: logoColors.secondaryGradient, gradient: true }) })] })] }), showSignIn && !token && (_jsx(Box, { sx: {
533
- position: 'fixed',
534
- top: 60,
535
- left: 0,
536
- right: 0,
537
- bottom: 0,
538
- zIndex: 150,
539
- bg: 'canvas.backdrop',
540
- p: 3,
541
- overflow: 'auto',
542
- }, children: _jsxs(Box, { sx: { maxWidth: 640, mx: 'auto' }, children: [_jsx(SignInSimple, { onSignIn: handleHeaderSignIn, onApiKeySignIn: apiKey => handleHeaderSignIn(apiKey, 'api-key-user'), title: "Agent Runtimes Examples", description: "Sign in to run authenticated examples and tools.", leadingIcon: _jsx(HomeIcon, { size: 24 }) }), _jsx(Box, { sx: { mt: 2, display: 'flex', justifyContent: 'center' }, children: _jsx(Button, { size: "small", variant: "invisible", onClick: () => setShowSignIn(false), children: "Cancel" }) })] }) })), _jsx(Box, { sx: {
573
+ })() }), isChangingExample && (_jsx(Box, { as: "span", sx: { color: 'fg.muted', fontSize: 0 }, children: "Loading\u2026" })), error && (_jsxs(Box, { as: "span", sx: { color: 'danger.fg', fontSize: 0 }, children: ["Error: ", error] }))] }), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 3 }, children: [_jsx(AppearanceControlsWithStore, { useStore: useExampleThemeStore }), _jsx(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: token ? (_jsxs(_Fragment, { children: [_jsx(UserBadge, { token: token, variant: "small", onTokenExpired: () => {
574
+ handleHeaderLogout();
575
+ setShowSignIn(true);
576
+ } }), _jsx(Button, { size: "small", variant: "invisible", onClick: handleHeaderLogout, leadingVisual: SignOutIcon, sx: { color: 'fg.muted' }, children: "Sign out" })] })) : (_jsx(Button, { size: "small", variant: "invisible", onClick: () => setShowSignIn(true), leadingVisual: SignInIcon, sx: { color: 'fg.muted' }, children: "Sign in" })) }), _jsx(Box, { as: "a", href: "https://datalayer.ai", target: "_blank", rel: "noopener noreferrer", "aria-label": "Open Datalayer website", sx: { display: 'inline-flex', alignItems: 'center' }, children: _jsx(DatalayerLogoText, { size: 24, variant: themeVariant, colorMode: colorMode, primaryColor: logoColors.primary, secondaryColor: logoColors.secondary, textColor: logoColors.textColor, primaryGradient: logoColors.primaryGradient, secondaryGradient: logoColors.secondaryGradient, gradient: true }) })] })] }), _jsx(Box, { sx: {
543
577
  marginTop: '60px',
544
578
  height: 'calc(100vh - 60px)',
545
579
  overflow: 'hidden',
546
- }, children: isChangingExample ? (_jsxs(Box, { sx: { p: 5, textAlign: 'center', color: 'fg.muted' }, children: [_jsxs("h3", { children: ["Loading ", selectedExample, "\u2026"] }), _jsx("p", { children: "Please wait while the example loads." })] })) : ExampleComponent ? (_jsx(ExampleWrapper, { children: _jsx(ExampleComponent, { ...exampleProps }, selectedExample) }, selectedExample)) : null })] }) }));
580
+ }, children: shouldShowAuthScreen ? (_jsx(Box, { sx: {
581
+ width: '100%',
582
+ height: '100%',
583
+ bg: 'canvas.backdrop',
584
+ p: 3,
585
+ overflow: 'auto',
586
+ }, children: _jsx(Box, { sx: { maxWidth: 640, mx: 'auto' }, children: _jsx(SignInSimple, { onSignIn: handleHeaderSignIn, onApiKeySignIn: apiKey => handleHeaderSignIn(apiKey, 'api-key-user'), title: "Agent Runtimes Examples", description: "Sign in to run authenticated examples and tools.", leadingIcon: _jsx(HomeIcon, { size: 24 }) }) }) })) : isChangingExample ? (_jsxs(Box, { sx: { p: 5, textAlign: 'center', color: 'fg.muted' }, children: [_jsxs("h3", { children: ["Loading ", selectedExample, "\u2026"] }), _jsx("p", { children: "Please wait while the example loads." })] })) : ExampleComponent ? (_jsx(ExampleWrapper, { children: _jsx(ExampleComponent, { ...exampleProps }, selectedExample) }, selectedExample)) : null })] }) }));
547
587
  };
548
588
  // Mount the app - check route to determine which app to render
549
589
  const root = document.getElementById('root');
@@ -13,6 +13,6 @@
13
13
  *
14
14
  * @example
15
15
  * uniqueAgentId('simple') // → "simple-a3f7b2" (cached)
16
- * uniqueAgentId('codemode-demo') // → "codemode-demo-k9x2m1" (cached)
16
+ * uniqueAgentId('codemode-demo') // → "codemode-example-k9x2m1" (cached)
17
17
  */
18
18
  export declare function uniqueAgentId(baseName: string): string;
@@ -32,7 +32,7 @@ function randomSlug(length = 6) {
32
32
  *
33
33
  * @example
34
34
  * uniqueAgentId('simple') // → "simple-a3f7b2" (cached)
35
- * uniqueAgentId('codemode-demo') // → "codemode-demo-k9x2m1" (cached)
35
+ * uniqueAgentId('codemode-demo') // → "codemode-example-k9x2m1" (cached)
36
36
  */
37
37
  export function uniqueAgentId(baseName) {
38
38
  const storageKey = `agent-runtimes:agentId:${baseName}`;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Resolve the base URL used by examples to call the agent-runtimes service.
3
+ * Priority: explicit override -> dedicated env -> legacy base env -> localhost.
4
+ */
5
+ export declare function useExampleAgentRuntimesUrl(override?: string): string;
@@ -0,0 +1,19 @@
1
+ /*
2
+ * Copyright (c) 2025-2026 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ import { useMemo } from 'react';
6
+ /**
7
+ * Resolve the base URL used by examples to call the agent-runtimes service.
8
+ * Priority: explicit override -> dedicated env -> legacy base env -> localhost.
9
+ */
10
+ export function useExampleAgentRuntimesUrl(override) {
11
+ return useMemo(() => {
12
+ if (override) {
13
+ return override;
14
+ }
15
+ return (import.meta.env.VITE_DATALAYER_AGENT_RUNTIMES_URL ||
16
+ import.meta.env.VITE_BASE_URL ||
17
+ 'http://localhost:8765');
18
+ }, [override]);
19
+ }
@@ -28,6 +28,20 @@ function useBaseUrl() {
28
28
  // ─── Hook ────────────────────────────────────────────────────────────
29
29
  const RECONNECT_DELAY_MS = 3_000;
30
30
  const WS_DEFAULT_PATH = `${API_BASE_PATHS.AI_AGENTS}/ws`;
31
+ const isDevTraceEnabled = () => {
32
+ try {
33
+ return Boolean(import.meta.env?.DEV);
34
+ }
35
+ catch {
36
+ return false;
37
+ }
38
+ };
39
+ const logApprovalTrace = (label, details) => {
40
+ if (!isDevTraceEnabled()) {
41
+ return;
42
+ }
43
+ console.debug(`[approval-trace] ${label}`, details);
44
+ };
31
45
  const isObject = (value) => !!value && typeof value === 'object';
32
46
  /**
33
47
  * Connect to the AI Agents generic WebSocket.
@@ -146,6 +160,17 @@ export function useAIAgentsWebSocket(options) {
146
160
  queryClient.invalidateQueries({ queryKey: ['agent-events'] });
147
161
  }
148
162
  if (event.startsWith('tool_approval_')) {
163
+ const data = msg.data;
164
+ logApprovalTrace('recv_tool_approval_event', {
165
+ event,
166
+ channel: msg.channel,
167
+ approvalId: typeof data?.id === 'string'
168
+ ? data.id
169
+ : typeof data?.approval_id === 'string'
170
+ ? data.approval_id
171
+ : undefined,
172
+ status: typeof data?.status === 'string' ? data.status : undefined,
173
+ });
149
174
  queryClient.invalidateQueries({ queryKey: ['tool-approvals'] });
150
175
  }
151
176
  if (event.startsWith('notification_')) {
@@ -231,6 +256,16 @@ export function useAIAgentsWebSocket(options) {
231
256
  return false;
232
257
  }
233
258
  try {
259
+ if (isObject(payload) && payload.type === 'tool_approval_decision') {
260
+ logApprovalTrace('send_tool_approval_decision', {
261
+ approvalId: typeof payload.approvalId === 'string'
262
+ ? payload.approvalId
263
+ : undefined,
264
+ approved: typeof payload.approved === 'boolean'
265
+ ? payload.approved
266
+ : undefined,
267
+ });
268
+ }
234
269
  ws.send(typeof payload === 'string' ? payload : JSON.stringify(payload));
235
270
  return true;
236
271
  }
@@ -4,6 +4,7 @@ import type { AgentConnection } from '../types/connection';
4
4
  import type { AgentStatus, AgentRuntimeData } from '../types/agents';
5
5
  import type { CreateAgentRuntimeRequest, AgentLifecycleState, CreateRuntimeApiResponse } from '../types/agents-lifecycle';
6
6
  import { ServiceManager } from '@jupyterlab/services/lib/manager';
7
+ export type RuntimeCreationTarget = 'backend-services' | 'local-agent-runtimes';
7
8
  /**
8
9
  * Options for the useAgents hook.
9
10
  */
@@ -18,6 +19,14 @@ export interface UseAgentOptions {
18
19
  autoStart?: boolean;
19
20
  /** Full agent spec object (persisted with checkpoints) */
20
21
  agentSpec?: Record<string, any>;
22
+ /**
23
+ * Where runtime create/list operations should be sent.
24
+ * - `backend-services`: use backend runtimes service URL
25
+ * - `local-agent-runtimes`: use local agent-runtimes URL
26
+ */
27
+ runtimeCreationTarget?: RuntimeCreationTarget;
28
+ /** Explicit base URL for runtime create/list operations. */
29
+ runtimeCreationBaseUrl?: string;
21
30
  }
22
31
  /**
23
32
  * Return type for the useAgents hook.
@@ -53,6 +62,10 @@ export interface UseAgentReturn {
53
62
  isReady: boolean;
54
63
  /** Error if any */
55
64
  error: string | null;
65
+ /** Effective runtime creation target mode. */
66
+ runtimeCreationTarget: RuntimeCreationTarget;
67
+ /** Effective base URL used for runtime create/list operations. */
68
+ runtimeCreationBaseUrl: string;
56
69
  }
57
70
  /** Default query options for all agent runtime queries. */
58
71
  export declare const AGENT_QUERY_OPTIONS: {
@@ -87,7 +100,7 @@ export declare const agentQueryKeys: {
87
100
  * // Connect mode — attach to an existing runtime
88
101
  * const { isReady, endpoint, connectToRuntime } = useAgents({
89
102
  * autoCreateAgent: true,
90
- * agentConfig: { model: 'bedrock:us.anthropic.claude-3-5-haiku-20241022-v1:0' },
103
+ * agentConfig: { model: 'bedrock:us.anthropic.claude-sonnet-4-5-20250929-v1:0' },
91
104
  * });
92
105
  *
93
106
  * // Lifecycle mode — full lifecycle with agentSpecId
@@ -105,7 +118,15 @@ export declare function useAgentRuntimes(options?: UseAgentOptions): UseAgentRet
105
118
  * The backend returns active runtimes from the operator **plus** paused
106
119
  * runtimes synthesised from Solr checkpoint records (with ``status="paused"``).
107
120
  */
108
- export declare function useAgentRuntimesQuery(): import("@tanstack/react-query").UseQueryResult<AgentRuntimeData[], Error>;
121
+ export declare function useAgentRuntimesQuery(scope?: {
122
+ selectedUserUid?: string;
123
+ selectedOrganizationUid?: string;
124
+ selectedTeamUid?: string;
125
+ selectedAgentUid?: string;
126
+ }, queryOptions?: {
127
+ enabled?: boolean;
128
+ refetchInterval?: number | false;
129
+ }): import("@tanstack/react-query").UseQueryResult<AgentRuntimeData[], Error>;
109
130
  /**
110
131
  * Hook to fetch a single agent runtime by pod name.
111
132
  */
@@ -149,7 +170,15 @@ export interface UseAgentsRuntimesReturn {
149
170
  /**
150
171
  * Consolidated runtime list and mutations.
151
172
  */
152
- export declare function useAgentsRuntimes(): UseAgentsRuntimesReturn;
173
+ export declare function useAgentsRuntimes(scope?: {
174
+ selectedUserUid?: string;
175
+ selectedOrganizationUid?: string;
176
+ selectedTeamUid?: string;
177
+ selectedAgentUid?: string;
178
+ }, queryOptions?: {
179
+ enabled?: boolean;
180
+ refetchInterval?: number | false;
181
+ }): UseAgentsRuntimesReturn;
153
182
  export interface UseAgentRuntimeWebSocketOptions {
154
183
  /** Enable/disable the connection. Defaults to `true`. */
155
184
  enabled?: boolean;