@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
@@ -7,8 +7,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
7
7
  import { useCallback, useEffect, useMemo, useRef, useState, } from 'react';
8
8
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
9
9
  import { Box } from '@datalayer/primer-addons';
10
+ import { ErrorView } from './components';
10
11
  import { Button, Heading, SegmentedControl, Spinner, Text, } from '@primer/react';
11
- import { AlertIcon, SignOutIcon, ToolsIcon } from '@primer/octicons-react';
12
+ import { SignOutIcon, ToolsIcon } from '@primer/octicons-react';
12
13
  import { useCoreStore } from '@datalayer/core';
13
14
  import { DEFAULT_SERVICE_URLS } from '@datalayer/core/lib/api/constants';
14
15
  import { useSimpleAuthStore } from '@datalayer/core/lib/views/otel';
@@ -111,6 +112,8 @@ const AgentToolApprovalsInner = ({ onLogout, }) => {
111
112
  const [toolApprovalState, setToolApprovalState] = useState({});
112
113
  const [wsState, setWsState] = useState('closed');
113
114
  const createdApprovalSignatures = useRef(new Set());
115
+ const toolRespondersRef = useRef(new Map());
116
+ const respondedToolCallsRef = useRef(new Set());
114
117
  const resolveLocalRef = useRef(async () => null);
115
118
  const authFetchRef = useRef((url, opts) => fetch(url, opts));
116
119
  const chatAuthToken = token === null ? undefined : token;
@@ -126,6 +129,29 @@ const AgentToolApprovalsInner = ({ onLogout, }) => {
126
129
  ...(opts.headers ?? {}),
127
130
  },
128
131
  }), [token]);
132
+ const emitServerToolDecision = useCallback((toolName, toolArgs, approved, approvalId, message) => {
133
+ const signature = approvalSignature(toolName, toolArgs);
134
+ const responder = toolRespondersRef.current.get(signature);
135
+ if (!responder?.respond) {
136
+ return false;
137
+ }
138
+ if (respondedToolCallsRef.current.has(responder.toolCallId)) {
139
+ return false;
140
+ }
141
+ setToolApprovalState(prev => ({
142
+ ...prev,
143
+ [responder.toolCallId]: approved ? 'approved' : 'denied',
144
+ }));
145
+ respondedToolCallsRef.current.add(responder.toolCallId);
146
+ responder.respond({
147
+ type: 'tool-approval-decision',
148
+ approved,
149
+ approvalId,
150
+ toolName: responder.toolName || toolName,
151
+ ...(message ? { message } : {}),
152
+ });
153
+ return true;
154
+ }, []);
129
155
  useEffect(() => {
130
156
  let isCancelled = false;
131
157
  const createLocalAgent = async () => {
@@ -315,6 +341,8 @@ const AgentToolApprovalsInner = ({ onLogout, }) => {
315
341
  const action = wsEvent === 'tool_approval_approved' ? 'approve' : 'reject';
316
342
  void (async () => {
317
343
  try {
344
+ const approved = wsEvent === 'tool_approval_approved';
345
+ emitServerToolDecision(approval.tool_name, approval.tool_args ?? {}, approved, approval.id, approval.note);
318
346
  const localMatch = await resolveLocalRef.current(approval.tool_name, approval.tool_args ?? {});
319
347
  if (localMatch) {
320
348
  const localBaseUrl = `${agentBaseUrl}/api/v1/tool-approvals/${localMatch.id}/${action}`;
@@ -356,6 +384,7 @@ const AgentToolApprovalsInner = ({ onLogout, }) => {
356
384
  chatAuthToken,
357
385
  agentId,
358
386
  pollApprovals,
387
+ emitServerToolDecision,
359
388
  ]);
360
389
  // Keep refs in sync so the WS handler always has the latest functions.
361
390
  useEffect(() => {
@@ -384,8 +413,9 @@ const AgentToolApprovalsInner = ({ onLogout, }) => {
384
413
  throw new Error(errorText ||
385
414
  `Failed to approve request (${response.status} ${response.statusText})`);
386
415
  }
387
- // In server mode the WS event will remove from queue and bridge to
388
- // the local runtime don't do it here to keep flow server-driven.
416
+ // In server mode, UI/continuation updates are websocket-driven only.
417
+ // The click only sends approve to the server; local chat reacts when
418
+ // tool_approval_approved is received.
389
419
  if (mode !== 'server') {
390
420
  setApprovals(prev => prev.filter(a => a.id !== requestId));
391
421
  void pollApprovals();
@@ -402,7 +432,14 @@ const AgentToolApprovalsInner = ({ onLogout, }) => {
402
432
  finally {
403
433
  setApprovalLoading(null);
404
434
  }
405
- }, [approvals, mode, aiAgentsBaseUrl, agentBaseUrl, authFetch, pollApprovals]);
435
+ }, [
436
+ approvals,
437
+ mode,
438
+ aiAgentsBaseUrl,
439
+ agentBaseUrl,
440
+ authFetch,
441
+ pollApprovals,
442
+ ]);
406
443
  const reject = useCallback(async (requestId, note) => {
407
444
  setApprovalLoading(requestId);
408
445
  setApprovalError(null);
@@ -423,8 +460,9 @@ const AgentToolApprovalsInner = ({ onLogout, }) => {
423
460
  throw new Error(errorText ||
424
461
  `Failed to reject request (${response.status} ${response.statusText})`);
425
462
  }
426
- // In server mode the WS event will remove from queue and bridge to
427
- // the local runtime don't do it here to keep flow server-driven.
463
+ // In server mode, UI/continuation updates are websocket-driven only.
464
+ // The click only sends reject to the server; local chat reacts when
465
+ // tool_approval_rejected is received.
428
466
  if (mode !== 'server') {
429
467
  setApprovals(prev => prev.filter(a => a.id !== requestId));
430
468
  void pollApprovals();
@@ -441,7 +479,14 @@ const AgentToolApprovalsInner = ({ onLogout, }) => {
441
479
  finally {
442
480
  setApprovalLoading(null);
443
481
  }
444
- }, [approvals, mode, aiAgentsBaseUrl, agentBaseUrl, authFetch, pollApprovals]);
482
+ }, [
483
+ approvals,
484
+ mode,
485
+ aiAgentsBaseUrl,
486
+ agentBaseUrl,
487
+ authFetch,
488
+ pollApprovals,
489
+ ]);
445
490
  const ensureServerApproval = useCallback(async (toolName, args) => {
446
491
  if (mode !== 'server' || !aiAgentsBaseUrl || !isReady) {
447
492
  return;
@@ -508,19 +553,46 @@ const AgentToolApprovalsInner = ({ onLogout, }) => {
508
553
  return stableStringify(approval.tool_args ?? {}) === argsSig;
509
554
  }) || null);
510
555
  }, [approvals]);
511
- const handleToolLevelApprove = useCallback(async (toolCallId, requestId) => {
556
+ const handleToolLevelApprove = useCallback(async (toolCallId, requestId, toolName, respond) => {
512
557
  const ok = await approve(requestId, 'Approved from tool message card');
513
558
  if (ok) {
514
- setToolApprovalState(prev => ({ ...prev, [toolCallId]: 'approved' }));
559
+ if (mode !== 'server') {
560
+ setToolApprovalState(prev => ({ ...prev, [toolCallId]: 'approved' }));
561
+ respond?.({
562
+ type: 'tool-approval-decision',
563
+ approved: true,
564
+ approvalId: requestId,
565
+ toolName,
566
+ });
567
+ }
515
568
  }
516
- }, [approve]);
517
- const handleToolLevelDeny = useCallback(async (toolCallId, requestId) => {
569
+ }, [approve, mode]);
570
+ const handleToolLevelDeny = useCallback(async (toolCallId, requestId, toolName, respond) => {
518
571
  const ok = await reject(requestId, 'Rejected from tool message card');
519
572
  if (ok) {
520
- setToolApprovalState(prev => ({ ...prev, [toolCallId]: 'denied' }));
573
+ if (mode !== 'server') {
574
+ setToolApprovalState(prev => ({ ...prev, [toolCallId]: 'denied' }));
575
+ respond?.({
576
+ type: 'tool-approval-decision',
577
+ approved: false,
578
+ approvalId: requestId,
579
+ toolName,
580
+ });
581
+ }
582
+ }
583
+ }, [reject, mode]);
584
+ const renderToolResult = useCallback(({ toolCallId, toolName, args, result, status, error, respond }) => {
585
+ const signature = approvalSignature(toolName, args);
586
+ if (respond && status === 'inProgress') {
587
+ toolRespondersRef.current.set(signature, {
588
+ toolCallId,
589
+ toolName,
590
+ respond,
591
+ });
592
+ }
593
+ else if (status === 'complete' || status === 'error') {
594
+ toolRespondersRef.current.delete(signature);
521
595
  }
522
- }, [reject]);
523
- const renderToolResult = useCallback(({ toolCallId, toolName, args, result, status, error }) => {
524
596
  const matchedApproval = findMatchingApproval(toolName, args);
525
597
  const resultObject = result && typeof result === 'object'
526
598
  ? result
@@ -539,9 +611,9 @@ const AgentToolApprovalsInner = ({ onLogout, }) => {
539
611
  ? 'pending'
540
612
  : undefined);
541
613
  return (_jsx(ToolCallDisplay, { toolCallId: toolCallId, toolName: toolName, args: args, result: result, status: status, error: error, approvalRequired: !!approvalState, approvalState: approvalState, approvalLoading: loadingThisApproval, onApprove: matchedApproval
542
- ? () => void handleToolLevelApprove(toolCallId, matchedApproval.id)
614
+ ? () => void handleToolLevelApprove(toolCallId, matchedApproval.id, toolName, respond)
543
615
  : undefined, onDeny: matchedApproval
544
- ? () => void handleToolLevelDeny(toolCallId, matchedApproval.id)
616
+ ? () => void handleToolLevelDeny(toolCallId, matchedApproval.id, toolName, respond)
545
617
  : undefined }));
546
618
  }, [
547
619
  mode,
@@ -563,14 +635,7 @@ const AgentToolApprovalsInner = ({ onLogout, }) => {
563
635
  }, children: [_jsx(Spinner, { size: "large" }), _jsx(Text, { sx: { color: 'fg.muted' }, children: "Launching tool approval demo..." })] }));
564
636
  }
565
637
  if (runtimeStatus === 'error' || hookError) {
566
- return (_jsxs(Box, { sx: {
567
- display: 'flex',
568
- flexDirection: 'column',
569
- alignItems: 'center',
570
- justifyContent: 'center',
571
- height: '100vh',
572
- gap: 3,
573
- }, children: [_jsx(AlertIcon, { size: 48 }), _jsx(Text, { sx: { color: 'danger.fg' }, children: hookError || 'Agent failed to start' })] }));
638
+ return _jsx(ErrorView, { error: hookError, onLogout: onLogout });
574
639
  }
575
640
  const serverPanel = mode === 'server' ? (_jsxs(Box, { sx: {
576
641
  width: 320,