@datalayer/core 1.2.28 → 1.2.29
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.
- package/lib/api/mcp/observability.d.ts +1 -1
- package/lib/api/mcp/observability.js +2 -0
- package/lib/api/mcp/operations.d.ts +28 -10
- package/lib/api/mcp/tasks.d.ts +9 -1
- package/lib/api/otel/firewall.d.ts +74 -0
- package/lib/api/otel/firewall.js +42 -0
- package/lib/api/otel/index.d.ts +1 -0
- package/lib/api/otel/index.js +1 -0
- package/lib/cli-login.js +2 -2
- package/lib/components/anonymous/AnonymousKeyExpired.js +15 -3
- package/lib/components/principal/PrincipalSwitcherMenu.js +4 -4
- package/lib/components/sharing/ShareAccessComponent.js +33 -8
- package/lib/components/toast/ToastPanel.js +18 -7
- package/lib/components/toast/toastQueue.d.ts +2 -0
- package/lib/hooks/index.d.ts +1 -0
- package/lib/hooks/index.js +1 -0
- package/lib/hooks/useCache.d.ts +4 -2
- package/lib/hooks/useCache.js +13 -4
- package/lib/hooks/useKeptScroll.d.ts +6 -0
- package/lib/hooks/useKeptScroll.js +54 -0
- package/lib/hooks/useMcp.d.ts +2 -2
- package/lib/hooks/useMcp.js +5 -2
- package/lib/hooks/useNavigate.d.ts +16 -2
- package/lib/hooks/useNavigate.js +65 -5
- package/lib/models/Usage.d.ts +13 -0
- package/lib/models/Usage.js +5 -0
- package/lib/otel/client/OtelClient.d.ts +56 -0
- package/lib/otel/client/OtelClient.js +25 -0
- package/lib/otel/client/index.d.ts +1 -1
- package/lib/otel/index.d.ts +1 -1
- package/lib/otel/views/OtelLive.js +1 -1
- package/lib/state/substates/LayoutState.js +24 -3
- package/lib/state/substates/NavigationState.d.ts +11 -3
- package/lib/state/substates/NavigationState.js +48 -5
- package/lib/views/mcp/McpObservability.d.ts +22 -3
- package/lib/views/mcp/McpObservability.js +65 -17
- package/lib/views/mcp/RunDetail.js +2 -2
- package/package.json +1 -1
|
@@ -10,6 +10,17 @@ import { TraceTimeline } from './TraceTimeline.js';
|
|
|
10
10
|
import { useNavigate } from '../../hooks/index.js';
|
|
11
11
|
import { MCP_METRIC_CATALOG } from '../../api/mcp/index.js';
|
|
12
12
|
import { durationLabel, timeAgo } from './format.js';
|
|
13
|
+
/** Every pane, in the order the switcher shows them. */
|
|
14
|
+
export const ALL_PANES = [
|
|
15
|
+
'runs',
|
|
16
|
+
'live',
|
|
17
|
+
'metrics',
|
|
18
|
+
];
|
|
19
|
+
const PANE_LABELS = {
|
|
20
|
+
runs: 'Runs',
|
|
21
|
+
live: 'Live',
|
|
22
|
+
metrics: 'Metrics',
|
|
23
|
+
};
|
|
13
24
|
/**
|
|
14
25
|
* What part of the platform a span belongs to, from its name.
|
|
15
26
|
*
|
|
@@ -71,8 +82,11 @@ const Sli = ({ label, value, note, }) => (_jsxs(Card, { border: true, shadow: "n
|
|
|
71
82
|
* second is usually a problem with the network between them, and sending
|
|
72
83
|
* somebody to the wrong one costs an hour.
|
|
73
84
|
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
85
|
+
* An engine taking work is healthy; a queue it was told to run that nobody
|
|
86
|
+
* serves is drawn as a warning beside it — work sent there is accepted and
|
|
87
|
+
* never done. The engine reports no backlog of its own (DBOS's pending and
|
|
88
|
+
* enqueued are both `running`), so what is running is counted among the
|
|
89
|
+
* newest runs it lists, and said as such.
|
|
76
90
|
*/
|
|
77
91
|
export const engineLook = (health, failed) => {
|
|
78
92
|
if (failed) {
|
|
@@ -85,26 +99,58 @@ export const engineLook = (health, failed) => {
|
|
|
85
99
|
if (!health) {
|
|
86
100
|
return { label: 'Asking…', variant: 'secondary', note: '' };
|
|
87
101
|
}
|
|
88
|
-
|
|
89
|
-
if (!health.healthy) {
|
|
102
|
+
if (!health.durable) {
|
|
90
103
|
return {
|
|
91
104
|
label: 'Unhealthy',
|
|
92
105
|
variant: 'danger',
|
|
93
|
-
note: health.detail || 'The engine reports
|
|
106
|
+
note: health.detail || 'The engine reports it is not taking work.',
|
|
94
107
|
};
|
|
95
108
|
}
|
|
109
|
+
const unserved = health.queuesNobodyServes ?? [];
|
|
110
|
+
if (unserved.length > 0) {
|
|
111
|
+
return {
|
|
112
|
+
label: 'Healthy',
|
|
113
|
+
variant: 'attention',
|
|
114
|
+
note: `Nobody serves ${unserved.join(', ')}: work sent there is accepted and never done.`,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
const running = (health.runs ?? []).filter(run => run.status === 'running').length;
|
|
96
118
|
return {
|
|
97
119
|
label: 'Healthy',
|
|
98
|
-
variant:
|
|
99
|
-
note:
|
|
100
|
-
? `${
|
|
101
|
-
: '
|
|
120
|
+
variant: 'success',
|
|
121
|
+
note: running > 0
|
|
122
|
+
? `${running} of its newest runs ${running === 1 ? 'is' : 'are'} running.`
|
|
123
|
+
: 'None of its newest runs is running.',
|
|
102
124
|
};
|
|
103
125
|
};
|
|
126
|
+
/** Each queue the engine polls, with how many of its newest runs are running there and the oldest of them. */
|
|
127
|
+
export const engineQueues = (health, now = Date.now()) => {
|
|
128
|
+
if (!health)
|
|
129
|
+
return [];
|
|
130
|
+
const unserved = health.queuesNobodyServes ?? [];
|
|
131
|
+
const names = [
|
|
132
|
+
...(health.queues ?? []),
|
|
133
|
+
...unserved.filter(name => !(health.queues ?? []).includes(name)),
|
|
134
|
+
];
|
|
135
|
+
return names.map(name => {
|
|
136
|
+
const running = (health.runs ?? []).filter(run => run.queue === name && run.status === 'running');
|
|
137
|
+
const started = running
|
|
138
|
+
.map(run => run.startedAt)
|
|
139
|
+
.filter((at) => typeof at === 'number');
|
|
140
|
+
return {
|
|
141
|
+
name,
|
|
142
|
+
running: running.length,
|
|
143
|
+
oldestSeconds: started.length
|
|
144
|
+
? Math.max(0, Math.round(now / 1000 - Math.min(...started)))
|
|
145
|
+
: undefined,
|
|
146
|
+
served: !unserved.includes(name),
|
|
147
|
+
};
|
|
148
|
+
});
|
|
149
|
+
};
|
|
104
150
|
const percentLabel = (value) => value === null || value === undefined
|
|
105
151
|
? 'Not measured'
|
|
106
152
|
: `${(value * 100).toFixed(1)}%`;
|
|
107
|
-
export const McpObservability = ({ errorState, routes, pane, onPaneChange, taskUid, traceId, onSelect, agent, org, showTitle = true, }) => {
|
|
153
|
+
export const McpObservability = ({ errorState, routes, pane, onPaneChange, panes = ALL_PANES, taskUid, traceId, onSelect, agent, org, showTitle = true, }) => {
|
|
108
154
|
const navigate = useNavigate();
|
|
109
155
|
const [find, setFind] = useState(taskUid ?? traceId ?? '');
|
|
110
156
|
// One of the two, never both: a task names its own trace, and a trace
|
|
@@ -120,7 +166,7 @@ export const McpObservability = ({ errorState, routes, pane, onPaneChange, taskU
|
|
|
120
166
|
const engine = useMcpWorkflowsHealth({ enabled: pane === 'live' });
|
|
121
167
|
const live = useTasks({ status: 'working' }, { enabled: pane === 'live' });
|
|
122
168
|
const telemetryNotice = (_jsxs(Text, { sx: { fontSize: 0, color: 'fg.subtle' }, children: ["This is telemetry: spans and metrics are sampled, kept for a short time and meant for understanding how a call ran. It is not the record of what was allowed \u2014", ' ', _jsx(Text, { as: "span", sx: { color: 'accent.fg', cursor: 'pointer' }, onClick: () => navigate(routes.audit), children: "the audit log" }), ' ', "is, and it is kept per plan and never changed."] }));
|
|
123
|
-
return (_jsxs(Box, { display: "grid", gap: 3, minWidth: 0, children: [showTitle && (_jsxs(Box, { children: [_jsx(Heading, { as: "h2", sx: { fontSize: 3, mb: 1 }, children: "Observability" }), _jsx(Text, { as: "p", sx: { color: 'fg.muted', fontSize: 1, m: 0 }, children: "How the calls of your agents ran: where the time went, and how the service is behaving." })] })),
|
|
169
|
+
return (_jsxs(Box, { display: "grid", gap: 3, minWidth: 0, children: [showTitle && (_jsxs(Box, { children: [_jsx(Heading, { as: "h2", sx: { fontSize: 3, mb: 1 }, children: "Observability" }), _jsx(Text, { as: "p", sx: { color: 'fg.muted', fontSize: 1, m: 0 }, children: "How the calls of your agents ran: where the time went, and how the service is behaving." })] })), panes.length > 1 && (_jsx(SegmentedControl, { "aria-label": "Observability panes", size: "small", children: panes.map(each => (_jsx(SegmentedControl.Button, { selected: pane === each, onClick: () => onPaneChange(each), children: PANE_LABELS[each] }, each))) })), telemetryNotice, pane === 'runs' && (_jsxs(Box, { display: "grid", gap: 3, children: [_jsxs(Box, { display: "flex", gap: 2, alignItems: "center", flexWrap: "wrap", children: [_jsx(TextInput, { size: "small", leadingVisual: SearchIcon, "aria-label": "Task or trace id", placeholder: "Task uid or trace id", value: find, sx: { minWidth: 320 }, onChange: event => setFind(event.currentTarget.value) }), _jsx(Button, { size: "small", onClick: () => {
|
|
124
170
|
const value = find.trim();
|
|
125
171
|
if (!value) {
|
|
126
172
|
onSelect({});
|
|
@@ -131,16 +177,18 @@ export const McpObservability = ({ errorState, routes, pane, onPaneChange, taskU
|
|
|
131
177
|
onSelect(/^[0-9a-f]{32}$/i.test(value)
|
|
132
178
|
? { trace: value }
|
|
133
179
|
: { task: value });
|
|
134
|
-
}, children: "Show the run" })] }), !taskUid && !traceId ? (_jsxs(Blankslate, { border: true, spacious: true, children: [_jsx(Blankslate.Visual, { children: _jsx(TelescopeIcon, { size: "medium" }) }), _jsx(Blankslate.Heading, { children: "Pick a run" }), _jsx(Blankslate.Description, { children: _jsx(Text, { sx: { textAlign: 'center' }, children: "Open a call from the audit log or the dashboard, or paste its task uid or trace id here, and its spans across the gateway, the policy check and the worker appear with the time each took." }) }), _jsx(Button, { size: "small", onClick: () => navigate(routes.audit), children: "Open the audit log" })] })) : run.isError ? (_jsx(McpErrorBlankslate, { state: errorState(run.error, 'This run'), onRetry: () => run.refetch() })) : run.isPending ? (_jsx(Box, { display: "flex", justifyContent: "center", py: 5, children: _jsx(Spinner, {}) })) : (run.data?.spans.length ?? 0) === 0 ? (_jsxs(Blankslate, { border: true, spacious: true, children: [_jsx(Blankslate.Visual, { children: _jsx(TelescopeIcon, { size: "medium" }) }), _jsx(Blankslate.Heading, { children: "No span for this call" }), _jsx(Blankslate.Description, { children: _jsx(Text, { sx: { textAlign: 'center' }, children: "Spans reach the collector a few seconds after the call and are kept for a short time. A call older than the retention window has an audit row but no trace." }) })] })) : (_jsxs(Box, { display: "grid", gap: 2, children: [_jsxs(Box, { display: "flex", gap: 3, alignItems: "center", flexWrap: "wrap", children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted', fontFamily: 'mono' }, children: run.data?.traceId }), _jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: [run.data?.spans.length, " spans"] }), _jsx(Button, { size: "small", onClick: () => navigate(`${routes.audit}?trace=${encodeURIComponent(run.data?.traceId ?? '')}`), children: "The audit row" })] }), _jsx(TraceTimeline, { tree: run.data?.tree ?? [] }), _jsx(Card, { border: true, shadow: "none", display: "block", overflowX: "auto", children: (run.data?.tree ?? []).map(node => (_jsx(SpanRow, { node: node, depth: 0 }, node.span.span_id))) })] }))] })), pane === 'live' && (_jsxs(Box, { display: "grid", gap: 3, children: [(() => {
|
|
135
|
-
const look = engineLook(engine.data, engine.isError);
|
|
136
|
-
const queues = engine.data?.queues ?? [];
|
|
137
|
-
return (_jsxs(Card, { border: true, shadow: "none", p: 3, display: "grid", gap: 2, children: [_jsxs(Box, { display: "flex", gap: 2, alignItems: "center", flexWrap: "wrap", children: [_jsx(Heading, { as: "h3", sx: { fontSize: 1 }, children: "The durable engine" }), _jsx(Label, { size: "small", variant: look.variant, children: look.label }), engine.data?.engine && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: engine.data.engine }))] }), look.note && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: look.note })), queues.length > 0 && (_jsx(Box, { display: "grid", gap: 1, children: queues.map(queue => (_jsxs(Box, { display: "flex", gap: 2, alignItems: "center", fontSize: 0, children: [_jsx(Text, { sx: { fontFamily: 'mono' }, children: queue.name }), _jsxs(Text, { sx: { color: 'fg.muted' }, children: [queue.backlog, " waiting"] }), typeof queue.oldestWaitSeconds === 'number' && (_jsxs(Text, { sx: { color: 'fg.muted' }, children: ["oldest", ' ', durationLabel(queue.oldestWaitSeconds * 1000)] }))] }, queue.name))) }))] }));
|
|
138
|
-
})(), _jsxs(Box, { display: "grid", gap: 2, children: [_jsx(Heading, { as: "h3", sx: { fontSize: 1 }, children: "Running now" }), live.isError ? (_jsx(McpErrorBlankslate, { state: errorState(live.error, 'The running calls'), onRetry: () => live.refetch() })) : live.isPending ? (_jsx(Box, { display: "flex", justifyContent: "center", py: 4, children: _jsx(Spinner, {}) })) : (live.data?.items.length ?? 0) === 0 ? (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Nothing of yours is running. A call that finishes inside its own request never appears here \u2014 it is over before this pane could draw it \u2014 and is found by its trace in Runs." })) : ((live.data?.items ?? []).map(task => (_jsxs(Box, { display: "flex", gap: 2, alignItems: "center", flexWrap: "wrap", py: 1, borderBottom: "1px solid", borderColor: "border.muted", children: [_jsx(Label, { size: "small", variant: "success", children: "Working" }), _jsx(Text, { sx: { fontSize: 0 }, children: task.tool || 'Run' }), _jsx(Text, { sx: {
|
|
180
|
+
}, children: "Show the run" })] }), !taskUid && !traceId ? (_jsxs(Blankslate, { border: true, spacious: true, children: [_jsx(Blankslate.Visual, { children: _jsx(TelescopeIcon, { size: "medium" }) }), _jsx(Blankslate.Heading, { children: "Pick a run" }), _jsx(Blankslate.Description, { children: _jsx(Text, { sx: { textAlign: 'center' }, children: "Open a call from the audit log or the dashboard, or paste its task uid or trace id here, and its spans across the gateway, the policy check and the worker appear with the time each took." }) }), _jsx(Button, { size: "small", onClick: () => navigate(routes.audit), children: "Open the audit log" })] })) : run.isError ? (_jsx(McpErrorBlankslate, { state: errorState(run.error, 'This run'), onRetry: () => run.refetch() })) : run.isPending ? (_jsx(Box, { display: "flex", justifyContent: "center", py: 5, children: _jsx(Spinner, {}) })) : (run.data?.spans.length ?? 0) === 0 ? (_jsxs(Blankslate, { border: true, spacious: true, children: [_jsx(Blankslate.Visual, { children: _jsx(TelescopeIcon, { size: "medium" }) }), _jsx(Blankslate.Heading, { children: "No span for this call" }), _jsx(Blankslate.Description, { children: _jsx(Text, { sx: { textAlign: 'center' }, children: "Spans reach the collector a few seconds after the call and are kept for a short time. A call older than the retention window has an audit row but no trace." }) })] })) : (_jsxs(Box, { display: "grid", gap: 2, children: [_jsxs(Box, { display: "flex", gap: 3, alignItems: "center", flexWrap: "wrap", children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted', fontFamily: 'mono' }, children: run.data?.traceId }), _jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: [run.data?.spans.length, " spans"] }), _jsx(Button, { size: "small", onClick: () => navigate(`${routes.audit}?trace=${encodeURIComponent(run.data?.traceId ?? '')}`), children: "The audit row" })] }), _jsx(TraceTimeline, { tree: run.data?.tree ?? [] }), _jsx(Card, { border: true, shadow: "none", display: "block", overflowX: "auto", children: (run.data?.tree ?? []).map(node => (_jsx(SpanRow, { node: node, depth: 0 }, node.span.span_id))) })] }))] })), pane === 'live' && (_jsxs(Box, { display: "grid", gap: 3, children: [_jsxs(Card, { border: true, shadow: "none", p: 3, display: "grid", gap: 2, children: [_jsx(Heading, { as: "h3", sx: { fontSize: 1 }, children: "Running now" }), live.isError ? (_jsx(McpErrorBlankslate, { state: errorState(live.error, 'The running calls'), onRetry: () => live.refetch() })) : live.isPending ? (_jsx(Box, { display: "flex", justifyContent: "center", py: 4, children: _jsx(Spinner, {}) })) : (live.data?.items.length ?? 0) === 0 ? (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Nothing of yours is running. A call that finishes inside its own request never appears here \u2014 it is over before this pane could draw it \u2014 and is found by its trace in Runs." })) : ((live.data?.items ?? []).map(task => (_jsxs(Box, { display: "flex", gap: 2, alignItems: "center", flexWrap: "wrap", py: 1, borderBottom: "1px solid", borderColor: "border.muted", children: [_jsx(Label, { size: "small", variant: "success", children: "Working" }), _jsx(Text, { sx: { fontSize: 0 }, children: task.tool || 'Run' }), _jsx(Text, { sx: {
|
|
139
181
|
fontSize: 0,
|
|
140
182
|
fontFamily: 'mono',
|
|
141
183
|
color: 'accent.fg',
|
|
142
184
|
cursor: 'pointer',
|
|
143
|
-
}, onClick: () => onSelect({ task: task.uid }), children: task.uid }), _jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: ["started ", timeAgo(task.createdAt)] })] }, task.uid))))] })
|
|
185
|
+
}, onClick: () => onSelect({ task: task.uid }), children: task.uid }), _jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: ["started ", timeAgo(task.createdAt)] })] }, task.uid))))] }), (() => {
|
|
186
|
+
const look = engineLook(engine.data, engine.isError);
|
|
187
|
+
const queues = engineQueues(engine.data);
|
|
188
|
+
return (_jsxs(Card, { border: true, shadow: "none", p: 3, display: "grid", gap: 2, children: [_jsxs(Box, { display: "flex", gap: 2, alignItems: "center", flexWrap: "wrap", children: [_jsx(Heading, { as: "h3", sx: { fontSize: 1 }, children: "The durable engine" }), _jsx(Label, { size: "small", variant: look.variant, children: look.label }), engine.data?.engine && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: engine.data.engine }))] }), look.note && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: look.note })), queues.length > 0 && (_jsx(Box, { display: "grid", gap: 1, children: queues.map(queue => (_jsxs(Box, { display: "flex", gap: 2, alignItems: "center", fontSize: 0, children: [_jsx(Text, { sx: { fontFamily: 'mono' }, children: queue.name }), queue.served ? (_jsx(Text, { sx: { color: 'fg.muted' }, children: queue.running > 0
|
|
189
|
+
? `${queue.running} running`
|
|
190
|
+
: 'idle' })) : (_jsx(Label, { size: "small", variant: "attention", children: "nobody serves it" })), typeof queue.oldestSeconds === 'number' && (_jsxs(Text, { sx: { color: 'fg.muted' }, children: ["oldest ", durationLabel(queue.oldestSeconds * 1000)] }))] }, queue.name))) }))] }));
|
|
191
|
+
})()] })), pane === 'metrics' && (_jsx(Box, { display: "grid", gap: 3, children: metrics.isError ? (_jsx(McpErrorBlankslate, { state: errorState(metrics.error, 'Metrics'), onRetry: () => metrics.refetch() })) : metrics.isPending && !metrics.data ? (_jsx(Box, { display: "flex", justifyContent: "center", py: 5, children: _jsx(Spinner, {}) })) : (_jsxs(_Fragment, { children: [_jsxs(Box, { display: "grid", gap: 3, gridTemplateColumns: [
|
|
144
192
|
'1fr',
|
|
145
193
|
'repeat(2, 1fr)',
|
|
146
194
|
'repeat(4, 1fr)',
|
|
@@ -160,8 +160,8 @@ export const RunDetail = ({ taskUid, errorState, routes, mock = false, }) => {
|
|
|
160
160
|
return (_jsxs(Box, { display: "grid", gap: 3, minWidth: 0, children: [_jsxs(Box, { children: [_jsx(Link, { href: routes.runs, onClick: event => {
|
|
161
161
|
event.preventDefault();
|
|
162
162
|
navigate(routes.runs);
|
|
163
|
-
}, sx: { fontSize: 0 }, children: "All runs" }), _jsx(Heading, { as: "h2", sx: { fontSize: 3, mt: 1, mb: 1 }, children: task.tool || 'Run' }), _jsxs(Box, { display: "flex", gap: 2, alignItems: "center", flexWrap: "wrap", children: [_jsx(Label, { size: "small", variant: look.variant, children: look.label }), _jsx(Text, { sx: { fontFamily: 'mono', fontSize: 0, color: 'fg.muted' }, children: task.uid }), _jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: ["updated ", _jsx(RelativeTime, { datetime: task.lastUpdatedAt })] })] }), task.statusMessage && (_jsx(Text, { as: "p", sx: { fontSize: 1, color: 'fg.muted', mt: 2 }, children: task.statusMessage }))] }), task.status === 'input_required' && (_jsxs(Box, { borderWidth: 1, borderStyle: "solid", borderColor: "attention.emphasis", borderRadius: 2, p: 3, display: "grid", gap: 2, children: [_jsx(Heading, { as: "h3", sx: { fontSize: 1 }, children: "This run is waiting on you" }), _jsx(Textarea, { "aria-label": "Your answer", value: reply, onChange: event => setReply(event.target.value), placeholder: "Your answer", rows: 3 }),
|
|
163
|
+
}, sx: { fontSize: 0 }, children: "All runs" }), _jsx(Heading, { as: "h2", sx: { fontSize: 3, mt: 1, mb: 1 }, children: task.tool || 'Run' }), _jsxs(Box, { display: "flex", gap: 2, alignItems: "center", flexWrap: "wrap", children: [_jsx(Label, { size: "small", variant: look.variant, children: look.label }), _jsx(Text, { sx: { fontFamily: 'mono', fontSize: 0, color: 'fg.muted' }, children: task.uid }), _jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: ["updated ", _jsx(RelativeTime, { datetime: task.lastUpdatedAt })] })] }), task.statusMessage && (_jsx(Text, { as: "p", sx: { fontSize: 1, color: 'fg.muted', mt: 2 }, children: task.statusMessage }))] }), task.status === 'input_required' && (_jsxs(Box, { borderWidth: 1, borderStyle: "solid", borderColor: "attention.emphasis", borderRadius: 2, p: 3, display: "grid", gap: 2, children: [_jsx(Heading, { as: "h3", sx: { fontSize: 1 }, children: "This run is waiting on you" }), _jsx(Textarea, { "aria-label": "Your answer", value: reply, onChange: event => setReply(event.target.value), placeholder: "Your answer", rows: 3 }), _jsxs(Box, { children: [_jsx(Button, { variant: "primary", disabled: !reply.trim() || answer.isPending, onClick: () => answer.mutate({ taskUid: task.uid, input: { answer: reply } }, { onSuccess: () => setReply('') }), children: answer.isPending ? 'Answering…' : 'Answer' }), answer.error && (_jsxs(Text, { as: "p", sx: { fontSize: 0, color: 'danger.fg', mt: 2 }, children: ["The answer did not reach the run: ", answer.error.message] }))] })] })), _jsxs(Box, { children: [_jsx(Heading, { as: "h3", sx: { fontSize: 1, mb: 2 }, children: "Output" }), output ? (_jsx(Box, { as: "pre", fontFamily: "mono", fontSize: 0, whiteSpace: "pre-wrap", overflowX: "auto", bg: "canvas.subtle", borderRadius: 2, p: 3, m: 0, children: output })) : (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: over
|
|
164
164
|
? 'This run printed nothing.'
|
|
165
|
-
: 'Nothing printed yet. Output appears here as it arrives.' }))] }), failure && (_jsxs(Box, { children: [_jsx(Heading, { as: "h3", sx: { fontSize: 1, mb: 2 }, children: "Why it failed" }), _jsx(Text, { sx: { fontFamily: 'mono', fontSize: 0, color: 'danger.fg' }, children: failure })] })), _jsx(TraceTimelineSection, { tree: mock ? SAMPLE_TRACE : (trace.data?.tree ?? []), traceId: mock ? SAMPLE_TRACE[0].span.trace_id : trace.data?.traceId, live: !over }), !over && (_jsxs(Box, { children: [_jsx(Button, { variant: "danger", disabled: cancel.isPending, onClick: () => cancel.mutate(task.uid), children: cancel.isPending ? 'Cancelling…' : 'Cancel this run' }), _jsx(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted', mt: 2 }, children: "Cancelling interrupts the work itself, so the sandbox stops being billed for it. What it has already printed is kept." })] }))] }));
|
|
165
|
+
: 'Nothing printed yet. Output appears here as it arrives.' }))] }), failure && (_jsxs(Box, { children: [_jsx(Heading, { as: "h3", sx: { fontSize: 1, mb: 2 }, children: "Why it failed" }), _jsx(Text, { sx: { fontFamily: 'mono', fontSize: 0, color: 'danger.fg' }, children: failure })] })), _jsx(TraceTimelineSection, { tree: mock ? SAMPLE_TRACE : (trace.data?.tree ?? []), traceId: mock ? SAMPLE_TRACE[0].span.trace_id : trace.data?.traceId, live: !over }), !over && (_jsxs(Box, { children: [_jsx(Button, { variant: "danger", disabled: cancel.isPending, onClick: () => cancel.mutate(task.uid), children: cancel.isPending ? 'Cancelling…' : 'Cancel this run' }), cancel.error && (_jsxs(Text, { as: "p", sx: { fontSize: 0, color: 'danger.fg', mt: 2 }, children: ["The run was not cancelled: ", cancel.error.message] })), _jsx(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted', mt: 2 }, children: "Cancelling interrupts the work itself, so the sandbox stops being billed for it. What it has already printed is kept." })] }))] }));
|
|
166
166
|
};
|
|
167
167
|
export default RunDetail;
|