@datalayer/agent-runtimes 1.0.3 → 1.0.4

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 (73) hide show
  1. package/README.md +13 -131
  2. package/lib/chat/Chat.d.ts +3 -1
  3. package/lib/chat/Chat.js +2 -2
  4. package/lib/chat/base/ChatBase.js +52 -1
  5. package/lib/chat/messages/ChatMessageList.js +17 -4
  6. package/lib/client/AgentsMixin.d.ts +48 -1
  7. package/lib/client/AgentsMixin.js +109 -0
  8. package/lib/components/NotificationEventCard.js +51 -26
  9. package/lib/components/OutputCard.js +21 -7
  10. package/lib/components/ToolApprovalCard.js +20 -2
  11. package/lib/examples/AgentCheckpointsExample.js +2 -8
  12. package/lib/examples/AgentCodemodeExample.js +3 -9
  13. package/lib/examples/AgentEvalsExample.js +3 -9
  14. package/lib/examples/AgentGuardrailsExample.js +3 -9
  15. package/lib/examples/AgentMemoryExample.js +3 -9
  16. package/lib/examples/AgentMonitoringExample.js +3 -9
  17. package/lib/examples/AgentNotificationsExample.js +2 -8
  18. package/lib/examples/AgentOutputsExample.js +3 -9
  19. package/lib/examples/AgentSandboxExample.js +3 -9
  20. package/lib/examples/AgentSkillsExample.js +3 -9
  21. package/lib/examples/AgentToolApprovalsExample.js +89 -24
  22. package/lib/examples/AgentTriggersExample.js +604 -37
  23. package/lib/examples/ChatExample.js +2 -10
  24. package/lib/examples/components/ErrorView.d.ts +14 -0
  25. package/lib/examples/components/ErrorView.js +20 -0
  26. package/lib/examples/components/index.d.ts +2 -0
  27. package/lib/examples/components/index.js +1 -0
  28. package/lib/examples/main.d.ts +1 -0
  29. package/lib/examples/main.js +1 -0
  30. package/lib/protocols/VercelAIAdapter.d.ts +2 -0
  31. package/lib/protocols/VercelAIAdapter.js +86 -20
  32. package/lib/shims/json5.d.ts +4 -0
  33. package/lib/shims/json5.js +8 -0
  34. package/lib/specs/agents/agents.js +241 -1390
  35. package/lib/specs/agents/index.js +1 -3
  36. package/lib/specs/envvars.js +20 -27
  37. package/lib/specs/evals.js +6 -6
  38. package/lib/specs/events.d.ts +10 -2
  39. package/lib/specs/events.js +84 -126
  40. package/lib/specs/frontendTools.js +2 -2
  41. package/lib/specs/guardrails.d.ts +7 -0
  42. package/lib/specs/guardrails.js +159 -240
  43. package/lib/specs/mcpServers.js +6 -35
  44. package/lib/specs/memory.d.ts +2 -0
  45. package/lib/specs/memory.js +17 -4
  46. package/lib/specs/models.js +5 -25
  47. package/lib/specs/notifications.js +18 -102
  48. package/lib/specs/outputs.js +9 -15
  49. package/lib/specs/skills.js +18 -18
  50. package/lib/specs/teams/index.js +1 -3
  51. package/lib/specs/teams/teams.js +348 -468
  52. package/lib/specs/tools.js +6 -3
  53. package/lib/specs/triggers.js +11 -61
  54. package/lib/types/tools.d.ts +2 -0
  55. package/package.json +1 -1
  56. package/scripts/codegen/__pycache__/versioning.cpython-313.pyc +0 -0
  57. package/scripts/codegen/generate_agents.py +4 -1
  58. package/scripts/codegen/generate_events.py +12 -4
  59. package/scripts/codegen/generate_tools.py +20 -0
  60. package/style/primer-primitives.css +1 -6
  61. package/scripts/codegen/__pycache__/generate_agents.cpython-313.pyc +0 -0
  62. package/scripts/codegen/__pycache__/generate_envvars.cpython-313.pyc +0 -0
  63. package/scripts/codegen/__pycache__/generate_evals.cpython-313.pyc +0 -0
  64. package/scripts/codegen/__pycache__/generate_guardrails.cpython-313.pyc +0 -0
  65. package/scripts/codegen/__pycache__/generate_mcp_servers.cpython-313.pyc +0 -0
  66. package/scripts/codegen/__pycache__/generate_memory.cpython-313.pyc +0 -0
  67. package/scripts/codegen/__pycache__/generate_models.cpython-313.pyc +0 -0
  68. package/scripts/codegen/__pycache__/generate_notifications.cpython-313.pyc +0 -0
  69. package/scripts/codegen/__pycache__/generate_outputs.cpython-313.pyc +0 -0
  70. package/scripts/codegen/__pycache__/generate_skills.cpython-313.pyc +0 -0
  71. package/scripts/codegen/__pycache__/generate_teams.cpython-313.pyc +0 -0
  72. package/scripts/codegen/__pycache__/generate_tools.cpython-313.pyc +0 -0
  73. package/scripts/codegen/__pycache__/generate_triggers.cpython-313.pyc +0 -0
@@ -17,9 +17,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
17
17
  */
18
18
  import { useEffect, useState } from 'react';
19
19
  import { Text, Spinner } from '@primer/react';
20
- import { AlertIcon } from '@primer/octicons-react';
21
20
  import { Box, setupPrimerPortals } from '@datalayer/primer-addons';
22
21
  import { ThemedProvider } from './utils/themedProvider';
22
+ import { ErrorView } from './components';
23
23
  import { Chat } from '../chat';
24
24
  setupPrimerPortals();
25
25
  const BASE_URL = 'http://localhost:8765';
@@ -101,15 +101,7 @@ const AgentRuntimeChatExample = () => {
101
101
  }
102
102
  // Error state
103
103
  if (error || !agentId) {
104
- return (_jsx(ThemedProvider, { children: _jsxs(Box, { sx: {
105
- display: 'flex',
106
- flexDirection: 'column',
107
- alignItems: 'center',
108
- justifyContent: 'center',
109
- height: '100vh',
110
- gap: 3,
111
- bg: 'canvas.default',
112
- }, children: [_jsx(AlertIcon, { size: 48 }), _jsx(Text, { sx: { color: 'danger.fg', fontSize: 2 }, children: "Failed to start agent" }), _jsx(Text, { sx: { color: 'fg.muted', fontSize: 1 }, children: error || 'No agent ID returned' })] }) }));
104
+ return (_jsx(ThemedProvider, { children: _jsx(ErrorView, { error: "Failed to start agent", detail: error || 'No agent ID returned' }) }));
113
105
  }
114
106
  // Agent is ready — render the Chat component
115
107
  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: [
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ export type ErrorViewProps = {
3
+ /** Primary error message. Falls back to "Agent failed to start". */
4
+ error?: string | null;
5
+ /** Optional secondary detail line shown below the primary message. */
6
+ detail?: string | null;
7
+ /** Called when the user clicks "Sign out". Button only appears for 401 errors. */
8
+ onLogout?: () => void;
9
+ };
10
+ /**
11
+ * Full-screen error view used by examples when agent creation fails.
12
+ * Automatically shows a "Sign out" button when the error contains "401".
13
+ */
14
+ export declare const ErrorView: React.FC<ErrorViewProps>;
@@ -0,0 +1,20 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Text, Button } from '@primer/react';
3
+ import { AlertIcon, SignOutIcon } from '@primer/octicons-react';
4
+ import { Box } from '@datalayer/primer-addons';
5
+ /**
6
+ * Full-screen error view used by examples when agent creation fails.
7
+ * Automatically shows a "Sign out" button when the error contains "401".
8
+ */
9
+ export const ErrorView = ({ error, detail, onLogout, }) => {
10
+ const message = error || 'Agent failed to start';
11
+ const is401 = String(message).includes('401') || String(detail || '').includes('401');
12
+ return (_jsxs(Box, { sx: {
13
+ display: 'flex',
14
+ flexDirection: 'column',
15
+ alignItems: 'center',
16
+ justifyContent: 'center',
17
+ height: '100vh',
18
+ gap: 3,
19
+ }, children: [_jsx(AlertIcon, { size: 48 }), _jsx(Text, { sx: { color: 'danger.fg', fontSize: 2 }, children: message }), detail && _jsx(Text, { sx: { color: 'fg.muted' }, children: detail }), is401 && onLogout && (_jsx(Button, { variant: "danger", leadingVisual: SignOutIcon, onClick: onLogout, children: "Sign out" }))] }));
20
+ };
@@ -1,3 +1,5 @@
1
+ export { ErrorView } from './ErrorView';
2
+ export type { ErrorViewProps } from './ErrorView';
1
3
  export { MockFileBrowser } from './MockFileBrowser';
2
4
  export type { MockFileBrowserProps } from './MockFileBrowser';
3
5
  export { MainContent } from './MainContent';
@@ -3,6 +3,7 @@
3
3
  * Distributed under the terms of the Modified BSD License.
4
4
  */
5
5
  // Example/layout components
6
+ export { ErrorView } from './ErrorView';
6
7
  export { MockFileBrowser } from './MockFileBrowser';
7
8
  export { MainContent } from './MainContent';
8
9
  export { SessionTabs } from './SessionTabs';
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  import { createRoot } from 'react-dom/client';
3
+ import '../../style/primer-primitives.css';
3
4
  declare global {
4
5
  interface Window {
5
6
  __agentRuntimesExamplesRoot?: ReturnType<typeof createRoot>;
@@ -17,6 +17,7 @@ import { EXAMPLES } from './example-selector';
17
17
  import { useExampleThemeStore } from './utils/themeStore';
18
18
  import { ExampleWrapper } from './components/ExampleWrapper';
19
19
  import nbformatExample from './utils/notebooks/NotebookExample1.ipynb.json';
20
+ import '../../style/primer-primitives.css';
20
21
  // Load configurations from DOM
21
22
  const loadConfigurations = () => {
22
23
  // Load Datalayer configuration
@@ -42,7 +42,9 @@ export declare class VercelAIAdapter extends BaseProtocolAdapter {
42
42
  private messageHistory;
43
43
  private lastAssistantText;
44
44
  private lastTools;
45
+ private lastFrontendToolNames;
45
46
  private isContinuation;
47
+ private deferredToolMeta;
46
48
  private _streamParsingDepth;
47
49
  private _streamDonePromise;
48
50
  private _streamDoneResolve;
@@ -22,7 +22,13 @@ export class VercelAIAdapter extends BaseProtocolAdapter {
22
22
  messageHistory = [];
23
23
  lastAssistantText = '';
24
24
  lastTools = [];
25
+ lastFrontendToolNames = new Set();
25
26
  isContinuation = false;
27
+ // Metadata for ALL deferred tool calls (frontend + approval), keyed by toolCallId.
28
+ // Unlike pendingToolCalls (which only tracks frontend tools for batching),
29
+ // this preserves tool name/args for approval tools so sendToolResult can
30
+ // build a correct continuation message.
31
+ deferredToolMeta = new Map();
26
32
  // Stream parsing depth — prevents premature continuations
27
33
  _streamParsingDepth = 0;
28
34
  _streamDonePromise = null;
@@ -97,10 +103,17 @@ export class VercelAIAdapter extends BaseProtocolAdapter {
97
103
  // Store tools for potential continuation
98
104
  if (options?.tools) {
99
105
  this.lastTools = options.tools;
106
+ this.lastFrontendToolNames = new Set(options.tools
107
+ .map(t => t?.name)
108
+ .filter((name) => Boolean(name)));
109
+ }
110
+ else {
111
+ this.lastFrontendToolNames = new Set();
100
112
  }
101
113
  // Reset assistant content tracking for fresh (non-continuation) messages
102
114
  if (!this.isContinuation) {
103
115
  this.lastAssistantText = '';
116
+ this.deferredToolMeta.clear();
104
117
  }
105
118
  try {
106
119
  let vercelMessages;
@@ -156,6 +169,9 @@ export class VercelAIAdapter extends BaseProtocolAdapter {
156
169
  const requestBody = {
157
170
  id: requestId,
158
171
  messages: vercelMessages,
172
+ // Required for pydantic-ai deferred tool approval continuations.
173
+ // sdkVersion 6 enables parsing approval-responded tool parts.
174
+ sdkVersion: 6,
159
175
  trigger: 'submit-message',
160
176
  ...(options?.tools && { tools: options.tools }),
161
177
  ...(options?.model && { model: options.model }),
@@ -439,12 +455,9 @@ export class VercelAIAdapter extends BaseProtocolAdapter {
439
455
  event.tool?.name;
440
456
  const args = normalizeToolArgs(event.input || event.args || event.arguments, pending?.inputText || '');
441
457
  if (toolName) {
442
- // Track as a pending frontend tool call for continuation
443
- this.pendingToolCalls.set(toolCallId, {
444
- toolCallId,
445
- toolName,
446
- args,
447
- });
458
+ // Emit tool-call for all tools so UI can render a tool entry.
459
+ // Only client-declared frontend tools should participate in
460
+ // frontend continuation batching via pendingToolCalls.
448
461
  this.emit({
449
462
  type: 'tool-call',
450
463
  toolCall: {
@@ -454,6 +467,20 @@ export class VercelAIAdapter extends BaseProtocolAdapter {
454
467
  },
455
468
  timestamp: new Date(),
456
469
  });
470
+ // Track metadata for ALL deferred tools so sendToolResult
471
+ // can build proper continuation messages (tool name + args).
472
+ this.deferredToolMeta.set(toolCallId, {
473
+ toolCallId,
474
+ toolName,
475
+ args,
476
+ });
477
+ if (this.lastFrontendToolNames.has(toolName)) {
478
+ this.pendingToolCalls.set(toolCallId, {
479
+ toolCallId,
480
+ toolName,
481
+ args,
482
+ });
483
+ }
457
484
  }
458
485
  }
459
486
  else if (event.type === 'tool-output-available') {
@@ -475,6 +502,7 @@ export class VercelAIAdapter extends BaseProtocolAdapter {
475
502
  // Server already executed this tool — remove from pending
476
503
  // frontend tool calls so emitDoneOnce is not blocked.
477
504
  this.pendingToolCalls.delete(toolCallId);
505
+ this.deferredToolMeta.delete(toolCallId);
478
506
  }
479
507
  else if (event.type === 'tool-output-error' ||
480
508
  event.type === 'tool-error') {
@@ -489,6 +517,7 @@ export class VercelAIAdapter extends BaseProtocolAdapter {
489
517
  // Server handled the error — clear from pending frontend
490
518
  // tool calls so emitDoneOnce is not blocked.
491
519
  this.pendingToolCalls.delete(toolCallId);
520
+ this.deferredToolMeta.delete(toolCallId);
492
521
  this.emit({
493
522
  type: 'tool-result',
494
523
  toolResult: {
@@ -575,8 +604,10 @@ export class VercelAIAdapter extends BaseProtocolAdapter {
575
604
  toolResult: result,
576
605
  timestamp: new Date(),
577
606
  });
578
- // 2. Retrieve tool metadata from pending map
579
- const pendingToolCall = this.pendingToolCalls.get(toolCallId);
607
+ // 2. Retrieve tool metadata from pending map (frontend tools) or
608
+ // deferred tool meta (approval / all deferred tools).
609
+ const pendingToolCall = this.pendingToolCalls.get(toolCallId) ??
610
+ this.deferredToolMeta.get(toolCallId);
580
611
  if (!pendingToolCall) {
581
612
  console.warn('[VercelAIAdapter] No pending tool call found for ID:', toolCallId);
582
613
  }
@@ -613,18 +644,53 @@ export class VercelAIAdapter extends BaseProtocolAdapter {
613
644
  state: 'done',
614
645
  });
615
646
  }
616
- // Add each tool call with its result as a DynamicToolUIPart
647
+ // Add each tool call with its result as a dynamic-tool part.
648
+ // pydantic-ai parses DynamicTool* parts with output-available / output-error
649
+ // and approval-responded states for deferred approval continuations.
617
650
  for (const tr of this.collectedToolResults.values()) {
618
- assistantParts.push({
619
- type: 'dynamic-tool',
620
- toolName: tr.toolName,
621
- toolCallId: tr.toolCallId,
622
- state: 'output-available',
623
- input: tr.args,
624
- output: tr.result.success
625
- ? tr.result.result
626
- : { error: tr.result.error ?? 'Tool execution failed' },
627
- });
651
+ const resultObj = tr.result.result && typeof tr.result.result === 'object'
652
+ ? tr.result.result
653
+ : undefined;
654
+ const isApprovalDecision = !!resultObj && typeof resultObj.approved === 'boolean';
655
+ if (isApprovalDecision) {
656
+ const approvalId = typeof resultObj?.approvalId === 'string'
657
+ ? resultObj.approvalId
658
+ : tr.toolCallId;
659
+ const approved = Boolean(resultObj?.approved);
660
+ const reason = typeof resultObj?.message === 'string' ? resultObj.message : undefined;
661
+ assistantParts.push({
662
+ type: 'dynamic-tool',
663
+ toolName: tr.toolName,
664
+ toolCallId: tr.toolCallId,
665
+ state: 'approval-responded',
666
+ input: tr.args,
667
+ approval: {
668
+ id: approvalId,
669
+ approved,
670
+ ...(reason ? { reason } : {}),
671
+ },
672
+ });
673
+ }
674
+ else if (tr.result.success) {
675
+ assistantParts.push({
676
+ type: 'dynamic-tool',
677
+ toolName: tr.toolName,
678
+ toolCallId: tr.toolCallId,
679
+ state: 'output-available',
680
+ input: tr.args,
681
+ output: tr.result.result,
682
+ });
683
+ }
684
+ else {
685
+ assistantParts.push({
686
+ type: 'dynamic-tool',
687
+ toolName: tr.toolName,
688
+ toolCallId: tr.toolCallId,
689
+ state: 'output-error',
690
+ input: tr.args,
691
+ errorText: tr.result.error ?? 'Tool execution failed',
692
+ });
693
+ }
628
694
  }
629
695
  const assistantMessage = {
630
696
  id: generateMessageId(),
@@ -636,9 +702,9 @@ export class VercelAIAdapter extends BaseProtocolAdapter {
636
702
  // 7. Clear batching state BEFORE the async sendMessage call
637
703
  this.pendingToolCalls.clear();
638
704
  this.collectedToolResults.clear();
705
+ this.deferredToolMeta.clear();
639
706
  // 8. Update stored message history
640
707
  this.messageHistory = continuationMessages;
641
- console.log('[VercelAIAdapter] === CONTINUATION MESSAGES ===', continuationMessages.map((m, i) => `[${i}] role=${m.role} parts=${m.parts.length}`));
642
708
  // 9. Mark as continuation
643
709
  this.isContinuation = true;
644
710
  // 10. Send ONE continuation request with all tool results
@@ -0,0 +1,4 @@
1
+ import JSON5 from 'json5/dist/index.mjs';
2
+ export declare const parse: any;
3
+ export declare const stringify: any;
4
+ export default JSON5;
@@ -0,0 +1,8 @@
1
+ /*
2
+ * Copyright (c) 2025-2026 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ import JSON5 from 'json5/dist/index.mjs';
6
+ export const parse = JSON5.parse.bind(JSON5);
7
+ export const stringify = JSON5.stringify.bind(JSON5);
8
+ export default JSON5;