@datalayer/agent-runtimes 1.0.19 → 1.0.21

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 (141) hide show
  1. package/README.md +11 -3
  2. package/lib/AgentNode.js +141 -40
  3. package/lib/App.js +2 -2
  4. package/lib/agent-node/AgentNodeGallery.js +188 -25
  5. package/lib/api/runtimes/runtimes.d.ts +57 -0
  6. package/lib/api/runtimes/runtimes.js +55 -1
  7. package/lib/chat/Chat.d.ts +1 -1
  8. package/lib/chat/Chat.js +2 -2
  9. package/lib/chat/base/ChatBase.js +50 -13
  10. package/lib/chat/document/EphemeralDocument.d.ts +5 -1
  11. package/lib/chat/document/EphemeralDocument.js +7 -5
  12. package/lib/chat/header/ChatHeaderBase.d.ts +3 -1
  13. package/lib/chat/header/ChatHeaderBase.js +5 -3
  14. package/lib/chat/messages/ChatMessageList.d.ts +19 -0
  15. package/lib/chat/messages/ChatMessageList.js +180 -9
  16. package/lib/chat/notebook/EphemeralNotebook.d.ts +5 -1
  17. package/lib/chat/notebook/EphemeralNotebook.js +9 -6
  18. package/lib/chat/prompt/InputPrompt.js +1 -1
  19. package/lib/chat/tools/SubagentActivity.d.ts +20 -0
  20. package/lib/chat/tools/SubagentActivity.js +154 -0
  21. package/lib/chat/tools/index.d.ts +1 -0
  22. package/lib/chat/tools/index.js +1 -0
  23. package/lib/chat/usage/TokenUsageBar.js +3 -3
  24. package/lib/client/AgentRuntimesClient.d.ts +5 -0
  25. package/lib/client/AgentsMixin.js +3 -1
  26. package/lib/client/mixins/RuntimesMixin.d.ts +12 -0
  27. package/lib/client/mixins/RuntimesMixin.js +24 -1
  28. package/lib/components/AgentSummary.d.ts +1 -0
  29. package/lib/components/AgentSummary.js +66 -10
  30. package/lib/components/runtimes/RuntimePickerBase.js +64 -29
  31. package/lib/components/runtimes/RuntimePickerCell.js +1 -1
  32. package/lib/components/runtimes/RuntimePickerNotebook.js +1 -1
  33. package/lib/components/runtimes/RuntimeSimplePicker.js +3 -2
  34. package/lib/components/runtimes/RuntimeUtils.js +2 -2
  35. package/lib/context/GraphFlowChart.js +1 -1
  36. package/lib/context/TokenUsageChart.js +1 -1
  37. package/lib/context/TurnGraphChart.js +2 -2
  38. package/lib/examples/A2UiAgentExample.js +4 -4
  39. package/lib/examples/A2UiComponentsGalleryExample.js +3 -3
  40. package/lib/examples/A2UiContactCardExample.js +3 -3
  41. package/lib/examples/A2UiRestaurantExample.js +2 -2
  42. package/lib/examples/A2UiViewerExample.js +3 -3
  43. package/lib/examples/AgUiAgenticExample.js +3 -3
  44. package/lib/examples/AgUiBackendToolRenderingExample.js +2 -2
  45. package/lib/examples/AgUiHaikuGenUiExample.js +3 -3
  46. package/lib/examples/AgUiHumanInTheLoopExample.js +5 -5
  47. package/lib/examples/AgUiSharedStateExample.js +3 -3
  48. package/lib/examples/AgUiToolsBasedGenUiExample.js +7 -5
  49. package/lib/examples/AgentCheckpointsExample.js +6 -5
  50. package/lib/examples/{AgentSandboxExample.d.ts → AgentCodeSandboxExample.d.ts} +4 -4
  51. package/lib/examples/{AgentSandboxExample.js → AgentCodeSandboxExample.js} +10 -9
  52. package/lib/examples/AgentCodeSandboxesExample.js +2 -2
  53. package/lib/examples/AgentCodemodeExample.js +3 -3
  54. package/lib/examples/AgentCompactionExample.d.ts +12 -0
  55. package/lib/examples/AgentCompactionExample.js +244 -0
  56. package/lib/examples/AgentEvalsExample.js +10 -20
  57. package/lib/examples/AgentGuardrailsExample.js +2 -2
  58. package/lib/examples/AgentHooksExample.js +1 -1
  59. package/lib/examples/AgentInferenceProviderExample.js +6 -8
  60. package/lib/examples/AgentLoopExample.js +3 -3
  61. package/lib/examples/AgentMCPExample.js +3 -3
  62. package/lib/examples/AgentMemoryExample.d.ts +4 -2
  63. package/lib/examples/AgentMemoryExample.js +93 -10
  64. package/lib/examples/AgentMonitoringExample.js +2 -2
  65. package/lib/examples/AgentNotificationsExample.js +1 -1
  66. package/lib/examples/AgentOtelExample.d.ts +2 -3
  67. package/lib/examples/AgentOtelExample.js +7 -12
  68. package/lib/examples/AgentOutputsExample.js +5 -5
  69. package/lib/examples/AgentParametersExample.js +3 -3
  70. package/lib/examples/AgentSkillsExample.js +4 -4
  71. package/lib/examples/AgentSubagentsExample.d.ts +2 -2
  72. package/lib/examples/AgentSubagentsExample.js +43 -34
  73. package/lib/examples/AgentToolApprovalsExample.js +1 -1
  74. package/lib/examples/AgentTriggersExample.js +9 -11
  75. package/lib/examples/AgentspecsExample.js +13 -5
  76. package/lib/examples/CellExample.d.ts +6 -0
  77. package/lib/examples/CellExample.js +84 -0
  78. package/lib/examples/ChatCustomExample.js +1 -1
  79. package/lib/examples/ChatExample.js +1 -1
  80. package/lib/examples/ChatStandaloneExample.js +2 -2
  81. package/lib/examples/HomeExample.js +29 -28
  82. package/lib/examples/Lexical2Example.js +2 -2
  83. package/lib/examples/LexicalAgentExample.js +1 -1
  84. package/lib/examples/LexicalAgentSidebarExample.js +2 -2
  85. package/lib/examples/NotebookAgentSidebarExample.d.ts +1 -1
  86. package/lib/examples/NotebookAgentSidebarExample.js +5 -4
  87. package/lib/examples/NotebookCollaborationExample.js +3 -3
  88. package/lib/examples/NotebookExample.js +2 -2
  89. package/lib/examples/components/ExampleWrapper.js +5 -0
  90. package/lib/examples/components/Header.js +2 -2
  91. package/lib/examples/components/HeaderControls.js +1 -1
  92. package/lib/examples/components/LexicalEditor.js +1 -1
  93. package/lib/examples/components/MainContent.js +1 -1
  94. package/lib/examples/components/MockFileBrowser.js +8 -8
  95. package/lib/examples/components/TimeTravel.js +1 -1
  96. package/lib/examples/components/haiku/HaikuDisplay.js +2 -2
  97. package/lib/examples/example-selector.js +4 -3
  98. package/lib/examples/hooks/useExampleAgentRuntime.js +11 -1
  99. package/lib/examples/hooks/useExampleAgentRuntimes.d.ts +7 -0
  100. package/lib/examples/hooks/useExampleAgentRuntimes.js +82 -0
  101. package/lib/examples/index.d.ts +2 -1
  102. package/lib/examples/index.js +2 -1
  103. package/lib/examples/main.js +359 -46
  104. package/lib/examples/utils/agentSummaryStore.d.ts +17 -0
  105. package/lib/examples/utils/themedProvider.js +32 -2
  106. package/lib/examples/utils/useExampleAgentRuntimesUrl.js +2 -1
  107. package/lib/examples2/NotebookMutationsKernel.js +6 -3
  108. package/lib/examples2/NotebookMutationsServiceManager.js +6 -3
  109. package/lib/examples2/ReactRouterExample.js +5 -5
  110. package/lib/examples2/main.js +38 -0
  111. package/lib/hooks/useAIAgentsWebSocket.js +35 -0
  112. package/lib/hooks/useAgentRuntimes.d.ts +22 -0
  113. package/lib/hooks/useAgentRuntimes.js +192 -5
  114. package/lib/hooks/useCheckpoints.js +2 -2
  115. package/lib/hooks/useToolApprovals.d.ts +10 -4
  116. package/lib/hooks/useToolApprovals.js +11 -5
  117. package/lib/models/Runtime.d.ts +10 -8
  118. package/lib/models/RuntimeDTO.d.ts +5 -3
  119. package/lib/models/RuntimeDTO.js +3 -3
  120. package/lib/runtimes/actions.js +3 -1
  121. package/lib/runtimes/apis.d.ts +7 -0
  122. package/lib/specs/agents/agents.d.ts +51 -0
  123. package/lib/specs/agents/agents.js +3389 -94
  124. package/lib/specs/models.d.ts +2 -0
  125. package/lib/specs/models.js +37 -0
  126. package/lib/stores/agentRuntimeStore.d.ts +32 -1
  127. package/lib/stores/agentRuntimeStore.js +65 -1
  128. package/lib/stores/index.d.ts +1 -1
  129. package/lib/stores/index.js +1 -1
  130. package/lib/types/agents.d.ts +9 -3
  131. package/lib/types/agentspecs.d.ts +2 -0
  132. package/lib/types/chat.d.ts +12 -0
  133. package/lib/types/models.d.ts +5 -0
  134. package/lib/types/stream.d.ts +58 -1
  135. package/package.json +4 -4
  136. package/scripts/codegen/__pycache__/versioning.cpython-313.pyc +0 -0
  137. package/scripts/codegen/generate_agents.py +7 -0
  138. package/scripts/codegen/generate_models.py +22 -9
  139. package/scripts/gen_workers.py +340 -0
  140. package/lib/examples/CellSimpleExample.d.ts +0 -6
  141. package/lib/examples/CellSimpleExample.js +0 -20
package/README.md CHANGED
@@ -171,6 +171,13 @@ pip install -e ".[chat]" # chat-related extras
171
171
  pip install -e ".[docs]" # docs build dependencies
172
172
  ```
173
173
 
174
+ For deterministic installs in CI (and to avoid resolver backtracking), use the
175
+ version constraints file:
176
+
177
+ ```bash
178
+ pip install -c constraints/py313.txt -e .
179
+ ```
180
+
174
181
  ### Run
175
182
 
176
183
  ```bash
@@ -262,10 +269,11 @@ make examples:prod DATALAYER_URL=https://prod2.datalayer.run
262
269
  If you are developing against a local Plane (`plane local`), use:
263
270
 
264
271
  ```bash
265
- make examples:proxy
272
+ make example-local
266
273
  ```
267
274
 
268
- This points each `DATALAYER_*_URL` at the matching localhost port exposed by
275
+ This points each `DATALAYER_*_URL` (and its `VITE_*` frontend counterpart, so
276
+ both http and ws traffic stay local) at the matching localhost port exposed by
269
277
  `plane local` (see `services/plane/datalayer_plane/sbin/local.sh`):
270
278
 
271
279
  | Variable | Default port |
@@ -286,7 +294,7 @@ This points each `DATALAYER_*_URL` at the matching localhost port exposed by
286
294
  Override any port on the command line, e.g.:
287
295
 
288
296
  ```bash
289
- PLANE_LOCAL_IAM_URL=http://localhost:9701 make examples:proxy
297
+ PLANE_LOCAL_IAM_URL=http://localhost:9701 make example-local
290
298
  ```
291
299
 
292
300
  On the main page, you’ll find an example gallery (cards) that break things down into practical building blocks:
package/lib/AgentNode.js CHANGED
@@ -3,13 +3,15 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
3
3
  * Copyright (c) 2025-2026 Datalayer, Inc.
4
4
  * Distributed under the terms of the Modified BSD License.
5
5
  */
6
- import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
6
+ import { useCallback, useEffect, useMemo, useRef, useState, } from 'react';
7
7
  import { useQueryClient } from '@tanstack/react-query';
8
- import { DatalayerLogoText, DatalayerThemeProvider, getLogoColors, setupPrimerPortals, themeConfigs, } from '@datalayer/primer-addons';
9
- import { AppearanceControlsWithStore } from '@datalayer/primer-addons/lib/components/appearance';
10
- import { ActionList, ActionMenu, Avatar, Box, Button, FormControl, Heading, Label, PageHeader, PageLayout, Text, } from '@primer/react';
11
- import { CommentIcon, HomeIcon, KeyAsteriskIcon, LockIcon, MoonIcon, PeopleIcon, PersonIcon, GearIcon, RocketIcon, SignOutIcon, } from '@primer/octicons-react';
8
+ import { AiAgentIcon, AlienIcon } from '@datalayer/icons-react';
9
+ import { DatalayerLogoText, DatalayerThemeProvider, getColorPalette, getLogoColors, setupPrimerPortals, themeConfigs, } from '@datalayer/primer-addons';
10
+ import { AppearanceMenu } from '@datalayer/primer-addons/lib/components/appearance';
11
+ import { ActionList, ActionMenu, Box, Button, Heading, Label, PageHeader, PageLayout, Text, } from '@primer/react';
12
+ import { CommentIcon, HomeIcon, KeyAsteriskIcon, LockIcon, MoonIcon, PeopleIcon, PersonIcon, GearIcon, SignOutIcon, } from '@primer/octicons-react';
12
13
  import { SignInSimple } from '@datalayer/core/lib/views/iam';
14
+ import { UserAvatar } from '@datalayer/core/lib/components/avatars';
13
15
  import { UserBadge } from '@datalayer/core/lib/views/profile';
14
16
  import { useSimpleAuthStore } from '@datalayer/core/lib/views/otel';
15
17
  import { useIAMStore } from '@datalayer/core/lib/state';
@@ -141,21 +143,33 @@ const DEFAULT_CONFIGURATION = {
141
143
  * but assembled exclusively from core building blocks so agent-runtimes does
142
144
  * not pull in the `ui` package.
143
145
  */
144
- function AgentNodeProfileView({ token, onTokenExpired, }) {
146
+ function AgentNodeProfileView({ token, onTokenExpired, avatarFallbackBackground, avatarFallbackForeground, }) {
145
147
  const user = useIAMStore(state => state.user);
148
+ const hasRealAvatar = (url) => {
149
+ if (!url) {
150
+ return false;
151
+ }
152
+ if (url.startsWith('https://www.gravatar.com/avatar')) {
153
+ return false;
154
+ }
155
+ return true;
156
+ };
146
157
  const display = useMemo(() => {
147
158
  if (!user)
148
159
  return null;
149
160
  const u = user;
150
- const displayName = [u.first_name, u.last_name].filter(Boolean).join(' ').trim() ||
151
- u.display_name ||
152
- u.name ||
153
- u.handle ||
154
- u.email ||
155
- 'Datalayer user';
161
+ const displayName = u.display_name ||
162
+ u.displayName ||
163
+ u.profile?.display_name ||
164
+ u.profile?.displayName ||
165
+ u.full_name ||
166
+ u.fullName ||
167
+ [u.first_name, u.last_name].filter(Boolean).join(' ').trim() ||
168
+ '';
156
169
  const username = u.username || u.handle || (u.email ? String(u.email).split('@')[0] : '');
170
+ const headingDisplayName = displayName || username || u.email || 'Datalayer user';
157
171
  const initials = u.initials ||
158
- String(displayName)
172
+ String(headingDisplayName)
159
173
  .split(/\s+/)
160
174
  .filter(Boolean)
161
175
  .slice(0, 2)
@@ -165,6 +179,7 @@ function AgentNodeProfileView({ token, onTokenExpired, }) {
165
179
  id: String(u.id || u.uid || ''),
166
180
  username,
167
181
  displayName,
182
+ headingDisplayName,
168
183
  initials,
169
184
  origin: String(u.origin || 'datalayer'),
170
185
  handle: u.handle ? `@${u.handle}` : '',
@@ -181,22 +196,42 @@ function AgentNodeProfileView({ token, onTokenExpired, }) {
181
196
  display: 'flex',
182
197
  flexDirection: 'column',
183
198
  gap: 3,
184
- }, children: !token ? (_jsx(Text, { sx: { color: 'fg.muted' }, children: "Sign in to view your profile." })) : !display ? (_jsx(Text, { sx: { color: 'fg.muted' }, children: "Loading profile\u2026" })) : (_jsxs(_Fragment, { children: [_jsx(Heading, { sx: { fontSize: 2, mb: 2 }, children: "Identity" }), _jsx(Box, { sx: { textAlign: 'left' }, children: _jsx(UserBadge, { token: token, variant: "small", onTokenExpired: onTokenExpired }) }), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 3 }, children: [display.avatarUrl ? (_jsx(Avatar, { src: display.avatarUrl, size: 72, alt: display.displayName })) : (_jsx(Box, { sx: {
185
- width: 72,
186
- height: 72,
187
- borderRadius: '50%',
188
- bg: 'canvas.subtle',
189
- display: 'inline-flex',
190
- alignItems: 'center',
191
- justifyContent: 'center',
192
- color: 'fg.muted',
193
- }, children: _jsx(PersonIcon, { size: 30 }) })), _jsxs(Box, { sx: { display: 'flex', flexDirection: 'column' }, children: [_jsx(Heading, { sx: { fontSize: 3, mb: 1 }, children: display.displayName }), display.handle && (_jsx(Text, { sx: { color: 'fg.muted' }, children: display.handle })), display.email && (_jsx(Text, { sx: { color: 'fg.muted', fontSize: 1 }, children: display.email }))] })] }), display.id && (_jsx(Box, { sx: { mt: 2 }, children: _jsx(Label, { size: "large", variant: "secondary", children: display.id }) })), _jsxs(Box, { sx: {
199
+ }, children: !token ? (_jsx(Text, { sx: { color: 'fg.muted' }, children: "Sign in to view your profile." })) : !display ? (_jsx(Text, { sx: { color: 'fg.muted' }, children: "Loading profile\u2026" })) : (_jsxs(_Fragment, { children: [_jsx(Heading, { sx: { fontSize: 2, mb: 2 }, children: "Profile" }), _jsxs(Box, { sx: {
194
200
  display: 'grid',
195
- gridTemplateColumns: '1fr 2fr',
196
- rowGap: 2,
197
- columnGap: 3,
198
- maxWidth: 560,
199
- }, children: [_jsx(Text, { sx: { fontWeight: 'bold' }, children: "Username" }), _jsx(Text, { children: display.username || '-' }), _jsx(Text, { sx: { fontWeight: 'bold' }, children: "Display name" }), _jsx(Text, { children: display.displayName || '-' }), _jsx(Text, { sx: { fontWeight: 'bold' }, children: "Initials" }), _jsx(Text, { children: display.initials || '-' }), _jsx(Text, { sx: { fontWeight: 'bold' }, children: "Origin" }), _jsx(Text, { children: display.origin || '-' })] }), display.roles.length > 0 && (_jsx(Box, { sx: { display: 'flex', gap: 2, flexWrap: 'wrap' }, children: display.roles.map(role => (_jsx(Label, { size: "small", variant: "secondary", children: role }, role))) }))] })) }));
201
+ gridTemplateColumns: [
202
+ '1fr',
203
+ null,
204
+ 'minmax(280px, 1fr) minmax(320px, 2fr)',
205
+ ],
206
+ gap: 4,
207
+ alignItems: 'start',
208
+ }, children: [_jsxs(Box, { sx: {
209
+ border: '1px solid',
210
+ borderColor: 'border.default',
211
+ borderRadius: 2,
212
+ p: 3,
213
+ display: 'flex',
214
+ flexDirection: 'column',
215
+ gap: 3,
216
+ }, children: [_jsx(Box, { sx: { textAlign: 'left' }, children: _jsx(UserBadge, { token: token, variant: "small", onTokenExpired: onTokenExpired }) }), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 3 }, children: [hasRealAvatar(display.avatarUrl) ? (_jsx(UserAvatar, { avatarUrl: display.avatarUrl, size: 72, square: false })) : (_jsx(Box, { sx: {
217
+ width: 72,
218
+ height: 72,
219
+ borderRadius: '50%',
220
+ bg: avatarFallbackBackground || 'accent.subtle',
221
+ display: 'flex',
222
+ alignItems: 'center',
223
+ justifyContent: 'center',
224
+ '--datalayer-icon-fg': avatarFallbackForeground || 'accent.fg',
225
+ }, children: _jsx(AlienIcon, { size: 34, themed: true, colormode: true }) })), _jsxs(Box, { sx: { display: 'flex', flexDirection: 'column' }, children: [_jsx(Heading, { sx: { fontSize: 3, mb: 1 }, children: display.headingDisplayName }), display.handle && (_jsx(Text, { sx: { color: 'fg.muted' }, children: display.handle }))] })] }), display.id && (_jsx(Box, { children: _jsx(Label, { size: "large", variant: "secondary", children: display.id }) }))] }), _jsxs(Box, { sx: {
226
+ border: '1px solid',
227
+ borderColor: 'border.default',
228
+ borderRadius: 2,
229
+ p: 3,
230
+ display: 'grid',
231
+ gridTemplateColumns: '1fr 2fr',
232
+ rowGap: 2,
233
+ columnGap: 3,
234
+ }, children: [_jsx(Text, { sx: { fontWeight: 'bold' }, children: "Username" }), _jsx(Text, { children: display.username || '-' }), _jsx(Text, { sx: { fontWeight: 'bold' }, children: "Display name" }), _jsx(Text, { children: display.displayName || '-' }), _jsx(Text, { sx: { fontWeight: 'bold' }, children: "Email" }), _jsx(Text, { children: display.email || '-' }), _jsx(Text, { sx: { fontWeight: 'bold' }, children: "Initials" }), _jsx(Text, { children: display.initials || '-' }), _jsx(Text, { sx: { fontWeight: 'bold' }, children: "Origin" }), _jsx(Text, { children: display.origin || '-' }), _jsx(Text, { sx: { fontWeight: 'bold' }, children: "Roles" }), _jsx(Box, { sx: { display: 'flex', gap: 1, flexWrap: 'wrap' }, children: display.roles.length > 0 ? (display.roles.map(role => (_jsx(Label, { size: "small", variant: "secondary", children: role }, role)))) : (_jsx(Text, { children: "-" })) })] })] })] })) }));
200
235
  }
201
236
  export function AgentNode() {
202
237
  const { token, setAuth, clearAuth } = useSimpleAuthStore();
@@ -205,6 +240,8 @@ export function AgentNode() {
205
240
  const queryClient = useQueryClient();
206
241
  const iamUser = useIAMStore(state => state.user);
207
242
  const { colorMode, theme: themeVariant } = useAgentNodeThemeStore();
243
+ const setColorMode = useAgentNodeThemeStore(state => state.setColorMode);
244
+ const setTheme = useAgentNodeThemeStore(state => state.setTheme);
208
245
  const cfg = themeConfigs[themeVariant];
209
246
  const logoColors = getLogoColors(themeVariant, colorMode);
210
247
  const resolvedMode = colorMode === 'auto'
@@ -215,6 +252,7 @@ export function AgentNode() {
215
252
  : colorMode === 'dark'
216
253
  ? 'dark'
217
254
  : 'light';
255
+ const avatarPalette = getColorPalette(themeVariant, resolvedMode);
218
256
  const authGradient = cfg.cardGradient[resolvedMode];
219
257
  const [step, setStep] = useState('auth');
220
258
  const [selectedAgentId, setSelectedAgentId] = useState('default');
@@ -282,13 +320,21 @@ export function AgentNode() {
282
320
  }
283
321
  : undefined,
284
322
  };
285
- }, [configuration.collaboration_document_uid, token, collaborationDocumentUser]);
323
+ }, [
324
+ configuration.collaboration_document_uid,
325
+ token,
326
+ collaborationDocumentUser,
327
+ ]);
286
328
  const [inferenceProvider, setInferenceProvider] = useState('datalayer');
287
329
  const [inferenceModels, setInferenceModels] = useState([]);
288
330
  const [inferenceDefaultModel, setInferenceDefaultModel] = useState(null);
289
331
  const [configurationLoaded, setConfigurationLoaded] = useState(false);
332
+ const [isActiveAgentRunning, setIsActiveAgentRunning] = useState(false);
290
333
  const chatRestoreAttemptRef = useRef('');
291
- const hasActiveAgent = Boolean(String(configuration.active_agent_id || '').trim());
334
+ const hasActiveAgent = Boolean(String(configuration.active_agent_id || '').trim()) &&
335
+ isActiveAgentRunning;
336
+ const isSaasOnlyChat = configuration.chat_access_mode === 'saas_only' ||
337
+ configuration.deployment_target === 'aws';
292
338
  // ── Local sandbox runtime override for the ephemeral surfaces ─────────────
293
339
  // In the node-local webapp the agent's Jupyter sandbox is a LOCAL server, not
294
340
  // a Kubernetes pod resolvable by `pod_name`, so the ephemeral notebook and
@@ -437,7 +483,9 @@ export function AgentNode() {
437
483
  };
438
484
  }, [step, selectedAgentId, token]);
439
485
  const chatTitle = agentSpecInfo?.name || 'Agent Node Chat';
440
- const chatDescription = agentSpecInfo?.welcomeMessage || agentSpecInfo?.description || 'Node-local chat';
486
+ const chatDescription = agentSpecInfo?.welcomeMessage ||
487
+ agentSpecInfo?.description ||
488
+ 'Node-local chat';
441
489
  const chatSuggestions = agentSpecInfo?.suggestions && agentSpecInfo.suggestions.length > 0
442
490
  ? agentSpecInfo.suggestions.map(s => ({ title: s, message: s }))
443
491
  : undefined;
@@ -698,6 +746,11 @@ export function AgentNode() {
698
746
  setStep('auth');
699
747
  }
700
748
  }, [token, step]);
749
+ useEffect(() => {
750
+ if (!token || !String(configuration.active_agent_id || '').trim()) {
751
+ setIsActiveAgentRunning(false);
752
+ }
753
+ }, [token, configuration.active_agent_id]);
701
754
  useEffect(() => {
702
755
  if (!token || !configurationLoaded) {
703
756
  return;
@@ -733,20 +786,30 @@ export function AgentNode() {
733
786
  const id = String(agent?.agent_id || agent?.id || '').trim();
734
787
  return id === activeAgentId;
735
788
  });
789
+ setIsActiveAgentRunning(running);
736
790
  if (running) {
737
791
  setSelectedAgentId(activeAgentId);
738
792
  setConfiguration(prev => prev.mode === 'private' ? prev : { ...prev, mode: 'private' });
739
793
  setStep('chat');
740
794
  }
795
+ else if (selectedAgentId === activeAgentId) {
796
+ setSelectedAgentId('default');
797
+ }
741
798
  }
742
799
  catch {
800
+ setIsActiveAgentRunning(false);
743
801
  // Best-effort restore only.
744
802
  }
745
803
  })();
746
804
  return () => {
747
805
  cancelled = true;
748
806
  };
749
- }, [token, configurationLoaded, configuration.active_agent_id]);
807
+ }, [
808
+ token,
809
+ configurationLoaded,
810
+ configuration.active_agent_id,
811
+ selectedAgentId,
812
+ ]);
750
813
  useEffect(() => {
751
814
  // If a persisted session is already authenticated on first load,
752
815
  // skip the auth screen and land on the agents gallery.
@@ -764,6 +827,11 @@ export function AgentNode() {
764
827
  setStep('gallery');
765
828
  }
766
829
  }, [step, hasActiveAgent]);
830
+ useEffect(() => {
831
+ if (step === 'chat' && isSaasOnlyChat) {
832
+ setStep('gallery');
833
+ }
834
+ }, [step, isSaasOnlyChat]);
767
835
  const handleSignIn = (newToken, handle) => {
768
836
  setAutoBootstrapDisabled(false);
769
837
  setDisableAutoBootstrap(false);
@@ -860,7 +928,7 @@ export function AgentNode() {
860
928
  if (nextStep === 'gallery')
861
929
  return true;
862
930
  if (nextStep === 'chat') {
863
- return configuration.mode === 'private' && hasActiveAgent;
931
+ return (configuration.mode === 'private' && hasActiveAgent && !isSaasOnlyChat);
864
932
  }
865
933
  return true;
866
934
  };
@@ -888,7 +956,7 @@ export function AgentNode() {
888
956
  gap: 2,
889
957
  fontSize: 2,
890
958
  lineHeight: '22px',
891
- }, children: [token && (_jsxs(_Fragment, { children: [_jsx(StepEntry, { entryStep: "chat", label: "Chat", leadingVisual: CommentIcon }), _jsx(StepEntry, { entryStep: "gallery", label: "Agents", leadingVisual: RocketIcon }), _jsx(StepEntry, { entryStep: "config", label: "Configuration", leadingVisual: GearIcon })] })), !token ? null : (_jsxs(_Fragment, { children: [_jsx(StepEntry, { entryStep: "profile", label: "Profile", leadingVisual: PersonIcon }), _jsx(Button, { size: "small", variant: "invisible", onClick: handleSignOut, leadingVisual: SignOutIcon, sx: { color: 'fg.default' }, children: "Sign out" })] })), _jsx(AppearanceControlsWithStore, { useStore: useAgentNodeThemeStore })] }) })] }) }), _jsxs(PageLayout.Content, { children: [_jsx(Box, { "aria-live": "polite", sx: {
959
+ }, children: [token && (_jsxs(_Fragment, { children: [_jsx(StepEntry, { entryStep: "chat", label: "Chat", leadingVisual: CommentIcon }), _jsx(StepEntry, { entryStep: "gallery", label: "Agents", leadingVisual: AiAgentIcon }), _jsx(StepEntry, { entryStep: "config", label: "Configuration", leadingVisual: GearIcon })] })), !token ? null : (_jsxs(_Fragment, { children: [_jsx(StepEntry, { entryStep: "profile", label: "Profile", leadingVisual: PersonIcon }), _jsx(Button, { size: "small", variant: "invisible", onClick: handleSignOut, leadingVisual: SignOutIcon, sx: { color: 'fg.default' }, children: "Sign out" })] })), _jsx(AppearanceMenu, { colorMode: colorMode, themeVariant: themeVariant, onColorModeChange: setColorMode, onThemeChange: nextTheme => setTheme(nextTheme, false), shape: "circle" })] }) })] }) }), _jsxs(PageLayout.Content, { children: [_jsx(Box, { "aria-live": "polite", sx: {
892
960
  position: 'fixed',
893
961
  top: 0,
894
962
  left: 0,
@@ -975,7 +1043,12 @@ export function AgentNode() {
975
1043
  display: 'flex',
976
1044
  flexDirection: 'column',
977
1045
  gap: 3,
978
- }, children: [_jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Mode" }), _jsx(Box, { sx: {
1046
+ }, children: [_jsxs(Box, { sx: {
1047
+ border: '1px solid',
1048
+ borderColor: 'border.default',
1049
+ borderRadius: 2,
1050
+ p: 3,
1051
+ }, children: [_jsx(Heading, { sx: { fontSize: 2, m: 0, mb: 2 }, children: "Mode" }), _jsx(Box, { sx: {
979
1052
  display: 'grid',
980
1053
  gridTemplateColumns: 'repeat(3, 1fr)',
981
1054
  gap: 3,
@@ -1015,7 +1088,12 @@ export function AgentNode() {
1015
1088
  ? cfg.brandColor
1016
1089
  : 'fg.default',
1017
1090
  }, children: [_jsx(Icon, { size: 20 }), _jsx(Text, { sx: { fontWeight: 'bold' }, children: card.name })] }), _jsx(Text, { sx: { color: 'fg.muted', fontSize: 1 }, children: card.description })] }, card.mode));
1018
- }) })] }), _jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Inference" }), _jsx(Text, { sx: { color: 'fg.muted', fontSize: 1, mb: 2 }, children: "Used inference provider for newly launched agent sessions." }), _jsxs(Box, { sx: {
1091
+ }) })] }), _jsxs(Box, { sx: {
1092
+ border: '1px solid',
1093
+ borderColor: 'border.default',
1094
+ borderRadius: 2,
1095
+ p: 3,
1096
+ }, children: [_jsx(Heading, { sx: { fontSize: 2, m: 0, mb: 2 }, children: "Inference" }), _jsx(Text, { sx: { color: 'fg.muted', fontSize: 1, mb: 2 }, children: "Used inference provider for newly launched agent sessions." }), _jsxs(Box, { sx: {
1019
1097
  display: 'flex',
1020
1098
  gap: 2,
1021
1099
  flexWrap: 'wrap',
@@ -1033,14 +1111,30 @@ export function AgentNode() {
1033
1111
  display: 'flex',
1034
1112
  flexDirection: 'column',
1035
1113
  gap: 1,
1036
- }, children: [_jsx(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: "Bedrock Anthropic model" }), inferenceModels.length === 0 ? (_jsx(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: "No model list available." })) : (_jsxs(ActionMenu, { children: [_jsx(ActionMenu.Button, { children: inferenceDefaultModel || inferenceModels[0] }), _jsx(ActionMenu.Overlay, { width: "large", children: _jsx(ActionList, { selectionVariant: "single", children: inferenceModels.map(model => (_jsx(ActionList.Item, { selected: inferenceDefaultModel === model, inactiveText: "Selection is locked", children: model }, model))) }) })] }))] }))] }), iamUser ? (_jsx(BillingEntitySelect, { value: configuration.billing_entity_uid || '', onChange: handleBillingEntityChange, onSelectedAccountChange: handleSelectedAccountChange, onAccountsResolved: handleAccountsResolved })) : (_jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Run this agent under" }), _jsx(Text, { sx: { color: 'fg.muted', fontSize: 1 }, children: "Loading billing entitys..." })] }))] }), _jsxs(Box, { sx: {
1114
+ }, children: [_jsx(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: "Bedrock Anthropic model" }), inferenceModels.length === 0 ? (_jsx(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: "No model list available." })) : (_jsxs(ActionMenu, { children: [_jsx(ActionMenu.Button, { children: inferenceDefaultModel || inferenceModels[0] }), _jsx(ActionMenu.Overlay, { width: "large", children: _jsx(ActionList, { selectionVariant: "single", children: inferenceModels.map(model => (_jsx(ActionList.Item, { selected: inferenceDefaultModel === model, inactiveText: "Selection is locked", children: model }, model))) }) })] }))] }))] }), iamUser ? (_jsxs(Box, { sx: {
1115
+ border: '1px solid',
1116
+ borderColor: 'border.default',
1117
+ borderRadius: 2,
1118
+ p: 3,
1119
+ }, children: [_jsx(Heading, { sx: { fontSize: 2, m: 0, mb: 2 }, children: "Billing Entity" }), _jsx(BillingEntitySelect, { value: configuration.billing_entity_uid || '', onChange: handleBillingEntityChange, onSelectedAccountChange: handleSelectedAccountChange, onAccountsResolved: handleAccountsResolved })] })) : (_jsxs(Box, { sx: {
1120
+ border: '1px solid',
1121
+ borderColor: 'border.default',
1122
+ borderRadius: 2,
1123
+ p: 3,
1124
+ }, children: [_jsx(Heading, { sx: { fontSize: 2, m: 0, mb: 2 }, children: "Billing Entity" }), _jsx(Text, { sx: { color: 'fg.muted', fontSize: 1 }, children: "Loading billing entitys..." })] }))] }), _jsx(Box, { sx: {
1037
1125
  display: 'flex',
1038
1126
  flexDirection: 'column',
1039
1127
  gap: 2,
1040
- }, children: [_jsx(Heading, { sx: { fontSize: 2, m: 0 }, children: "Share" }), _jsx(ShareAccessComponent, { isOpen: true, displayMode: "inline", requestUrl: `${AGENT_RUNTIMES_BASE_URL}/api/v1/agent-node/sharing`, resourceLabel: "Agent Node", resourceName: "this Agent Node", onClose: handleSharingInlineClose })] })] }), error && _jsx(Text, { sx: { color: 'danger.fg' }, children: error }), _jsx(Box, { sx: { display: 'flex', justifyContent: 'flex-end' }, children: _jsx(Button, { variant: "primary", onClick: saveConfiguration, disabled: isSaving, children: isSaving ? 'Saving...' : 'Save' }) })] })), step === 'profile' && (_jsx(AgentNodeProfileView, { token: token, onTokenExpired: handleSignOut })), step === 'gallery' && (_jsx(AgentNodeGallery, { baseUrl: AGENT_RUNTIMES_BASE_URL, token: token, activeAgentId: configuration.active_agent_id, onLaunchError: message => {
1128
+ }, children: _jsxs(Box, { sx: {
1129
+ border: '1px solid',
1130
+ borderColor: 'border.default',
1131
+ borderRadius: 2,
1132
+ p: 3,
1133
+ }, children: [_jsx(Heading, { sx: { fontSize: 2, m: 0, mb: 2 }, children: "Share" }), _jsx(ShareAccessComponent, { isOpen: true, displayMode: "inline", requestUrl: `${AGENT_RUNTIMES_BASE_URL}/api/v1/agent-node/sharing`, resourceLabel: "Agent Node", resourceName: "this Agent Node", onClose: handleSharingInlineClose })] }) })] }), error && _jsx(Text, { sx: { color: 'danger.fg' }, children: error }), _jsx(Box, { sx: { display: 'flex', justifyContent: 'flex-end' }, children: _jsx(Button, { variant: "primary", onClick: saveConfiguration, disabled: isSaving, children: isSaving ? 'Saving...' : 'Save' }) })] })), step === 'profile' && (_jsx(AgentNodeProfileView, { token: token, onTokenExpired: handleSignOut, avatarFallbackBackground: avatarPalette.bgAlt, avatarFallbackForeground: avatarPalette.primary })), step === 'gallery' && (_jsx(AgentNodeGallery, { baseUrl: AGENT_RUNTIMES_BASE_URL, token: token, activeAgentId: configuration.active_agent_id, onLaunchError: message => {
1041
1134
  showBanner('error', message);
1042
1135
  }, onLaunched: agentId => {
1043
1136
  setSelectedAgentId(agentId);
1137
+ setIsActiveAgentRunning(true);
1044
1138
  const nextConfiguration = {
1045
1139
  ...configuration,
1046
1140
  active_agent_id: agentId,
@@ -1058,9 +1152,16 @@ export function AgentNode() {
1058
1152
  }).catch(() => {
1059
1153
  // Best-effort persistence; local state already switched.
1060
1154
  });
1061
- setStep('chat');
1155
+ if (isSaasOnlyChat) {
1156
+ showBanner('info', 'This node is configured for SaaS chat. Open Agent Nodes in Datalayer to chat with it.');
1157
+ setStep('gallery');
1158
+ }
1159
+ else {
1160
+ setStep('chat');
1161
+ }
1062
1162
  }, onTerminated: () => {
1063
1163
  setSelectedAgentId('default');
1164
+ setIsActiveAgentRunning(false);
1064
1165
  setConfiguration(prev => ({
1065
1166
  ...prev,
1066
1167
  active_agent_id: undefined,
@@ -1071,6 +1172,6 @@ export function AgentNode() {
1071
1172
  borderColor: 'border.default',
1072
1173
  borderRadius: 2,
1073
1174
  overflow: 'hidden',
1074
- }, children: _jsx(Chat, { protocol: "ag-ui", baseUrl: AGENT_RUNTIMES_BASE_URL, agentId: selectedAgentId, title: chatTitle, placeholder: "Send a message...", description: chatDescription, suggestions: chatSuggestions, submitOnSuggestionClick: true, showHeader: true, height: '70vh', showModelSelector: true, showToolsMenu: true, showSkillsMenu: true, showTokenUsage: true, showInformation: true, autoFocus: true, enableEphemeralNotebook: true, enableEphemeralDocument: true, initialEphemeralSurfaceMode: "notebook", runtimeId: selectedAgentId, ephemeralRuntimeOverride: sandboxRuntimeOverride, kernelEnvironmentName: sandboxEnvironmentName, ephemeralNotebookCollaborationProvider: ephemeralNotebookCollaborationProvider, ephemeralNotebookCollaborationDocumentId: ephemeralCollaborationDocumentId, ephemeralDocumentCollaboration: ephemeralDocumentCollaboration, historyEndpoint: `${AGENT_RUNTIMES_BASE_URL}/api/v1/history` }) }))] })] }) }) }));
1175
+ }, children: isSaasOnlyChat ? (_jsxs(Box, { sx: { p: 4 }, children: [_jsx(Heading, { sx: { fontSize: 2, mb: 2 }, children: "Chat From SaaS" }), _jsx(Text, { sx: { color: 'fg.muted' }, children: "This Agent Node deployment is configured for SaaS-only chat. Use the Datalayer Agent Nodes view to open chat sessions over the runtimes tunnel." })] })) : (_jsx(Chat, { protocol: "ag-ui", baseUrl: AGENT_RUNTIMES_BASE_URL, agentId: selectedAgentId, title: chatTitle, placeholder: "Send a message...", description: chatDescription, suggestions: chatSuggestions, submitOnSuggestionClick: true, showHeader: true, height: '70vh', showModelSelector: true, showToolsMenu: true, showSkillsMenu: true, showTokenUsage: true, showInformation: true, autoFocus: true, enableEphemeralNotebook: true, enableEphemeralDocument: true, initialEphemeralSurfaceMode: "notebook", runtimeId: selectedAgentId, ephemeralRuntimeOverride: sandboxRuntimeOverride, kernelEnvironmentName: sandboxEnvironmentName, themeVariant: themeVariant, colorMode: colorMode, ephemeralNotebookCollaborationProvider: ephemeralNotebookCollaborationProvider, ephemeralNotebookCollaborationDocumentId: ephemeralCollaborationDocumentId, ephemeralDocumentCollaboration: ephemeralDocumentCollaboration, historyEndpoint: `${AGENT_RUNTIMES_BASE_URL}/api/v1/history` })) }))] })] }) }) }));
1075
1176
  }
1076
1177
  export default AgentNode;
package/lib/App.js CHANGED
@@ -4,7 +4,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
4
4
  * Distributed under the terms of the Modified BSD License.
5
5
  */
6
6
  import { useJupyter, JupyterReactTheme } from '@datalayer/jupyter-react';
7
- import { JupyterCellExample } from './examples/CellSimpleExample';
7
+ import { CellExample } from './examples/CellExample';
8
8
  import { JupyterNotebookExample } from './examples/NotebookExample';
9
9
  import './App.css';
10
10
  export function App() {
@@ -13,6 +13,6 @@ export function App() {
13
13
  jupyterServerToken: '60c1661cc408f978c309d04157af55c9588ff9557c9380e4fb50785750703da6',
14
14
  startDefaultKernel: true,
15
15
  });
16
- return (_jsxs(JupyterReactTheme, { children: [serviceManager && _jsx(JupyterCellExample, { serviceManager: serviceManager }), serviceManager && (_jsx(JupyterNotebookExample, { serviceManager: serviceManager }))] }));
16
+ return (_jsxs(JupyterReactTheme, { children: [serviceManager && _jsx(CellExample, { serviceManager: serviceManager }), serviceManager && (_jsx(JupyterNotebookExample, { serviceManager: serviceManager }))] }));
17
17
  }
18
18
  export default App;