@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
@@ -3,12 +3,22 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  * Copyright (c) 2025-2026 Datalayer, Inc.
4
4
  * Distributed under the terms of the Modified BSD License.
5
5
  */
6
+ import { useState } from 'react';
6
7
  import { Button, Label, Text, Truncate } from '@primer/react';
7
8
  import { Box } from '@datalayer/primer-addons';
8
- import { DownloadIcon, EyeClosedIcon, EyeIcon, TrashIcon, } from '@primer/octicons-react';
9
- import { createMarkdownDownloadPayload, downloadTextPayload, formatRelativeTime, } from '@datalayer/core/lib/utils';
9
+ import { ChevronDownIcon, DownloadIcon, EyeClosedIcon, EyeIcon, TrashIcon, } from '@primer/octicons-react';
10
+ import { createMarkdownDownloadPayload, downloadTextPayload, formatDurationMs, formatRelativeTime, } from '@datalayer/core/lib/utils';
10
11
  import { Streamdown } from 'streamdown';
11
12
  import { streamdownMarkdownStyles } from '../chat/styles/streamdownStyles';
13
+ const EVENT_KIND_VARIANT = {
14
+ 'agent-start-requested': 'attention',
15
+ 'agent-assigned': 'accent',
16
+ 'agent-started': 'success',
17
+ 'agent-output': 'accent',
18
+ 'agent-termination-requested': 'attention',
19
+ 'agent-terminated': 'danger',
20
+ 'tool-approval-requested': 'attention',
21
+ };
12
22
  const eventStartedAt = (evt) => {
13
23
  const startedAt = evt?.started_at || evt?.payload?.started_at;
14
24
  return typeof startedAt === 'string' && startedAt ? startedAt : null;
@@ -17,15 +27,15 @@ const eventEndedAt = (evt) => {
17
27
  const endedAt = evt?.ended_at || evt?.payload?.ended_at;
18
28
  return typeof endedAt === 'string' && endedAt ? endedAt : null;
19
29
  };
20
- const isRunningEvent = (evt) => {
21
- const status = String(evt?.status ?? '').toLowerCase();
22
- return evt?.kind === 'agent-started' && status === 'running';
23
- };
24
30
  export function NotificationEventCard({ event, onToggleRead, onDelete, onOpenAgent, }) {
31
+ const [isOutputExpanded, setIsOutputExpanded] = useState(false);
32
+ const [isDetailsExpanded, setIsDetailsExpanded] = useState(false);
33
+ const eventKind = String(event?.kind ?? '').toLowerCase();
34
+ const eventTitle = String(event?.title ?? '');
35
+ const eventOrigin = String(event?.metadata?.origin || '');
25
36
  const startedAt = eventStartedAt(event);
26
37
  const endedAt = eventEndedAt(event);
27
- const running = isRunningEvent(event);
28
- const outputText = event.kind === 'agent-ended' && event.payload?.outputs
38
+ const outputText = eventKind === 'agent-output' && event.payload?.outputs
29
39
  ? String(event.payload.outputs)
30
40
  : null;
31
41
  const runtimeId = String(event?.agent_id ||
@@ -33,6 +43,7 @@ export function NotificationEventCard({ event, onToggleRead, onDelete, onOpenAge
33
43
  event?.payload?.runtime_id ||
34
44
  event?.payload?.agent_id ||
35
45
  'runtime');
46
+ const hasAgentRoute = Boolean(onOpenAgent) && runtimeId !== 'runtime';
36
47
  const detailEntries = [];
37
48
  const detailLineSx = { fontSize: 0, overflowWrap: 'anywhere' };
38
49
  const detailLabelSx = { color: 'fg.muted' };
@@ -51,9 +62,6 @@ export function NotificationEventCard({ event, onToggleRead, onDelete, onOpenAge
51
62
  detailEntries.push({ label: key, value: String(value) });
52
63
  });
53
64
  Object.entries(event?.payload || {}).forEach(([key, value]) => {
54
- if (key === 'outputs') {
55
- return;
56
- }
57
65
  if (value === undefined || value === null || value === '') {
58
66
  return;
59
67
  }
@@ -88,13 +96,7 @@ export function NotificationEventCard({ event, onToggleRead, onDelete, onOpenAge
88
96
  gap: 2,
89
97
  minWidth: 0,
90
98
  flex: 1,
91
- }, children: [_jsx(Label, { variant: event.kind === 'agent-started'
92
- ? 'accent'
93
- : event.kind === 'agent-ended'
94
- ? 'success'
95
- : event.kind?.includes('alert')
96
- ? 'danger'
97
- : 'attention', children: event.kind }), _jsx(Truncate, { maxWidth: "50%", title: String(event.title || ''), sx: { fontWeight: 'semibold', fontSize: 1, minWidth: 0 }, children: event.title }), event.kind === 'agent-ended' && event.payload?.exit_status && (_jsxs(Label, { variant: "success", sx: { fontSize: 0, whiteSpace: 'nowrap' }, children: ["Status: ", String(event.payload.exit_status)] })), event.agent_id && (_jsx(Truncate, { maxWidth: 240, title: String(event.agent_id), children: _jsx(Label, { variant: "secondary", sx: { fontSize: 0, maxWidth: '100%' }, children: event.agent_id }) }))] }), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1, flexShrink: 0 }, children: [running && event.agent_id && (_jsx(Button, { size: "small", variant: "invisible", onClick: () => onOpenAgent?.(String(event.agent_id)), children: "Open agent" })), event.created_at && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted', whiteSpace: 'nowrap' }, children: new Date(event.created_at).toLocaleString() })), _jsx(Button, { size: "small", variant: "invisible", onClick: () => onToggleRead(event), sx: { p: 1 }, children: event.read ? _jsx(EyeClosedIcon, { size: 12 }) : _jsx(EyeIcon, { size: 12 }) }), _jsx(Button, { size: "small", variant: "invisible", onClick: () => onDelete(event), sx: { p: 1, color: 'danger.fg' }, children: _jsx(TrashIcon, { size: 12 }) })] })] }), event.payload && (_jsxs(Box, { sx: {
99
+ }, children: [_jsx(Label, { variant: EVENT_KIND_VARIANT[eventKind] ?? 'secondary', children: eventKind }), _jsx(Truncate, { maxWidth: "50%", title: String(eventTitle || ''), sx: { fontWeight: 'semibold', fontSize: 1, minWidth: 0 }, children: eventTitle }), eventKind === 'agent-output' && event.payload?.exit_status && (_jsxs(Label, { variant: "success", sx: { fontSize: 0, whiteSpace: 'nowrap' }, children: ["Status: ", String(event.payload.exit_status)] })), event.agent_id && (_jsx(Truncate, { maxWidth: 240, title: String(event.agent_id), children: _jsx(Label, { variant: "secondary", sx: { fontSize: 0, maxWidth: '100%' }, children: event.agent_id }) })), eventOrigin && (_jsxs(Label, { variant: "secondary", sx: { fontSize: 0, whiteSpace: 'nowrap' }, children: ["Origin: ", eventOrigin] }))] }), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1, flexShrink: 0 }, children: [hasAgentRoute && (_jsx(Button, { size: "small", variant: "invisible", onClick: () => onOpenAgent?.(runtimeId), children: "View agent" })), event.created_at && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted', whiteSpace: 'nowrap' }, children: new Date(event.created_at).toLocaleString() })), _jsx(Button, { size: "small", variant: "invisible", onClick: () => onToggleRead(event), sx: { p: 1 }, children: event.read ? _jsx(EyeClosedIcon, { size: 12 }) : _jsx(EyeIcon, { size: 12 }) }), _jsx(Button, { size: "small", variant: "invisible", onClick: () => onDelete(event), sx: { p: 1, color: 'danger.fg' }, children: _jsx(TrashIcon, { size: 12 }) })] })] }), event.payload && (_jsxs(Box, { sx: {
98
100
  fontSize: 0,
99
101
  color: 'fg.muted',
100
102
  mt: 1,
@@ -102,21 +104,24 @@ export function NotificationEventCard({ event, onToggleRead, onDelete, onOpenAge
102
104
  overflowWrap: 'anywhere',
103
105
  }, children: [(startedAt ||
104
106
  endedAt ||
105
- (event.kind === 'agent-ended' &&
107
+ (eventKind === 'agent-output' &&
106
108
  event.payload.duration_ms != null)) && (_jsxs(Text, { as: "p", children: [startedAt ? `Started: ${formatRelativeTime(startedAt)}` : '', startedAt && endedAt ? ' · ' : '', endedAt ? `Ended: ${formatRelativeTime(endedAt)}` : '', (startedAt || endedAt) &&
107
- event.kind === 'agent-ended' &&
109
+ eventKind === 'agent-output' &&
108
110
  event.payload.duration_ms != null
109
111
  ? ' · '
110
- : '', event.kind === 'agent-ended' && event.payload.duration_ms != null
111
- ? `Duration: ${(Number(event.payload.duration_ms) / 1000).toFixed(1)}s`
112
- : ''] })), event.kind?.includes('guardrail') && event.payload.message && (_jsx(Text, { as: "p", sx: { mb: 1 }, children: String(event.payload.message) })), event.kind?.includes('guardrail') && event.payload.action_taken && (_jsxs(Text, { as: "p", children: ["Action: ", String(event.payload.action_taken)] })), event.kind === 'agent-started' && event.payload.trigger_type && (_jsxs(Text, { as: "p", children: ["Trigger: ", String(event.payload.trigger_type)] })), outputText && (_jsx(Box, { sx: {
112
+ : '', eventKind === 'agent-output' && event.payload.duration_ms != null
113
+ ? `Duration: ${formatDurationMs(Number(event.payload.duration_ms))}`
114
+ : ''] })), eventKind.includes('guardrail') && event.payload.message && (_jsx(Text, { as: "p", sx: { mb: 1 }, children: String(event.payload.message) })), eventKind.includes('guardrail') && event.payload.action_taken && (_jsxs(Text, { as: "p", children: ["Action: ", String(event.payload.action_taken)] })), eventKind === 'agent-started' && event.payload.trigger_type && (_jsxs(Text, { as: "p", children: ["Trigger: ", String(event.payload.trigger_type)] })), outputText && (_jsx(Box, { sx: {
113
115
  mt: 2,
114
116
  p: 2,
115
117
  borderRadius: 2,
116
118
  border: '1px solid',
117
119
  borderColor: 'border.muted',
118
120
  bg: 'canvas.subtle',
119
- }, children: _jsxs(Box, { sx: { display: 'flex', alignItems: 'flex-start', gap: 1 }, children: [_jsx(Box, { sx: { flex: 1, minWidth: 0 }, children: _jsxs("details", { children: [_jsx("summary", { style: {
121
+ }, children: _jsxs(Box, { sx: { display: 'flex', alignItems: 'flex-start', gap: 1 }, children: [_jsx(Box, { sx: { flex: 1, minWidth: 0 }, children: _jsxs("details", { open: isOutputExpanded, children: [_jsx("summary", { onClick: e => {
122
+ e.preventDefault();
123
+ setIsOutputExpanded(prev => !prev);
124
+ }, style: {
120
125
  cursor: 'pointer',
121
126
  display: 'flex',
122
127
  alignItems: 'center',
@@ -128,7 +133,16 @@ export function NotificationEventCard({ event, onToggleRead, onDelete, onOpenAge
128
133
  minWidth: 0,
129
134
  width: '100%',
130
135
  flexWrap: 'nowrap',
131
- }, children: [_jsx(Text, { sx: {
136
+ }, children: [_jsx(Box, { sx: {
137
+ display: 'flex',
138
+ alignItems: 'center',
139
+ color: 'fg.muted',
140
+ flexShrink: 0,
141
+ transition: 'transform 0.15s ease',
142
+ transform: isOutputExpanded
143
+ ? 'rotate(180deg)'
144
+ : 'rotate(0deg)',
145
+ }, children: _jsx(ChevronDownIcon, { size: 12 }) }), _jsx(Text, { sx: {
132
146
  fontSize: 0,
133
147
  fontWeight: 'semibold',
134
148
  flexShrink: 0,
@@ -147,6 +161,17 @@ export function NotificationEventCard({ event, onToggleRead, onDelete, onOpenAge
147
161
  border: '1px solid',
148
162
  borderColor: 'border.muted',
149
163
  bg: 'canvas.subtle',
150
- }, children: _jsxs("details", { children: [_jsx("summary", { style: { cursor: 'pointer' }, children: _jsx(Text, { sx: { fontSize: 0, fontWeight: 'semibold' }, children: "View details" }) }), _jsx(Box, { sx: { mt: 2, display: 'grid', gap: 1 }, children: detailEntries.map(({ label, value }) => (_jsxs(Text, { sx: detailLineSx, children: [_jsxs(Text, { as: "span", sx: detailLabelSx, children: [label, ":", ' '] }), _jsx(Text, { as: "span", sx: detailValueSx, children: value })] }, label))) })] }) })] }))] }));
164
+ }, children: _jsxs("details", { open: isDetailsExpanded, children: [_jsx("summary", { onClick: e => {
165
+ e.preventDefault();
166
+ setIsDetailsExpanded(prev => !prev);
167
+ }, style: { cursor: 'pointer', display: 'flex', alignItems: 'center' }, children: _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1 }, children: [_jsx(Box, { sx: {
168
+ display: 'flex',
169
+ alignItems: 'center',
170
+ color: 'fg.muted',
171
+ transition: 'transform 0.15s ease',
172
+ transform: isDetailsExpanded
173
+ ? 'rotate(180deg)'
174
+ : 'rotate(0deg)',
175
+ }, children: _jsx(ChevronDownIcon, { size: 12 }) }), _jsx(Text, { sx: { fontSize: 0, fontWeight: 'semibold' }, children: "View details" })] }) }), _jsx(Box, { sx: { mt: 2, display: 'grid', gap: 1 }, children: detailEntries.map(({ label, value }) => (_jsxs(Text, { sx: detailLineSx, children: [_jsxs(Text, { as: "span", sx: detailLabelSx, children: [label, ":", ' '] }), _jsx(Text, { as: "span", sx: detailValueSx, children: value })] }, label))) })] }) })] }))] }));
151
176
  }
152
177
  export default NotificationEventCard;
@@ -3,14 +3,16 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  * Copyright (c) 2025-2026 Datalayer, Inc.
4
4
  * Distributed under the terms of the Modified BSD License.
5
5
  */
6
+ import { useState } from 'react';
6
7
  import { Button, Label, Text, Truncate } from '@primer/react';
7
8
  import { Box } from '@datalayer/primer-addons';
8
- import { DownloadIcon, EyeClosedIcon, EyeIcon, TrashIcon, } from '@primer/octicons-react';
9
- import { createMarkdownDownloadPayload, downloadTextPayload, formatRelativeTime, } from '@datalayer/core/lib/utils';
9
+ import { ChevronDownIcon, DownloadIcon, EyeClosedIcon, EyeIcon, TrashIcon, } from '@primer/octicons-react';
10
+ import { createMarkdownDownloadPayload, downloadTextPayload, formatDurationMs, formatRelativeTime, } from '@datalayer/core/lib/utils';
10
11
  import { Streamdown } from 'streamdown';
11
12
  import { streamdownMarkdownStyles } from '../chat/styles/streamdownStyles';
12
13
  export function OutputCard({ event, onToggleRead, onDelete, onOpenAgent, }) {
13
- const outputText = event.kind === 'agent-ended' && event.payload?.outputs
14
+ const [isOutputExpanded, setIsOutputExpanded] = useState(false);
15
+ const outputText = event.kind === 'agent-output' && event.payload?.outputs
14
16
  ? String(event.payload.outputs)
15
17
  : null;
16
18
  const runtimeId = String(event?.agent_id ||
@@ -20,7 +22,7 @@ export function OutputCard({ event, onToggleRead, onDelete, onOpenAgent, }) {
20
22
  'runtime');
21
23
  const startedAt = event?.started_at || event?.payload?.started_at || null;
22
24
  const endedAt = event?.ended_at || event?.payload?.ended_at || null;
23
- const durationMs = event.kind === 'agent-ended' ? event.payload?.duration_ms : null;
25
+ const durationMs = event.kind === 'agent-output' ? event.payload?.duration_ms : null;
24
26
  return (_jsxs(Box, { sx: {
25
27
  minWidth: 0,
26
28
  maxWidth: '100%',
@@ -44,14 +46,17 @@ export function OutputCard({ event, onToggleRead, onDelete, onOpenAgent, }) {
44
46
  minWidth: 0,
45
47
  flex: 1,
46
48
  }, children: [_jsx(Label, { variant: "success", children: "output" }), _jsx(Truncate, { maxWidth: "50%", title: String(event.title || runtimeId), sx: { fontWeight: 'semibold', fontSize: 1, minWidth: 0 }, children: event.title || runtimeId }), event.payload?.exit_status && (_jsxs(Label, { variant: "success", sx: { fontSize: 0, whiteSpace: 'nowrap' }, children: ["Status: ", String(event.payload.exit_status)] })), event.agent_id && (_jsx(Truncate, { maxWidth: 240, title: String(event.agent_id), children: _jsx(Label, { variant: "secondary", sx: { fontSize: 0, maxWidth: '100%' }, children: event.agent_id }) }))] }), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1, flexShrink: 0 }, children: [event.agent_id && onOpenAgent && (_jsx(Button, { size: "small", variant: "invisible", onClick: () => onOpenAgent(String(event.agent_id)), children: "Open agent" })), event.created_at && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted', whiteSpace: 'nowrap' }, children: new Date(event.created_at).toLocaleString() })), _jsx(Button, { size: "small", variant: "invisible", onClick: () => onToggleRead(event), sx: { p: 1 }, children: event.read ? _jsx(EyeClosedIcon, { size: 12 }) : _jsx(EyeIcon, { size: 12 }) }), _jsx(Button, { size: "small", variant: "invisible", onClick: () => onDelete(event), sx: { p: 1, color: 'danger.fg' }, children: _jsx(TrashIcon, { size: 12 }) })] })] }), (startedAt || endedAt || durationMs != null) && (_jsxs(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted', mb: 2 }, children: [startedAt ? `Started: ${formatRelativeTime(startedAt)}` : '', startedAt && endedAt ? ' · ' : '', endedAt ? `Ended: ${formatRelativeTime(endedAt)}` : '', (startedAt || endedAt) && durationMs != null ? ' · ' : '', durationMs != null
47
- ? `Duration: ${(Number(durationMs) / 1000).toFixed(1)}s`
49
+ ? `Duration: ${formatDurationMs(Number(durationMs))}`
48
50
  : ''] })), outputText && (_jsx(Box, { sx: {
49
51
  p: 2,
50
52
  borderRadius: 2,
51
53
  border: '1px solid',
52
54
  borderColor: 'border.muted',
53
55
  bg: 'canvas.subtle',
54
- }, children: _jsxs(Box, { sx: { display: 'flex', alignItems: 'flex-start', gap: 1 }, children: [_jsx(Box, { sx: { flex: 1, minWidth: 0 }, children: _jsxs("details", { children: [_jsx("summary", { style: {
56
+ }, children: _jsxs(Box, { sx: { display: 'flex', alignItems: 'flex-start', gap: 1 }, children: [_jsx(Box, { sx: { flex: 1, minWidth: 0 }, children: _jsxs("details", { open: isOutputExpanded, children: [_jsx("summary", { onClick: e => {
57
+ e.preventDefault();
58
+ setIsOutputExpanded(prev => !prev);
59
+ }, style: {
55
60
  cursor: 'pointer',
56
61
  display: 'flex',
57
62
  alignItems: 'center',
@@ -63,7 +68,16 @@ export function OutputCard({ event, onToggleRead, onDelete, onOpenAgent, }) {
63
68
  minWidth: 0,
64
69
  width: '100%',
65
70
  flexWrap: 'nowrap',
66
- }, children: [_jsx(Text, { sx: {
71
+ }, children: [_jsx(Box, { sx: {
72
+ display: 'flex',
73
+ alignItems: 'center',
74
+ color: 'fg.muted',
75
+ flexShrink: 0,
76
+ transition: 'transform 0.15s ease',
77
+ transform: isOutputExpanded
78
+ ? 'rotate(180deg)'
79
+ : 'rotate(0deg)',
80
+ }, children: _jsx(ChevronDownIcon, { size: 12 }) }), _jsx(Text, { sx: {
67
81
  fontSize: 0,
68
82
  fontWeight: 'semibold',
69
83
  flexShrink: 0,
@@ -3,9 +3,10 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  * Copyright (c) 2025-2026 Datalayer, Inc.
4
4
  * Distributed under the terms of the Modified BSD License.
5
5
  */
6
+ import { useState } from 'react';
6
7
  import { Button, Label, Text } from '@primer/react';
7
8
  import { Box } from '@datalayer/primer-addons';
8
- import { CheckCircleIcon, EyeClosedIcon, EyeIcon, TrashIcon, XCircleIcon, } from '@primer/octicons-react';
9
+ import { CheckCircleIcon, ChevronDownIcon, EyeClosedIcon, EyeIcon, TrashIcon, XCircleIcon, } from '@primer/octicons-react';
9
10
  import { formatRelativeTime } from '@datalayer/core/lib/utils';
10
11
  export const TOOL_APPROVAL_STATUS_CONFIG = {
11
12
  pending: { label: 'Pending', variant: 'attention' },
@@ -19,6 +20,7 @@ const RISK_CONFIG = {
19
20
  high: { label: 'High Risk', variant: 'severe' },
20
21
  };
21
22
  export function ToolApprovalCard({ approval, onApprove, onReject, onToggleRead, onDelete, }) {
23
+ const [isDetailsExpanded, setIsDetailsExpanded] = useState(false);
22
24
  const statusConfig = TOOL_APPROVAL_STATUS_CONFIG[approval.status];
23
25
  const riskConfig = RISK_CONFIG[approval.riskLevel];
24
26
  const parameterCount = approval.parameters
@@ -55,6 +57,22 @@ export function ToolApprovalCard({ approval, onApprove, onReject, onToggleRead,
55
57
  border: '1px solid',
56
58
  borderColor: 'border.muted',
57
59
  bg: 'canvas.subtle',
58
- }, children: _jsxs("details", { children: [_jsx("summary", { style: { cursor: 'pointer' }, children: _jsx(Text, { sx: { fontSize: 0, fontWeight: 'semibold' }, children: "View details" }) }), _jsxs(Box, { sx: { mt: 2, display: 'grid', gap: 1 }, children: [_jsxs(Text, { sx: detailLineSx, children: [_jsxs(Text, { as: "span", sx: detailLabelSx, children: ["Source:", ' '] }), _jsxs(Text, { as: "span", sx: detailValueSx, children: [approval.sourceName, " (", approval.sourceType, ")"] })] }), _jsxs(Text, { sx: detailLineSx, children: [_jsxs(Text, { as: "span", sx: detailLabelSx, children: ["Request ID:", ' '] }), _jsx(Text, { as: "span", sx: detailValueSx, children: approval.id })] }), _jsxs(Text, { sx: detailLineSx, children: [_jsxs(Text, { as: "span", sx: detailLabelSx, children: ["Requested at:", ' '] }), _jsx(Text, { as: "span", sx: detailValueSx, children: new Date(approval.requestedAt).toLocaleString() })] }), _jsxs(Text, { sx: detailLineSx, children: [_jsxs(Text, { as: "span", sx: detailLabelSx, children: ["Requested by:", ' '] }), _jsx(Text, { as: "span", sx: detailValueSx, children: approval.requestedBy })] }), approval.reviewedAt && (_jsxs(Text, { sx: detailLineSx, children: [_jsxs(Text, { as: "span", sx: detailLabelSx, children: ["Reviewed at:", ' '] }), _jsxs(Text, { as: "span", sx: detailValueSx, children: [new Date(approval.reviewedAt).toLocaleString(), " by", ' ', approval.reviewedBy || 'reviewer'] })] })), _jsxs(Text, { sx: detailLineSx, children: [_jsxs(Text, { as: "span", sx: detailLabelSx, children: ["Parameters:", ' '] }), _jsx(Text, { as: "span", sx: detailValueSx, children: parameterCount })] }), _jsxs(Text, { sx: detailLineSx, children: [_jsxs(Text, { as: "span", sx: detailLabelSx, children: ["Reason:", ' '] }), _jsx(Text, { as: "span", sx: detailValueSx, children: approval.reason || approval.toolDescription })] })] }), parameterCount > 0 && (_jsx(Box, { sx: { mt: 2, display: 'grid', gap: 1 }, children: Object.entries(approval.parameters || {}).map(([key, value]) => (_jsxs(Text, { sx: detailLineSx, children: [_jsxs(Text, { as: "span", sx: detailLabelSx, children: [key, ":", ' '] }), _jsx(Text, { as: "span", sx: detailValueSx, children: String(value) })] }, key))) }))] }) })] }), approval.status === 'pending' && (_jsxs(Box, { sx: { display: 'flex', gap: 2, flexShrink: 0 }, children: [_jsx(Button, { size: "small", variant: "primary", leadingVisual: CheckCircleIcon, onClick: () => onApprove?.(approval.id), children: "Approve" }), _jsx(Button, { size: "small", variant: "danger", leadingVisual: XCircleIcon, onClick: () => onReject?.(approval.id), children: "Reject" })] })), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1, flexShrink: 0 }, children: [_jsx(Button, { size: "small", variant: "invisible", onClick: () => onToggleRead?.(approval.id, isRead), sx: { p: 1 }, title: `Mark as ${isRead ? 'unread' : 'read'}`, "aria-label": `Mark as ${isRead ? 'unread' : 'read'}`, children: isRead ? _jsx(EyeClosedIcon, { size: 12 }) : _jsx(EyeIcon, { size: 12 }) }), _jsx(Button, { size: "small", variant: "invisible", onClick: () => onDelete?.(approval.id), sx: { p: 1, color: 'danger.fg' }, title: "Delete", "aria-label": "Delete", children: _jsx(TrashIcon, { size: 12 }) })] })] }) }));
60
+ }, children: _jsxs("details", { open: isDetailsExpanded, children: [_jsx("summary", { onClick: e => {
61
+ e.preventDefault();
62
+ setIsDetailsExpanded(prev => !prev);
63
+ }, style: {
64
+ cursor: 'pointer',
65
+ display: 'flex',
66
+ alignItems: 'center',
67
+ minWidth: 0,
68
+ }, children: _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1 }, children: [_jsx(Box, { sx: {
69
+ display: 'flex',
70
+ alignItems: 'center',
71
+ color: 'fg.muted',
72
+ transition: 'transform 0.15s ease',
73
+ transform: isDetailsExpanded
74
+ ? 'rotate(180deg)'
75
+ : 'rotate(0deg)',
76
+ }, children: _jsx(ChevronDownIcon, { size: 12 }) }), _jsx(Text, { sx: { fontSize: 0, fontWeight: 'semibold' }, children: "View details" })] }) }), _jsxs(Box, { sx: { mt: 2, display: 'grid', gap: 1 }, children: [_jsxs(Text, { sx: detailLineSx, children: [_jsxs(Text, { as: "span", sx: detailLabelSx, children: ["Source:", ' '] }), _jsxs(Text, { as: "span", sx: detailValueSx, children: [approval.sourceName, " (", approval.sourceType, ")"] })] }), _jsxs(Text, { sx: detailLineSx, children: [_jsxs(Text, { as: "span", sx: detailLabelSx, children: ["Request ID:", ' '] }), _jsx(Text, { as: "span", sx: detailValueSx, children: approval.id })] }), _jsxs(Text, { sx: detailLineSx, children: [_jsxs(Text, { as: "span", sx: detailLabelSx, children: ["Requested at:", ' '] }), _jsx(Text, { as: "span", sx: detailValueSx, children: new Date(approval.requestedAt).toLocaleString() })] }), _jsxs(Text, { sx: detailLineSx, children: [_jsxs(Text, { as: "span", sx: detailLabelSx, children: ["Requested by:", ' '] }), _jsx(Text, { as: "span", sx: detailValueSx, children: approval.requestedBy })] }), approval.reviewedAt && (_jsxs(Text, { sx: detailLineSx, children: [_jsxs(Text, { as: "span", sx: detailLabelSx, children: ["Reviewed at:", ' '] }), _jsxs(Text, { as: "span", sx: detailValueSx, children: [new Date(approval.reviewedAt).toLocaleString(), " by", ' ', approval.reviewedBy || 'reviewer'] })] })), _jsxs(Text, { sx: detailLineSx, children: [_jsxs(Text, { as: "span", sx: detailLabelSx, children: ["Parameters:", ' '] }), _jsx(Text, { as: "span", sx: detailValueSx, children: parameterCount })] }), _jsxs(Text, { sx: detailLineSx, children: [_jsxs(Text, { as: "span", sx: detailLabelSx, children: ["Reason:", ' '] }), _jsx(Text, { as: "span", sx: detailValueSx, children: approval.reason || approval.toolDescription })] })] }), parameterCount > 0 && (_jsx(Box, { sx: { mt: 2, display: 'grid', gap: 1 }, children: Object.entries(approval.parameters || {}).map(([key, value]) => (_jsxs(Text, { sx: detailLineSx, children: [_jsxs(Text, { as: "span", sx: detailLabelSx, children: [key, ":", ' '] }), _jsx(Text, { as: "span", sx: detailValueSx, children: String(value) })] }, key))) }))] }) })] }), approval.status === 'pending' && (_jsxs(Box, { sx: { display: 'flex', gap: 2, flexShrink: 0 }, children: [_jsx(Button, { size: "small", variant: "primary", leadingVisual: CheckCircleIcon, onClick: () => onApprove?.(approval.id), children: "Approve" }), _jsx(Button, { size: "small", variant: "danger", leadingVisual: XCircleIcon, onClick: () => onReject?.(approval.id), children: "Reject" })] })), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1, flexShrink: 0 }, children: [_jsx(Button, { size: "small", variant: "invisible", onClick: () => onToggleRead?.(approval.id, isRead), sx: { p: 1 }, title: `Mark as ${isRead ? 'unread' : 'read'}`, "aria-label": `Mark as ${isRead ? 'unread' : 'read'}`, children: isRead ? _jsx(EyeClosedIcon, { size: 12 }) : _jsx(EyeIcon, { size: 12 }) }), _jsx(Button, { size: "small", variant: "invisible", onClick: () => onDelete?.(approval.id), sx: { p: 1, color: 'danger.fg' }, title: "Delete", "aria-label": "Delete", children: _jsx(TrashIcon, { size: 12 }) })] })] }) }));
59
77
  }
60
78
  export default ToolApprovalCard;
@@ -25,6 +25,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
25
25
  import { Text, Button, IconButton, Spinner, Label, Flash, Heading, Tooltip, } from '@primer/react';
26
26
  import { AlertIcon, PlayIcon, SquareIcon, HistoryIcon, CheckCircleIcon, WorkflowIcon, SignOutIcon, XCircleIcon, ClockIcon, TagIcon, GlobeIcon, ZapIcon, GraphIcon, AiModelIcon, PeopleIcon, SidebarCollapseIcon, SidebarExpandIcon, SyncIcon, AgentIcon, } from '@primer/octicons-react';
27
27
  import { Box } from '@datalayer/primer-addons';
28
+ import { ErrorView } from './components';
28
29
  import { coreStore } from '@datalayer/core';
29
30
  import { ThemedProvider } from './utils/themedProvider';
30
31
  import { useSimpleAuthStore } from '@datalayer/core/lib/views/otel';
@@ -285,14 +286,7 @@ const AgentCheckpointsInner = ({ onLogout, }) => {
285
286
  isStarting;
286
287
  // ── Error ────────────────────────────────────────────────────────────────
287
288
  if (runtimeStatus === 'error' && !runtime) {
288
- return (_jsxs(Box, { sx: {
289
- display: 'flex',
290
- flexDirection: 'column',
291
- alignItems: 'center',
292
- justifyContent: 'center',
293
- height: '100vh',
294
- gap: 3,
295
- }, children: [_jsx(AlertIcon, { size: 48 }), _jsx(Text, { sx: { color: 'danger.fg', fontSize: 2 }, children: "Agent failed to start" }), _jsx(Text, { sx: { color: 'fg.muted' }, children: displayError })] }));
289
+ return _jsx(ErrorView, { detail: displayError, onLogout: onLogout });
296
290
  }
297
291
  // ── Running / Paused ─────────────────────────────────────────────────────
298
292
  return (_jsxs(Box, { sx: {
@@ -17,8 +17,9 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
17
17
  /// <reference types="vite/client" />
18
18
  import { useEffect, useState, useCallback, useRef } from 'react';
19
19
  import { Text, Button, Spinner, Heading, Label, Flash } from '@primer/react';
20
- import { AlertIcon, CodeIcon, DiffIcon, FileCodeIcon, CheckIcon, XIcon, SignOutIcon, } from '@primer/octicons-react';
20
+ import { CodeIcon, DiffIcon, FileCodeIcon, CheckIcon, XIcon, SignOutIcon, } from '@primer/octicons-react';
21
21
  import { Box } from '@datalayer/primer-addons';
22
+ import { ErrorView } from './components';
22
23
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
23
24
  import { useSimpleAuthStore } from '@datalayer/core/lib/views/otel';
24
25
  import { SignInSimple } from '@datalayer/core/lib/views/iam';
@@ -111,14 +112,7 @@ const AgentCodemodeInner = ({ onLogout, }) => {
111
112
  : 'Creating codemode demo agent…' })] }));
112
113
  }
113
114
  if (runtimeStatus === 'error' || hookError) {
114
- return (_jsxs(Box, { sx: {
115
- display: 'flex',
116
- flexDirection: 'column',
117
- alignItems: 'center',
118
- justifyContent: 'center',
119
- height: '100vh',
120
- gap: 3,
121
- }, children: [_jsx(AlertIcon, { size: 48 }), _jsx(Text, { sx: { color: 'danger.fg' }, children: hookError || 'Agent failed to start' })] }));
115
+ return _jsx(ErrorView, { error: hookError, onLogout: onLogout });
122
116
  }
123
117
  const selected = artifacts.find(a => a.id === selectedId) ?? artifacts[0] ?? null;
124
118
  const pendingCount = artifacts.filter(a => a.status === 'pending').length;
@@ -18,8 +18,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
18
18
  import { useEffect, useState, useCallback, useRef } from 'react';
19
19
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
20
20
  import { Text, Button, Spinner, Heading, Label, Flash, ProgressBar, } from '@primer/react';
21
- import { AlertIcon, BeakerIcon, CheckCircleIcon, XCircleIcon, PlayIcon, SignOutIcon, } from '@primer/octicons-react';
21
+ import { BeakerIcon, CheckCircleIcon, XCircleIcon, PlayIcon, SignOutIcon, } from '@primer/octicons-react';
22
22
  import { Box } from '@datalayer/primer-addons';
23
+ import { ErrorView } from './components';
23
24
  import { ThemedProvider } from './utils/themedProvider';
24
25
  import { useSimpleAuthStore } from '@datalayer/core/lib/views/otel';
25
26
  import { SignInSimple } from '@datalayer/core/lib/views/iam';
@@ -113,14 +114,7 @@ const AgentEvalsInner = ({ onLogout }) => {
113
114
  : 'Creating eval demo agent…' })] }));
114
115
  }
115
116
  if (runtimeStatus === 'error' || hookError) {
116
- return (_jsxs(Box, { sx: {
117
- display: 'flex',
118
- flexDirection: 'column',
119
- alignItems: 'center',
120
- justifyContent: 'center',
121
- height: '100vh',
122
- gap: 3,
123
- }, children: [_jsx(AlertIcon, { size: 48 }), _jsx(Text, { sx: { color: 'danger.fg' }, children: hookError || 'Agent failed to start' })] }));
117
+ return _jsx(ErrorView, { error: hookError, onLogout: onLogout });
124
118
  }
125
119
  const latestScore = evalRuns.length > 0 ? evalRuns[0].score : null;
126
120
  return (_jsxs(Box, { sx: {
@@ -18,8 +18,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
18
18
  import { useEffect, useState, useCallback, useRef } from 'react';
19
19
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
20
20
  import { Text, Button, Spinner, Heading, Label, Flash, ProgressBar, } from '@primer/react';
21
- import { AlertIcon, ShieldCheckIcon, CheckIcon, XIcon, SignOutIcon, } from '@primer/octicons-react';
21
+ import { ShieldCheckIcon, CheckIcon, XIcon, SignOutIcon, } from '@primer/octicons-react';
22
22
  import { Box } from '@datalayer/primer-addons';
23
+ import { ErrorView } from './components';
23
24
  import { ThemedProvider } from './utils/themedProvider';
24
25
  const queryClient = new QueryClient();
25
26
  import { useSimpleAuthStore } from '@datalayer/core/lib/views/otel';
@@ -142,14 +143,7 @@ const AgentGuardrailsInner = ({ onLogout, }) => {
142
143
  : 'Creating guardrails demo agent…' })] }));
143
144
  }
144
145
  if (runtimeStatus === 'error' || hookError) {
145
- return (_jsxs(Box, { sx: {
146
- display: 'flex',
147
- flexDirection: 'column',
148
- alignItems: 'center',
149
- justifyContent: 'center',
150
- height: '100vh',
151
- gap: 3,
152
- }, children: [_jsx(AlertIcon, { size: 48 }), _jsx(Text, { sx: { color: 'danger.fg' }, children: hookError || 'Agent failed to start' })] }));
146
+ return _jsx(ErrorView, { error: hookError, onLogout: onLogout });
153
147
  }
154
148
  const costPercent = Math.min((costUsd / COST_LIMIT_USD) * 100, 100);
155
149
  const costColor = costPercent > 80
@@ -18,8 +18,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
18
18
  import { useEffect, useState, useCallback, useRef } from 'react';
19
19
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
20
20
  import { Text, Button, Spinner, TextInput, Heading, Label, Flash, } from '@primer/react';
21
- import { AlertIcon, SearchIcon, DatabaseIcon, SignOutIcon, } from '@primer/octicons-react';
21
+ import { SearchIcon, DatabaseIcon, SignOutIcon, } from '@primer/octicons-react';
22
22
  import { Box } from '@datalayer/primer-addons';
23
+ import { ErrorView } from './components';
23
24
  import { ThemedProvider } from './utils/themedProvider';
24
25
  const queryClient = new QueryClient();
25
26
  import { useSimpleAuthStore } from '@datalayer/core/lib/views/otel';
@@ -116,14 +117,7 @@ const AgentMemoryInner = ({ onLogout }) => {
116
117
  : 'Creating memory-enabled agent…' })] }));
117
118
  }
118
119
  if (runtimeStatus === 'error' || hookError) {
119
- return (_jsxs(Box, { sx: {
120
- display: 'flex',
121
- flexDirection: 'column',
122
- alignItems: 'center',
123
- justifyContent: 'center',
124
- height: '100vh',
125
- gap: 3,
126
- }, children: [_jsx(AlertIcon, { size: 48 }), _jsx(Text, { sx: { color: 'danger.fg' }, children: hookError || 'Agent failed to start' })] }));
120
+ return _jsx(ErrorView, { error: hookError, onLogout: onLogout });
127
121
  }
128
122
  // ── Main layout ──────────────────────────────────────────────────────────
129
123
  return (_jsxs(Box, { sx: {
@@ -17,8 +17,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
17
17
  import { useEffect, useState, useCallback, useRef } from 'react';
18
18
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
19
19
  import { Text, Button, Spinner, Heading, Label } from '@primer/react';
20
- import { AlertIcon, CheckCircleIcon, GraphIcon, SignOutIcon, } from '@primer/octicons-react';
20
+ import { CheckCircleIcon, GraphIcon, SignOutIcon, } from '@primer/octicons-react';
21
21
  import { Box } from '@datalayer/primer-addons';
22
+ import { ErrorView } from './components';
22
23
  import { ThemedProvider } from './utils/themedProvider';
23
24
  const queryClient = new QueryClient();
24
25
  import { useSimpleAuthStore } from '@datalayer/core/lib/views/otel';
@@ -213,14 +214,7 @@ const AgentMonitoringInner = ({ onLogout, }) => {
213
214
  : 'Creating monitoring demo agent…' })] }));
214
215
  }
215
216
  if (runtimeStatus === 'error' || hookError) {
216
- return (_jsxs(Box, { sx: {
217
- display: 'flex',
218
- flexDirection: 'column',
219
- alignItems: 'center',
220
- justifyContent: 'center',
221
- height: '100vh',
222
- gap: 3,
223
- }, children: [_jsx(AlertIcon, { size: 48 }), _jsx(Text, { sx: { color: 'danger.fg' }, children: hookError || 'Agent failed to start' })] }));
217
+ return _jsx(ErrorView, { error: hookError, onLogout: onLogout });
224
218
  }
225
219
  const latest = snapshots[0] ?? createSyntheticSnapshot();
226
220
  return (_jsxs(Box, { sx: {
@@ -20,6 +20,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
20
20
  import { Text, Button, Spinner, Heading, Label, TextInput, Flash, Timeline, } from '@primer/react';
21
21
  import { AlertIcon, BellIcon, MailIcon, CheckCircleIcon, MuteIcon, SignOutIcon, } from '@primer/octicons-react';
22
22
  import { Box } from '@datalayer/primer-addons';
23
+ import { ErrorView } from './components';
23
24
  import { ThemedProvider } from './utils/themedProvider';
24
25
  import { useSimpleAuthStore } from '@datalayer/core/lib/views/otel';
25
26
  import { SignInSimple } from '@datalayer/core/lib/views/iam';
@@ -160,14 +161,7 @@ const AgentNotificationsInner = ({ onLogout, }) => {
160
161
  : 'Creating notification demo agent…' })] }));
161
162
  }
162
163
  if (runtimeStatus === 'error' || hookError) {
163
- return (_jsxs(Box, { sx: {
164
- display: 'flex',
165
- flexDirection: 'column',
166
- alignItems: 'center',
167
- justifyContent: 'center',
168
- height: '100vh',
169
- gap: 3,
170
- }, children: [_jsx(AlertIcon, { size: 48 }), _jsx(Text, { sx: { color: 'danger.fg' }, children: hookError || 'Agent failed to start' })] }));
164
+ return _jsx(ErrorView, { error: hookError, onLogout: onLogout });
171
165
  }
172
166
  const unreadCount = notifications.filter(n => !n.read).length;
173
167
  const channelIcon = (ch) => {
@@ -18,8 +18,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
18
18
  import { useEffect, useState, useCallback, useRef } from 'react';
19
19
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
20
20
  import { Text, Button, Spinner, Heading, Label } from '@primer/react';
21
- import { AlertIcon, TableIcon, FileIcon, CodeIcon, GraphIcon, DownloadIcon, SignOutIcon, } from '@primer/octicons-react';
21
+ import { TableIcon, FileIcon, CodeIcon, GraphIcon, DownloadIcon, SignOutIcon, } from '@primer/octicons-react';
22
22
  import { Box } from '@datalayer/primer-addons';
23
+ import { ErrorView } from './components';
23
24
  import { useSimpleAuthStore } from '@datalayer/core/lib/views/otel';
24
25
  import { SignInSimple } from '@datalayer/core/lib/views/iam';
25
26
  import { UserBadge } from '@datalayer/core/lib/views/profile';
@@ -90,14 +91,7 @@ const AgentOutputsInner = ({ onLogout, }) => {
90
91
  : 'Creating output demo agent…' })] }));
91
92
  }
92
93
  if (runtimeStatus === 'error' || hookError) {
93
- return (_jsxs(Box, { sx: {
94
- display: 'flex',
95
- flexDirection: 'column',
96
- alignItems: 'center',
97
- justifyContent: 'center',
98
- height: '100vh',
99
- gap: 3,
100
- }, children: [_jsx(AlertIcon, { size: 48 }), _jsx(Text, { sx: { color: 'danger.fg' }, children: hookError || 'Agent failed to start' })] }));
94
+ return _jsx(ErrorView, { error: hookError, onLogout: onLogout });
101
95
  }
102
96
  const filtered = artifacts.filter(a => a.type === activeTab);
103
97
  return (_jsxs(Box, { sx: {
@@ -21,8 +21,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
21
21
  import { useCallback, useEffect, useMemo, useRef, useState, } from 'react';
22
22
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
23
23
  import { Box } from '@datalayer/primer-addons';
24
+ import { ErrorView } from './components';
24
25
  import { Button, Flash, Heading, Label, SegmentedControl, Spinner, Text, } from '@primer/react';
25
- import { AlertIcon, CodeIcon, SignOutIcon, StopIcon, TerminalIcon, } from '@primer/octicons-react';
26
+ import { CodeIcon, SignOutIcon, StopIcon, TerminalIcon, } from '@primer/octicons-react';
26
27
  import { useSimpleAuthStore } from '@datalayer/core/lib/views/otel';
27
28
  import { SignInSimple } from '@datalayer/core/lib/views/iam';
28
29
  import { UserBadge } from '@datalayer/core/lib/views/profile';
@@ -343,14 +344,7 @@ const AgentSandboxInner = ({ onLogout, }) => {
343
344
  }
344
345
  // ── Error state ──
345
346
  if (runtimeStatus === 'error' || hookError) {
346
- return (_jsxs(Box, { sx: {
347
- display: 'flex',
348
- flexDirection: 'column',
349
- alignItems: 'center',
350
- justifyContent: 'center',
351
- height: '100vh',
352
- gap: 3,
353
- }, children: [_jsx(AlertIcon, { size: 48 }), _jsx(Text, { sx: { color: 'danger.fg' }, children: hookError || 'Agent failed to start' })] }));
347
+ return _jsx(ErrorView, { error: hookError, onLogout: onLogout });
354
348
  }
355
349
  // ── Sidebar ──
356
350
  const sidebar = (_jsxs(Box, { sx: {
@@ -7,8 +7,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
7
7
  import { useCallback, useEffect, 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, Label, Spinner, Text, Token as PrimerToken, } from '@primer/react';
11
- import { AlertIcon, BeakerIcon, BriefcaseIcon, PackageIcon, SignOutIcon, } from '@primer/octicons-react';
12
+ import { BeakerIcon, BriefcaseIcon, PackageIcon, SignOutIcon, } from '@primer/octicons-react';
12
13
  import { useSimpleAuthStore } from '@datalayer/core/lib/views/otel';
13
14
  import { SignInSimple } from '@datalayer/core/lib/views/iam';
14
15
  import { UserBadge } from '@datalayer/core/lib/views/profile';
@@ -187,14 +188,7 @@ const AgentSkillsInner = ({ onLogout }) => {
187
188
  }, children: [_jsx(Spinner, { size: "large" }), _jsx(Text, { sx: { color: 'fg.muted' }, children: "Launching skills demo agent..." })] }));
188
189
  }
189
190
  if (runtimeStatus === 'error' || hookError) {
190
- return (_jsxs(Box, { sx: {
191
- display: 'flex',
192
- flexDirection: 'column',
193
- alignItems: 'center',
194
- justifyContent: 'center',
195
- height: '100vh',
196
- gap: 3,
197
- }, children: [_jsx(AlertIcon, { size: 48 }), _jsx(Text, { sx: { color: 'danger.fg' }, children: hookError || 'Agent failed to start' })] }));
191
+ return _jsx(ErrorView, { error: hookError, onLogout: onLogout });
198
192
  }
199
193
  return (_jsxs(Box, { sx: {
200
194
  height: 'calc(100vh - 60px)',