@lumea-labs/orchestrator 0.1.0
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/README.md +21 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +93 -0
- package/dist/lib/format.d.ts +3 -0
- package/dist/lib/format.js +9 -0
- package/dist/orchestrator-document.d.ts +37 -0
- package/dist/orchestrator-document.js +122 -0
- package/dist/plan-detail.d.ts +102 -0
- package/dist/plan-detail.js +385 -0
- package/dist/plan-graph.d.ts +39 -0
- package/dist/plan-graph.js +597 -0
- package/dist/plan-node-detail.d.ts +29 -0
- package/dist/plan-node-detail.js +346 -0
- package/dist/plan-task-detail.d.ts +76 -0
- package/dist/plan-task-detail.js +450 -0
- package/dist/plan-types.d.ts +85 -0
- package/dist/plan-types.js +51 -0
- package/dist/run-kanban-filter-menu.d.ts +24 -0
- package/dist/run-kanban-filter-menu.js +152 -0
- package/dist/run-kanban.d.ts +61 -0
- package/dist/run-kanban.js +234 -0
- package/dist/swarm-agent-badge.d.ts +15 -0
- package/dist/swarm-agent-badge.js +39 -0
- package/dist/swarm-run-activity.d.ts +39 -0
- package/dist/swarm-run-activity.js +289 -0
- package/dist/swarm-run-card.d.ts +22 -0
- package/dist/swarm-run-card.js +91 -0
- package/dist/swarm-run-detail.d.ts +45 -0
- package/dist/swarm-run-detail.js +559 -0
- package/dist/swarm-run-list.d.ts +22 -0
- package/dist/swarm-run-list.js +75 -0
- package/dist/swarm-run-row.d.ts +22 -0
- package/dist/swarm-run-row.js +125 -0
- package/dist/swarm-skeletons.d.ts +28 -0
- package/dist/swarm-skeletons.js +78 -0
- package/dist/swarm-status-bar.d.ts +15 -0
- package/dist/swarm-status-bar.js +79 -0
- package/dist/swarm-status-pill.d.ts +12 -0
- package/dist/swarm-status-pill.js +86 -0
- package/dist/swarm-timeline.d.ts +21 -0
- package/dist/swarm-timeline.js +414 -0
- package/dist/task-workspace-sidebar.d.ts +71 -0
- package/dist/task-workspace-sidebar.js +352 -0
- package/dist/types.d.ts +285 -0
- package/dist/types.js +44 -0
- package/package.json +41 -0
|
@@ -0,0 +1,559 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
useLayoutEffect,
|
|
4
|
+
useRef,
|
|
5
|
+
useState
|
|
6
|
+
} from "react";
|
|
7
|
+
import {
|
|
8
|
+
ChevronDown,
|
|
9
|
+
ExternalLink,
|
|
10
|
+
FileText,
|
|
11
|
+
Hash,
|
|
12
|
+
Image as ImageIcon,
|
|
13
|
+
RotateCcw,
|
|
14
|
+
Square,
|
|
15
|
+
StickyNote,
|
|
16
|
+
X
|
|
17
|
+
} from "lucide-react";
|
|
18
|
+
import {
|
|
19
|
+
defaultSwarmLabels
|
|
20
|
+
} from "./types";
|
|
21
|
+
import { elapsedSeconds } from "./lib/format";
|
|
22
|
+
import { SwarmStatusPill } from "./swarm-status-pill";
|
|
23
|
+
import { SwarmAgentBadge } from "./swarm-agent-badge";
|
|
24
|
+
function SwarmRunDetail({
|
|
25
|
+
run,
|
|
26
|
+
now,
|
|
27
|
+
variant = "tabs",
|
|
28
|
+
renderAvatar,
|
|
29
|
+
renderToolCalls,
|
|
30
|
+
renderArtifacts,
|
|
31
|
+
renderEvaluation,
|
|
32
|
+
renderMarkdown,
|
|
33
|
+
hideTools = false,
|
|
34
|
+
onClose,
|
|
35
|
+
onCancel,
|
|
36
|
+
onRetry,
|
|
37
|
+
labels,
|
|
38
|
+
className
|
|
39
|
+
}) {
|
|
40
|
+
const L = { ...defaultSwarmLabels, ...labels };
|
|
41
|
+
const clock = now ?? Date.now();
|
|
42
|
+
const elapsed = elapsedSeconds(run.startedAt, run.finishedAt, clock);
|
|
43
|
+
const isLive = run.status === "running" || run.status === "pending";
|
|
44
|
+
const showCancel = onCancel && isLive;
|
|
45
|
+
const showRetry = onRetry && (run.status === "failed" || run.status === "cancelled");
|
|
46
|
+
return /* @__PURE__ */ React.createElement(
|
|
47
|
+
"section",
|
|
48
|
+
{
|
|
49
|
+
className: [
|
|
50
|
+
"flex h-full min-h-0 flex-col overflow-hidden rounded-2xl border border-p-line bg-p-surface",
|
|
51
|
+
className || ""
|
|
52
|
+
].join(" ")
|
|
53
|
+
},
|
|
54
|
+
/* @__PURE__ */ React.createElement("header", { className: "flex shrink-0 flex-wrap items-center gap-2 border-b border-p-line px-4 py-3" }, /* @__PURE__ */ React.createElement(SwarmAgentBadge, { agent: run.agent, avatar: renderAvatar?.(run.agent) }), /* @__PURE__ */ React.createElement("span", { className: "ml-auto inline-flex items-center gap-1" }, showCancel ? /* @__PURE__ */ React.createElement(
|
|
55
|
+
"button",
|
|
56
|
+
{
|
|
57
|
+
type: "button",
|
|
58
|
+
onClick: () => onCancel(run.id),
|
|
59
|
+
className: "inline-flex items-center gap-1 rounded-md px-2 py-1 font-mono text-[10.5px] font-bold uppercase tracking-[0.16em] text-p-ink-3 transition-colors cursor-pointer hover:bg-p-warm hover:text-[#E63946]"
|
|
60
|
+
},
|
|
61
|
+
/* @__PURE__ */ React.createElement(Square, { className: "size-2.5" }),
|
|
62
|
+
L.cancel
|
|
63
|
+
) : null, showRetry ? /* @__PURE__ */ React.createElement(
|
|
64
|
+
"button",
|
|
65
|
+
{
|
|
66
|
+
type: "button",
|
|
67
|
+
onClick: () => onRetry(run.id),
|
|
68
|
+
className: "inline-flex items-center gap-1 rounded-md px-2 py-1 font-mono text-[10.5px] font-bold uppercase tracking-[0.16em] text-p-ink-3 transition-colors cursor-pointer hover:bg-p-warm hover:text-p-ink"
|
|
69
|
+
},
|
|
70
|
+
/* @__PURE__ */ React.createElement(RotateCcw, { className: "size-2.5" }),
|
|
71
|
+
L.retry
|
|
72
|
+
) : null, onClose ? /* @__PURE__ */ React.createElement(
|
|
73
|
+
"button",
|
|
74
|
+
{
|
|
75
|
+
type: "button",
|
|
76
|
+
onClick: onClose,
|
|
77
|
+
"aria-label": "Close",
|
|
78
|
+
title: "Close",
|
|
79
|
+
className: "grid size-7 place-items-center rounded-md text-p-ink-3 transition-colors cursor-pointer hover:bg-p-warm hover:text-p-ink"
|
|
80
|
+
},
|
|
81
|
+
/* @__PURE__ */ React.createElement(X, { className: "size-4" })
|
|
82
|
+
) : null)),
|
|
83
|
+
/* @__PURE__ */ React.createElement(VitalSigns, { run, L, isLive, elapsed }),
|
|
84
|
+
/* @__PURE__ */ React.createElement("div", { className: "border-b border-p-line px-4 py-3" }, /* @__PURE__ */ React.createElement("div", { className: "font-mono text-[10px] font-bold uppercase tracking-[0.18em] text-p-ink-3" }, L.goal), /* @__PURE__ */ React.createElement("div", { className: "mt-1 font-body text-[14px] leading-snug text-p-ink" }, renderMarkdown ? renderMarkdown(run.goal) : /* @__PURE__ */ React.createElement("p", { className: "m-0" }, run.goal)), isLive && run.lastLog ? /* @__PURE__ */ React.createElement(
|
|
85
|
+
"div",
|
|
86
|
+
{
|
|
87
|
+
className: "mt-2 flex items-center gap-2 rounded-md border border-p-line bg-p-bg/60 px-2 py-1.5 font-mono text-[11px] italic text-p-ink-3",
|
|
88
|
+
"aria-live": "polite"
|
|
89
|
+
},
|
|
90
|
+
/* @__PURE__ */ React.createElement(
|
|
91
|
+
"span",
|
|
92
|
+
{
|
|
93
|
+
"aria-hidden": true,
|
|
94
|
+
className: "size-1.5 shrink-0 animate-pulse rounded-full bg-p-accent"
|
|
95
|
+
}
|
|
96
|
+
),
|
|
97
|
+
/* @__PURE__ */ React.createElement("span", { className: "truncate" }, run.lastLog)
|
|
98
|
+
) : null),
|
|
99
|
+
variant === "tabs" ? /* @__PURE__ */ React.createElement(
|
|
100
|
+
TabsBody,
|
|
101
|
+
{
|
|
102
|
+
run,
|
|
103
|
+
L,
|
|
104
|
+
hideTools,
|
|
105
|
+
renderToolCalls,
|
|
106
|
+
renderArtifacts,
|
|
107
|
+
renderEvaluation,
|
|
108
|
+
renderMarkdown
|
|
109
|
+
}
|
|
110
|
+
) : /* @__PURE__ */ React.createElement(
|
|
111
|
+
FlatBody,
|
|
112
|
+
{
|
|
113
|
+
run,
|
|
114
|
+
L,
|
|
115
|
+
hideTools,
|
|
116
|
+
renderToolCalls,
|
|
117
|
+
renderArtifacts,
|
|
118
|
+
renderEvaluation,
|
|
119
|
+
renderMarkdown
|
|
120
|
+
}
|
|
121
|
+
)
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
function TabsBody({
|
|
125
|
+
run,
|
|
126
|
+
L,
|
|
127
|
+
hideTools,
|
|
128
|
+
renderToolCalls,
|
|
129
|
+
renderArtifacts,
|
|
130
|
+
renderEvaluation,
|
|
131
|
+
renderMarkdown
|
|
132
|
+
}) {
|
|
133
|
+
const hasEval = !!run.evaluation;
|
|
134
|
+
const isLive = run.status === "running" || run.status === "pending";
|
|
135
|
+
const [tab, setTab] = useState(
|
|
136
|
+
isLive && !hideTools ? "tools" : "output"
|
|
137
|
+
);
|
|
138
|
+
const artifactCount = run.artifacts?.length ?? 0;
|
|
139
|
+
const toolCount = run.toolCalls?.length ?? 0;
|
|
140
|
+
const safeTab = tab === "tools" && hideTools ? "output" : tab;
|
|
141
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "flex shrink-0 items-center gap-1 border-b border-p-line px-2" }, /* @__PURE__ */ React.createElement(
|
|
142
|
+
Tab,
|
|
143
|
+
{
|
|
144
|
+
active: safeTab === "output",
|
|
145
|
+
onClick: () => setTab("output"),
|
|
146
|
+
label: run.error ? L.error : L.output
|
|
147
|
+
}
|
|
148
|
+
), /* @__PURE__ */ React.createElement(
|
|
149
|
+
Tab,
|
|
150
|
+
{
|
|
151
|
+
active: safeTab === "artifacts",
|
|
152
|
+
onClick: () => setTab("artifacts"),
|
|
153
|
+
label: "artifacts",
|
|
154
|
+
badge: artifactCount > 0 ? /* @__PURE__ */ React.createElement(CountBadge, { value: artifactCount }) : null
|
|
155
|
+
}
|
|
156
|
+
), !hideTools ? /* @__PURE__ */ React.createElement(
|
|
157
|
+
Tab,
|
|
158
|
+
{
|
|
159
|
+
active: safeTab === "tools",
|
|
160
|
+
onClick: () => setTab("tools"),
|
|
161
|
+
label: L.tools,
|
|
162
|
+
badge: toolCount > 0 ? /* @__PURE__ */ React.createElement(CountBadge, { value: toolCount }) : null
|
|
163
|
+
}
|
|
164
|
+
) : null, hasEval ? /* @__PURE__ */ React.createElement(
|
|
165
|
+
Tab,
|
|
166
|
+
{
|
|
167
|
+
active: safeTab === "eval",
|
|
168
|
+
onClick: () => setTab("eval"),
|
|
169
|
+
label: "eval",
|
|
170
|
+
badge: /* @__PURE__ */ React.createElement(
|
|
171
|
+
ScoreBadge,
|
|
172
|
+
{
|
|
173
|
+
score: run.evaluation.verdict.overall,
|
|
174
|
+
scale: run.evaluation.verdict.scale
|
|
175
|
+
}
|
|
176
|
+
)
|
|
177
|
+
}
|
|
178
|
+
) : null), /* @__PURE__ */ React.createElement("div", { className: "min-h-0 flex-1 overflow-y-auto p-4" }, safeTab === "output" ? /* @__PURE__ */ React.createElement(OutputBlock, { run, L, renderMarkdown }) : null, safeTab === "artifacts" ? /* @__PURE__ */ React.createElement(ArtifactsBlock, { run, renderArtifacts }) : null, safeTab === "tools" && !hideTools ? /* @__PURE__ */ React.createElement(ToolsBlock, { run, renderToolCalls }) : null, safeTab === "eval" && run.evaluation ? /* @__PURE__ */ React.createElement(
|
|
179
|
+
EvalBlock,
|
|
180
|
+
{
|
|
181
|
+
evaluation: run.evaluation,
|
|
182
|
+
renderEvaluation
|
|
183
|
+
}
|
|
184
|
+
) : null));
|
|
185
|
+
}
|
|
186
|
+
function FlatBody({
|
|
187
|
+
run,
|
|
188
|
+
L,
|
|
189
|
+
hideTools,
|
|
190
|
+
renderToolCalls,
|
|
191
|
+
renderArtifacts,
|
|
192
|
+
renderEvaluation,
|
|
193
|
+
renderMarkdown
|
|
194
|
+
}) {
|
|
195
|
+
const toolCount = run.toolCalls?.length ?? 0;
|
|
196
|
+
const artifactCount = run.artifacts?.length ?? 0;
|
|
197
|
+
const hasEval = !!run.evaluation;
|
|
198
|
+
return /* @__PURE__ */ React.createElement("div", { className: "min-h-0 flex-1 overflow-y-auto" }, /* @__PURE__ */ React.createElement(FlatSection, { title: run.error ? L.error : L.output }, /* @__PURE__ */ React.createElement(OutputBlock, { run, L, renderMarkdown })), /* @__PURE__ */ React.createElement(
|
|
199
|
+
FlatSection,
|
|
200
|
+
{
|
|
201
|
+
title: "artifacts",
|
|
202
|
+
meta: artifactCount > 0 ? String(artifactCount) : void 0
|
|
203
|
+
},
|
|
204
|
+
/* @__PURE__ */ React.createElement(ArtifactsBlock, { run, renderArtifacts })
|
|
205
|
+
), !hideTools ? /* @__PURE__ */ React.createElement(
|
|
206
|
+
FlatSection,
|
|
207
|
+
{
|
|
208
|
+
title: L.tools,
|
|
209
|
+
meta: toolCount > 0 ? String(toolCount) : void 0,
|
|
210
|
+
last: !hasEval
|
|
211
|
+
},
|
|
212
|
+
/* @__PURE__ */ React.createElement(ToolsBlock, { run, renderToolCalls })
|
|
213
|
+
) : null, hasEval ? /* @__PURE__ */ React.createElement(FlatSection, { title: "evaluation", last: true }, /* @__PURE__ */ React.createElement(
|
|
214
|
+
EvalBlock,
|
|
215
|
+
{
|
|
216
|
+
evaluation: run.evaluation,
|
|
217
|
+
renderEvaluation
|
|
218
|
+
}
|
|
219
|
+
)) : null);
|
|
220
|
+
}
|
|
221
|
+
function FlatSection({
|
|
222
|
+
title,
|
|
223
|
+
meta,
|
|
224
|
+
last,
|
|
225
|
+
/** Max height of the body before "Show more" appears. Default 220px.
|
|
226
|
+
* The body is clipped to this height with a soft fade gradient at
|
|
227
|
+
* the bottom; clicking "Show more" expands. */
|
|
228
|
+
previewMaxHeight = 220,
|
|
229
|
+
children
|
|
230
|
+
}) {
|
|
231
|
+
const [mode, setMode] = useState(
|
|
232
|
+
"preview"
|
|
233
|
+
);
|
|
234
|
+
const bodyRef = useRef(null);
|
|
235
|
+
const [overflows, setOverflows] = useState(false);
|
|
236
|
+
useLayoutEffect(() => {
|
|
237
|
+
if (mode === "collapsed" || !bodyRef.current) return;
|
|
238
|
+
setOverflows(bodyRef.current.scrollHeight > previewMaxHeight + 4);
|
|
239
|
+
}, [mode, previewMaxHeight, children]);
|
|
240
|
+
return /* @__PURE__ */ React.createElement(
|
|
241
|
+
"section",
|
|
242
|
+
{
|
|
243
|
+
className: [
|
|
244
|
+
"px-4 py-4",
|
|
245
|
+
last ? "" : "border-b border-p-line"
|
|
246
|
+
].join(" ")
|
|
247
|
+
},
|
|
248
|
+
/* @__PURE__ */ React.createElement("div", { className: "mb-2 flex items-center gap-2" }, /* @__PURE__ */ React.createElement("span", { className: "font-mono text-[10px] font-bold uppercase tracking-[0.22em] text-p-ink-3" }, title), meta ? /* @__PURE__ */ React.createElement("span", { className: "font-mono text-[10px] uppercase tracking-[0.18em] text-p-ink-3/70 tabular-nums" }, "\xB7 ", meta) : null, /* @__PURE__ */ React.createElement(
|
|
249
|
+
"button",
|
|
250
|
+
{
|
|
251
|
+
type: "button",
|
|
252
|
+
onClick: () => setMode((m) => m === "collapsed" ? "preview" : "collapsed"),
|
|
253
|
+
"aria-label": mode === "collapsed" ? "Expand section" : "Collapse section",
|
|
254
|
+
"aria-expanded": mode !== "collapsed",
|
|
255
|
+
className: "ml-auto grid size-5 place-items-center rounded text-p-ink-3 transition-colors cursor-pointer hover:bg-p-warm hover:text-p-ink"
|
|
256
|
+
},
|
|
257
|
+
/* @__PURE__ */ React.createElement(
|
|
258
|
+
ChevronDown,
|
|
259
|
+
{
|
|
260
|
+
className: [
|
|
261
|
+
"size-3.5 transition-transform duration-150",
|
|
262
|
+
mode === "collapsed" ? "-rotate-90" : ""
|
|
263
|
+
].join(" ")
|
|
264
|
+
}
|
|
265
|
+
)
|
|
266
|
+
)),
|
|
267
|
+
mode === "collapsed" ? null : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
|
|
268
|
+
"div",
|
|
269
|
+
{
|
|
270
|
+
ref: bodyRef,
|
|
271
|
+
className: "relative overflow-hidden",
|
|
272
|
+
style: {
|
|
273
|
+
maxHeight: mode === "preview" && overflows ? previewMaxHeight : void 0
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
children,
|
|
277
|
+
mode === "preview" && overflows ? /* @__PURE__ */ React.createElement(
|
|
278
|
+
"div",
|
|
279
|
+
{
|
|
280
|
+
"aria-hidden": true,
|
|
281
|
+
className: "pointer-events-none absolute inset-x-0 bottom-0 h-12 bg-gradient-to-t from-p-surface to-transparent"
|
|
282
|
+
}
|
|
283
|
+
) : null
|
|
284
|
+
), overflows ? /* @__PURE__ */ React.createElement(
|
|
285
|
+
"button",
|
|
286
|
+
{
|
|
287
|
+
type: "button",
|
|
288
|
+
onClick: () => setMode((m) => m === "preview" ? "expanded" : "preview"),
|
|
289
|
+
className: "mt-2 inline-flex items-center gap-1 rounded-md font-mono text-[10.5px] font-bold uppercase tracking-[0.16em] text-p-ink-3 transition-colors cursor-pointer hover:text-p-ink"
|
|
290
|
+
},
|
|
291
|
+
mode === "preview" ? "show more" : "show less",
|
|
292
|
+
/* @__PURE__ */ React.createElement(
|
|
293
|
+
ChevronDown,
|
|
294
|
+
{
|
|
295
|
+
className: [
|
|
296
|
+
"size-3 transition-transform duration-150",
|
|
297
|
+
mode === "expanded" ? "rotate-180" : ""
|
|
298
|
+
].join(" ")
|
|
299
|
+
}
|
|
300
|
+
)
|
|
301
|
+
) : null)
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
function VitalSigns({
|
|
305
|
+
run,
|
|
306
|
+
L,
|
|
307
|
+
isLive,
|
|
308
|
+
elapsed
|
|
309
|
+
}) {
|
|
310
|
+
const attempts = (run.retries ?? 0) + 1;
|
|
311
|
+
const maxAttempts = typeof run.maxRetries === "number" ? run.maxRetries + 1 : void 0;
|
|
312
|
+
return /* @__PURE__ */ React.createElement("section", { className: "grid shrink-0 grid-cols-3 gap-px border-b border-p-line bg-p-line" }, /* @__PURE__ */ React.createElement(
|
|
313
|
+
Stat,
|
|
314
|
+
{
|
|
315
|
+
label: "duration",
|
|
316
|
+
value: /* @__PURE__ */ React.createElement("span", { className: "tabular-nums" }, isLive ? L.startedAgo(elapsed) : L.duration(elapsed))
|
|
317
|
+
}
|
|
318
|
+
), /* @__PURE__ */ React.createElement(
|
|
319
|
+
Stat,
|
|
320
|
+
{
|
|
321
|
+
label: "status",
|
|
322
|
+
value: /* @__PURE__ */ React.createElement(
|
|
323
|
+
SwarmStatusPill,
|
|
324
|
+
{
|
|
325
|
+
status: run.status,
|
|
326
|
+
label: L[run.status],
|
|
327
|
+
size: "sm"
|
|
328
|
+
}
|
|
329
|
+
)
|
|
330
|
+
}
|
|
331
|
+
), /* @__PURE__ */ React.createElement(
|
|
332
|
+
Stat,
|
|
333
|
+
{
|
|
334
|
+
label: "attempts",
|
|
335
|
+
value: /* @__PURE__ */ React.createElement("span", { className: "tabular-nums" }, attempts, typeof maxAttempts === "number" ? /* @__PURE__ */ React.createElement("span", { className: "text-p-ink-3" }, "/", maxAttempts) : null)
|
|
336
|
+
}
|
|
337
|
+
));
|
|
338
|
+
}
|
|
339
|
+
function Stat({ label, value }) {
|
|
340
|
+
return /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-1 bg-p-surface px-4 py-3" }, /* @__PURE__ */ React.createElement("span", { className: "font-mono text-[9.5px] font-bold uppercase tracking-[0.22em] text-p-ink-3" }, label), /* @__PURE__ */ React.createElement("span", { className: "font-display text-[16px] font-bold leading-tight tracking-[-0.01em] text-p-ink" }, value));
|
|
341
|
+
}
|
|
342
|
+
function OutputBlock({
|
|
343
|
+
run,
|
|
344
|
+
L,
|
|
345
|
+
renderMarkdown
|
|
346
|
+
}) {
|
|
347
|
+
if (run.error) {
|
|
348
|
+
return /* @__PURE__ */ React.createElement("pre", { className: "m-0 whitespace-pre-wrap break-words font-mono text-[12px] leading-relaxed text-[#E63946]" }, run.error);
|
|
349
|
+
}
|
|
350
|
+
if (!run.output) {
|
|
351
|
+
return /* @__PURE__ */ React.createElement("span", { className: "block px-1 py-2 font-mono text-[11px] uppercase tracking-[0.16em] text-p-ink-3" }, L.output, " \u2014 \u2014");
|
|
352
|
+
}
|
|
353
|
+
if (renderMarkdown) {
|
|
354
|
+
return /* @__PURE__ */ React.createElement("div", { className: "font-body text-[14px] leading-[1.65] text-p-ink-2" }, renderMarkdown(run.output));
|
|
355
|
+
}
|
|
356
|
+
return /* @__PURE__ */ React.createElement("pre", { className: "m-0 whitespace-pre-wrap break-words font-mono text-[12px] leading-relaxed text-p-ink-2" }, run.output);
|
|
357
|
+
}
|
|
358
|
+
function ArtifactsBlock({
|
|
359
|
+
run,
|
|
360
|
+
renderArtifacts
|
|
361
|
+
}) {
|
|
362
|
+
const artifacts = run.artifacts ?? [];
|
|
363
|
+
if (renderArtifacts) return /* @__PURE__ */ React.createElement(React.Fragment, null, renderArtifacts(artifacts));
|
|
364
|
+
if (artifacts.length === 0) {
|
|
365
|
+
return /* @__PURE__ */ React.createElement("span", { className: "block px-1 py-2 font-mono text-[11px] uppercase tracking-[0.16em] text-p-ink-3" }, "no artifacts produced");
|
|
366
|
+
}
|
|
367
|
+
return /* @__PURE__ */ React.createElement(DefaultArtifactList, { artifacts });
|
|
368
|
+
}
|
|
369
|
+
function ToolsBlock({
|
|
370
|
+
run,
|
|
371
|
+
renderToolCalls
|
|
372
|
+
}) {
|
|
373
|
+
if (renderToolCalls) return /* @__PURE__ */ React.createElement(React.Fragment, null, renderToolCalls(run.toolCalls ?? []));
|
|
374
|
+
return /* @__PURE__ */ React.createElement(DefaultToolCallList, { toolCalls: run.toolCalls ?? [] });
|
|
375
|
+
}
|
|
376
|
+
function EvalBlock({
|
|
377
|
+
evaluation,
|
|
378
|
+
renderEvaluation
|
|
379
|
+
}) {
|
|
380
|
+
if (renderEvaluation) return /* @__PURE__ */ React.createElement(React.Fragment, null, renderEvaluation(evaluation));
|
|
381
|
+
return /* @__PURE__ */ React.createElement(DefaultEvalSummary, { evaluation });
|
|
382
|
+
}
|
|
383
|
+
function DefaultEvalSummary({
|
|
384
|
+
evaluation
|
|
385
|
+
}) {
|
|
386
|
+
const { verdict, scores, evaluatedAt } = evaluation;
|
|
387
|
+
const scale = verdict.scale ?? scores[0]?.scale ?? { min: 1, max: 5 };
|
|
388
|
+
const tone = verdictTone(verdict.overall, scale);
|
|
389
|
+
return /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-4" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-baseline gap-3" }, /* @__PURE__ */ React.createElement(
|
|
390
|
+
"span",
|
|
391
|
+
{
|
|
392
|
+
className: "font-display text-[40px] font-bold leading-none tracking-[-0.02em] tabular-nums",
|
|
393
|
+
style: { color: tone }
|
|
394
|
+
},
|
|
395
|
+
formatScore(verdict.overall)
|
|
396
|
+
), /* @__PURE__ */ React.createElement("span", { className: "font-mono text-[10.5px] uppercase tracking-[0.18em] text-p-ink-3" }, "/", scale.max, " \xB7 evaluated", " ", new Date(evaluatedAt).toLocaleDateString(void 0, {
|
|
397
|
+
month: "short",
|
|
398
|
+
day: "numeric"
|
|
399
|
+
}), typeof verdict.passed === "boolean" ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("span", { className: "mx-1.5 text-p-line" }, "\xB7"), /* @__PURE__ */ React.createElement("span", { style: { color: verdict.passed ? "var(--green)" : "#E63946" } }, verdict.passed ? "passed" : "failed")) : null)), verdict.summary ? /* @__PURE__ */ React.createElement("p", { className: "font-body text-[13px] leading-[1.55] text-p-ink-2" }, verdict.summary) : null, /* @__PURE__ */ React.createElement("ul", { className: "flex flex-col gap-2" }, scores.map((s) => {
|
|
400
|
+
const sScale = s.scale ?? scale;
|
|
401
|
+
const pct = Math.max(
|
|
402
|
+
0,
|
|
403
|
+
Math.min(
|
|
404
|
+
100,
|
|
405
|
+
(s.value - sScale.min) / (sScale.max - sScale.min) * 100
|
|
406
|
+
)
|
|
407
|
+
);
|
|
408
|
+
const sTone = verdictTone(s.value, sScale);
|
|
409
|
+
return /* @__PURE__ */ React.createElement("li", { key: s.criterion, className: "flex flex-col gap-1" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-baseline justify-between gap-3 font-mono text-[10.5px] uppercase tracking-[0.16em]" }, /* @__PURE__ */ React.createElement("span", { className: "text-p-ink-2" }, s.criterion), /* @__PURE__ */ React.createElement("span", { className: "tabular-nums", style: { color: sTone } }, formatScore(s.value), /* @__PURE__ */ React.createElement("span", { className: "text-p-ink-3" }, "/", sScale.max))), /* @__PURE__ */ React.createElement("div", { className: "h-[3px] w-full overflow-hidden rounded-full bg-p-line" }, /* @__PURE__ */ React.createElement(
|
|
410
|
+
"div",
|
|
411
|
+
{
|
|
412
|
+
className: "h-full rounded-full",
|
|
413
|
+
style: { width: `${pct}%`, background: sTone }
|
|
414
|
+
}
|
|
415
|
+
)));
|
|
416
|
+
})));
|
|
417
|
+
}
|
|
418
|
+
function formatScore(n) {
|
|
419
|
+
return n.toFixed(1).replace(/\.0$/, "");
|
|
420
|
+
}
|
|
421
|
+
function verdictTone(value, scale) {
|
|
422
|
+
const range = scale.max - scale.min;
|
|
423
|
+
if (range <= 0) return "var(--ink-2)";
|
|
424
|
+
const norm = (value - scale.min) / range;
|
|
425
|
+
if (norm >= 0.75) return "var(--green)";
|
|
426
|
+
if (norm >= 0.5) return "var(--p-accent)";
|
|
427
|
+
if (norm >= 0.25) return "#D4A017";
|
|
428
|
+
return "#E63946";
|
|
429
|
+
}
|
|
430
|
+
function Tab({
|
|
431
|
+
active,
|
|
432
|
+
onClick,
|
|
433
|
+
label,
|
|
434
|
+
badge
|
|
435
|
+
}) {
|
|
436
|
+
return /* @__PURE__ */ React.createElement(
|
|
437
|
+
"button",
|
|
438
|
+
{
|
|
439
|
+
type: "button",
|
|
440
|
+
onClick,
|
|
441
|
+
className: [
|
|
442
|
+
"relative inline-flex items-center gap-1.5 px-3 py-2 font-mono text-[11px] font-bold uppercase tracking-[0.16em] transition-colors cursor-pointer",
|
|
443
|
+
active ? "text-p-ink" : "text-p-ink-3 hover:text-p-ink"
|
|
444
|
+
].join(" ")
|
|
445
|
+
},
|
|
446
|
+
label,
|
|
447
|
+
badge,
|
|
448
|
+
active ? /* @__PURE__ */ React.createElement(
|
|
449
|
+
"span",
|
|
450
|
+
{
|
|
451
|
+
"aria-hidden": true,
|
|
452
|
+
className: "absolute inset-x-2 -bottom-px h-[2px] rounded-t bg-p-accent"
|
|
453
|
+
}
|
|
454
|
+
) : null
|
|
455
|
+
);
|
|
456
|
+
}
|
|
457
|
+
function CountBadge({ value }) {
|
|
458
|
+
return /* @__PURE__ */ React.createElement("span", { className: "inline-flex h-[18px] min-w-[18px] items-center justify-center rounded-full border border-p-line bg-transparent px-1.5 font-mono text-[10px] font-bold tabular-nums text-p-ink-3" }, value);
|
|
459
|
+
}
|
|
460
|
+
function ScoreBadge({
|
|
461
|
+
score,
|
|
462
|
+
scale
|
|
463
|
+
}) {
|
|
464
|
+
const sc = scale ?? { min: 1, max: 5 };
|
|
465
|
+
const range = sc.max - sc.min;
|
|
466
|
+
const norm = range > 0 ? (score - sc.min) / range : 0;
|
|
467
|
+
const palette = norm >= 0.75 ? { fg: "text-p-green", bg: "bg-p-green-light", ring: "border-p-green/30" } : norm >= 0.5 ? {
|
|
468
|
+
fg: "text-p-accent",
|
|
469
|
+
bg: "bg-p-accent-light",
|
|
470
|
+
ring: "border-p-accent/30"
|
|
471
|
+
} : norm >= 0.25 ? {
|
|
472
|
+
fg: "text-[#B45309]",
|
|
473
|
+
bg: "bg-[#FEF3C7]",
|
|
474
|
+
ring: "border-[#D4A017]/30"
|
|
475
|
+
} : {
|
|
476
|
+
fg: "text-[#E63946]",
|
|
477
|
+
bg: "bg-[#FEF2F2]",
|
|
478
|
+
ring: "border-[#E63946]/30"
|
|
479
|
+
};
|
|
480
|
+
return /* @__PURE__ */ React.createElement(
|
|
481
|
+
"span",
|
|
482
|
+
{
|
|
483
|
+
className: [
|
|
484
|
+
"inline-flex h-[18px] items-center justify-center rounded-full border px-1.5 font-mono text-[10px] font-bold tabular-nums",
|
|
485
|
+
palette.fg,
|
|
486
|
+
palette.bg,
|
|
487
|
+
palette.ring
|
|
488
|
+
].join(" ")
|
|
489
|
+
},
|
|
490
|
+
formatScore(score)
|
|
491
|
+
);
|
|
492
|
+
}
|
|
493
|
+
function DefaultToolCallList({ toolCalls }) {
|
|
494
|
+
if (toolCalls.length === 0) {
|
|
495
|
+
return /* @__PURE__ */ React.createElement("span", { className: "block px-1 py-2 font-mono text-[11px] uppercase tracking-[0.16em] text-p-ink-3" }, "no tool calls yet");
|
|
496
|
+
}
|
|
497
|
+
return /* @__PURE__ */ React.createElement("ul", { className: "flex flex-col gap-1.5" }, toolCalls.map((t) => /* @__PURE__ */ React.createElement(
|
|
498
|
+
"li",
|
|
499
|
+
{
|
|
500
|
+
key: t.id,
|
|
501
|
+
className: "flex items-center gap-2 rounded-md border border-p-line bg-p-bg px-2 py-1.5"
|
|
502
|
+
},
|
|
503
|
+
/* @__PURE__ */ React.createElement(
|
|
504
|
+
"span",
|
|
505
|
+
{
|
|
506
|
+
"aria-hidden": true,
|
|
507
|
+
className: [
|
|
508
|
+
"size-1.5 shrink-0 rounded-full",
|
|
509
|
+
t.state === "calling" ? "bg-p-accent animate-pulse" : t.state === "completed" ? "bg-p-green" : "bg-[#E63946]"
|
|
510
|
+
].join(" ")
|
|
511
|
+
}
|
|
512
|
+
),
|
|
513
|
+
/* @__PURE__ */ React.createElement("span", { className: "font-mono text-[11.5px] font-semibold text-p-ink" }, t.name),
|
|
514
|
+
t.summary ? /* @__PURE__ */ React.createElement("span", { className: "truncate font-mono text-[11px] text-p-ink-3" }, t.summary) : null
|
|
515
|
+
)));
|
|
516
|
+
}
|
|
517
|
+
const ARTIFACT_ICON = {
|
|
518
|
+
file: FileText,
|
|
519
|
+
url: ExternalLink,
|
|
520
|
+
image: ImageIcon,
|
|
521
|
+
data: Hash,
|
|
522
|
+
note: StickyNote
|
|
523
|
+
};
|
|
524
|
+
function DefaultArtifactList({ artifacts }) {
|
|
525
|
+
return /* @__PURE__ */ React.createElement("ul", { className: "flex flex-col gap-1.5" }, artifacts.map((a) => {
|
|
526
|
+
const Icon = ARTIFACT_ICON[a.kind];
|
|
527
|
+
const interactive = !!a.url;
|
|
528
|
+
const Wrapper = interactive ? "a" : "div";
|
|
529
|
+
return /* @__PURE__ */ React.createElement("li", { key: a.id }, /* @__PURE__ */ React.createElement(
|
|
530
|
+
Wrapper,
|
|
531
|
+
{
|
|
532
|
+
...interactive ? {
|
|
533
|
+
href: a.url,
|
|
534
|
+
target: "_blank",
|
|
535
|
+
rel: "noreferrer noopener"
|
|
536
|
+
} : {},
|
|
537
|
+
className: [
|
|
538
|
+
"flex items-center gap-2 rounded-md border border-p-line bg-p-surface px-2.5 py-1.5 no-underline transition-colors",
|
|
539
|
+
interactive ? "cursor-pointer hover:bg-p-warm/40" : ""
|
|
540
|
+
].join(" ")
|
|
541
|
+
},
|
|
542
|
+
/* @__PURE__ */ React.createElement(Icon, { className: "size-3 shrink-0 text-p-ink-3", "aria-hidden": true }),
|
|
543
|
+
/* @__PURE__ */ React.createElement("span", { className: "min-w-0 flex-1 truncate font-display text-[12.5px] font-semibold text-p-ink" }, a.label),
|
|
544
|
+
a.path ? /* @__PURE__ */ React.createElement("code", { className: "hidden truncate font-mono text-[10.5px] text-p-ink-3 sm:inline" }, a.path) : null,
|
|
545
|
+
a.tags && a.tags.length > 0 ? /* @__PURE__ */ React.createElement("span", { className: "hidden flex-wrap gap-1 sm:inline-flex" }, a.tags.map((t) => /* @__PURE__ */ React.createElement(
|
|
546
|
+
"span",
|
|
547
|
+
{
|
|
548
|
+
key: t,
|
|
549
|
+
className: "inline-flex items-center rounded border border-p-line bg-p-bg px-1 py-px font-mono text-[9.5px] uppercase tracking-[0.14em] text-p-ink-2"
|
|
550
|
+
},
|
|
551
|
+
t
|
|
552
|
+
))) : null,
|
|
553
|
+
a.summary ? /* @__PURE__ */ React.createElement("span", { className: "hidden truncate font-mono text-[10.5px] text-p-ink-3 lg:inline" }, a.summary) : null
|
|
554
|
+
));
|
|
555
|
+
}));
|
|
556
|
+
}
|
|
557
|
+
export {
|
|
558
|
+
SwarmRunDetail
|
|
559
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
import { SwarmRun, SwarmLabels } from './types.js';
|
|
4
|
+
|
|
5
|
+
interface SwarmRunListProps {
|
|
6
|
+
runs: SwarmRun[];
|
|
7
|
+
now?: number;
|
|
8
|
+
/** Group background runs into a separate trailing section. */
|
|
9
|
+
groupBackground?: boolean;
|
|
10
|
+
/** Currently-selected run id — passes through to row `active` flag. */
|
|
11
|
+
activeId?: string | null;
|
|
12
|
+
renderAvatar?: (agent: SwarmRun["agent"]) => ReactNode;
|
|
13
|
+
onCancel?: (id: string) => void;
|
|
14
|
+
onRetry?: (id: string) => void;
|
|
15
|
+
onOpen?: (id: string) => void;
|
|
16
|
+
emptyState?: ReactNode;
|
|
17
|
+
labels?: Partial<SwarmLabels>;
|
|
18
|
+
className?: string;
|
|
19
|
+
}
|
|
20
|
+
declare function SwarmRunList({ runs, now, groupBackground, activeId, renderAvatar, onCancel, onRetry, onOpen, emptyState, labels, className, }: SwarmRunListProps): react.JSX.Element;
|
|
21
|
+
|
|
22
|
+
export { SwarmRunList, type SwarmRunListProps };
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useMemo } from "react";
|
|
3
|
+
import {
|
|
4
|
+
defaultSwarmLabels
|
|
5
|
+
} from "./types";
|
|
6
|
+
import { SwarmRunRow } from "./swarm-run-row";
|
|
7
|
+
function SwarmRunList({
|
|
8
|
+
runs,
|
|
9
|
+
now,
|
|
10
|
+
groupBackground = false,
|
|
11
|
+
activeId,
|
|
12
|
+
renderAvatar,
|
|
13
|
+
onCancel,
|
|
14
|
+
onRetry,
|
|
15
|
+
onOpen,
|
|
16
|
+
emptyState,
|
|
17
|
+
labels,
|
|
18
|
+
className
|
|
19
|
+
}) {
|
|
20
|
+
const L = { ...defaultSwarmLabels, ...labels };
|
|
21
|
+
const { foreground, background } = useMemo(() => {
|
|
22
|
+
if (!groupBackground)
|
|
23
|
+
return { foreground: runs, background: [] };
|
|
24
|
+
const fg = [];
|
|
25
|
+
const bg = [];
|
|
26
|
+
for (const r of runs) (r.background ? bg : fg).push(r);
|
|
27
|
+
return { foreground: fg, background: bg };
|
|
28
|
+
}, [runs, groupBackground]);
|
|
29
|
+
if (runs.length === 0) {
|
|
30
|
+
return /* @__PURE__ */ React.createElement("div", { className: ["px-3 py-10 text-center", className || ""].join(" ") }, emptyState ?? /* @__PURE__ */ React.createElement("span", { className: "font-mono text-[11px] uppercase tracking-[0.16em] text-p-ink-3" }, L.noRuns));
|
|
31
|
+
}
|
|
32
|
+
const Section = ({
|
|
33
|
+
label,
|
|
34
|
+
list
|
|
35
|
+
}) => /* @__PURE__ */ React.createElement("div", { className: "flex flex-col" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-baseline gap-2 border-b border-p-line bg-p-bg/50 px-3 py-1.5" }, /* @__PURE__ */ React.createElement("span", { className: "font-mono text-[10px] font-bold uppercase tracking-[0.22em] text-p-ink-3" }, label), /* @__PURE__ */ React.createElement("span", { className: "font-mono text-[10px] tabular-nums text-p-ink-3" }, String(list.length).padStart(2, "0"))), /* @__PURE__ */ React.createElement("div", { className: "flex flex-col" }, list.map((r) => /* @__PURE__ */ React.createElement(
|
|
36
|
+
SwarmRunRow,
|
|
37
|
+
{
|
|
38
|
+
key: r.id,
|
|
39
|
+
run: r,
|
|
40
|
+
now,
|
|
41
|
+
renderAvatar,
|
|
42
|
+
onCancel,
|
|
43
|
+
onRetry,
|
|
44
|
+
onOpen,
|
|
45
|
+
active: activeId === r.id,
|
|
46
|
+
labels
|
|
47
|
+
}
|
|
48
|
+
))));
|
|
49
|
+
return /* @__PURE__ */ React.createElement(
|
|
50
|
+
"div",
|
|
51
|
+
{
|
|
52
|
+
className: [
|
|
53
|
+
"overflow-hidden rounded-xl border border-p-line bg-p-surface",
|
|
54
|
+
className || ""
|
|
55
|
+
].join(" ")
|
|
56
|
+
},
|
|
57
|
+
groupBackground ? /* @__PURE__ */ React.createElement(React.Fragment, null, foreground.length > 0 ? /* @__PURE__ */ React.createElement(Section, { label: L.foregroundGroup, list: foreground }) : null, background.length > 0 ? /* @__PURE__ */ React.createElement(Section, { label: L.backgroundGroup, list: background }) : null) : /* @__PURE__ */ React.createElement("div", { className: "flex flex-col" }, runs.map((r) => /* @__PURE__ */ React.createElement(
|
|
58
|
+
SwarmRunRow,
|
|
59
|
+
{
|
|
60
|
+
key: r.id,
|
|
61
|
+
run: r,
|
|
62
|
+
now,
|
|
63
|
+
renderAvatar,
|
|
64
|
+
onCancel,
|
|
65
|
+
onRetry,
|
|
66
|
+
onOpen,
|
|
67
|
+
active: activeId === r.id,
|
|
68
|
+
labels
|
|
69
|
+
}
|
|
70
|
+
)))
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
export {
|
|
74
|
+
SwarmRunList
|
|
75
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
import { SwarmRun, SwarmLabels } from './types.js';
|
|
4
|
+
|
|
5
|
+
interface SwarmRunRowProps {
|
|
6
|
+
run: SwarmRun;
|
|
7
|
+
/** Live clock — pass `state.now` from `useSwarm()` to make the
|
|
8
|
+
* elapsed counter tick. */
|
|
9
|
+
now?: number;
|
|
10
|
+
renderAvatar?: (agent: SwarmRun["agent"]) => ReactNode;
|
|
11
|
+
onCancel?: (id: string) => void;
|
|
12
|
+
onRetry?: (id: string) => void;
|
|
13
|
+
onOpen?: (id: string) => void;
|
|
14
|
+
/** Highlight the row as currently selected (e.g. open in a detail
|
|
15
|
+
* panel next to it). */
|
|
16
|
+
active?: boolean;
|
|
17
|
+
labels?: Partial<SwarmLabels>;
|
|
18
|
+
className?: string;
|
|
19
|
+
}
|
|
20
|
+
declare function SwarmRunRow({ run, now, renderAvatar, onCancel, onRetry, onOpen, active, labels, className, }: SwarmRunRowProps): react.JSX.Element;
|
|
21
|
+
|
|
22
|
+
export { SwarmRunRow, type SwarmRunRowProps };
|