@post-print/agent-test 2.0.0 → 2.0.1
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/dist/sdk/cli.d.ts +1 -1
- package/dist/sdk/cli.d.ts.map +1 -1
- package/dist/sdk/cli.js +49 -14
- package/dist/sdk/cli.js.map +1 -1
- package/dist/sdk/definitions.js +1 -1
- package/dist/sdk/definitions.js.map +1 -1
- package/dist/sdk/execution-reporter.d.ts +18 -0
- package/dist/sdk/execution-reporter.d.ts.map +1 -0
- package/dist/sdk/execution-reporter.js +171 -0
- package/dist/sdk/execution-reporter.js.map +1 -0
- package/dist/sdk/execution-runner.d.ts +14 -0
- package/dist/sdk/execution-runner.d.ts.map +1 -0
- package/dist/sdk/execution-runner.js +80 -0
- package/dist/sdk/execution-runner.js.map +1 -0
- package/dist/sdk/execution-store.d.ts +92 -0
- package/dist/sdk/execution-store.d.ts.map +1 -0
- package/dist/sdk/execution-store.js +357 -0
- package/dist/sdk/execution-store.js.map +1 -0
- package/dist/sdk/expect.d.ts.map +1 -1
- package/dist/sdk/expect.js +33 -5
- package/dist/sdk/expect.js.map +1 -1
- package/dist/sdk/playwright-cli.d.ts +2 -0
- package/dist/sdk/playwright-cli.d.ts.map +1 -0
- package/dist/sdk/playwright-cli.js +6 -0
- package/dist/sdk/playwright-cli.js.map +1 -0
- package/dist/sdk/reporter.d.ts.map +1 -1
- package/dist/sdk/reporter.js +40 -0
- package/dist/sdk/reporter.js.map +1 -1
- package/dist/sdk/runtime.d.ts +1 -1
- package/dist/sdk/runtime.d.ts.map +1 -1
- package/dist/sdk/runtime.js +14 -5
- package/dist/sdk/runtime.js.map +1 -1
- package/dist/sdk/test.d.ts +10 -1
- package/dist/sdk/test.d.ts.map +1 -1
- package/dist/sdk/test.js +45 -4
- package/dist/sdk/test.js.map +1 -1
- package/dist/sdk/types.d.ts +2 -1
- package/dist/sdk/types.d.ts.map +1 -1
- package/dist/sdk/viewer.d.ts +3 -9
- package/dist/sdk/viewer.d.ts.map +1 -1
- package/dist/sdk/viewer.js +41 -127
- package/dist/sdk/viewer.js.map +1 -1
- package/dist/viewer/bootstrap.d.ts +10 -0
- package/dist/viewer/bootstrap.d.ts.map +1 -0
- package/dist/viewer/bootstrap.js +2 -0
- package/dist/viewer/bootstrap.js.map +1 -0
- package/dist/viewer/client-entry.d.ts +2 -0
- package/dist/viewer/client-entry.d.ts.map +1 -0
- package/dist/viewer/client-entry.js +31 -0
- package/dist/viewer/client-entry.js.map +1 -0
- package/dist/viewer/generated-api.d.ts +15 -0
- package/dist/viewer/generated-api.d.ts.map +1 -0
- package/dist/viewer/generated-api.js +42 -0
- package/dist/viewer/generated-api.js.map +1 -0
- package/dist/viewer/generated-contracts.d.ts +13 -0
- package/dist/viewer/generated-contracts.d.ts.map +1 -0
- package/dist/viewer/generated-contracts.js +12 -0
- package/dist/viewer/generated-contracts.js.map +1 -0
- package/dist/viewer/main.js +64 -3
- package/dist/viewer/main.js.map +1 -1
- package/dist/viewer/page.d.ts +2 -4
- package/dist/viewer/page.d.ts.map +1 -1
- package/dist/viewer/page.js +18 -194
- package/dist/viewer/page.js.map +1 -1
- package/dist/viewer/presentation.d.ts +8 -0
- package/dist/viewer/presentation.d.ts.map +1 -0
- package/dist/viewer/presentation.js +45 -0
- package/dist/viewer/presentation.js.map +1 -0
- package/dist/viewer/protocol.d.ts +21 -0
- package/dist/viewer/protocol.d.ts.map +1 -0
- package/dist/viewer/protocol.js +6 -0
- package/dist/viewer/protocol.js.map +1 -0
- package/dist/viewer/server.d.ts +5 -10
- package/dist/viewer/server.d.ts.map +1 -1
- package/dist/viewer/server.js +301 -199
- package/dist/viewer/server.js.map +1 -1
- package/dist/viewer/styles.d.ts +1 -1
- package/dist/viewer/styles.d.ts.map +1 -1
- package/dist/viewer/styles.js +82 -429
- package/dist/viewer/styles.js.map +1 -1
- package/dist/viewer/stylex.css +1322 -0
- package/dist/viewer/test-catalog.d.ts +43 -0
- package/dist/viewer/test-catalog.d.ts.map +1 -0
- package/dist/viewer/test-catalog.js +27 -0
- package/dist/viewer/test-catalog.js.map +1 -0
- package/dist/viewer/v2-client.d.ts +7 -0
- package/dist/viewer/v2-client.d.ts.map +1 -0
- package/dist/viewer/v2-client.js +1862 -0
- package/dist/viewer/v2-client.js.map +1 -0
- package/package.json +14 -4
- package/dist/compare-scenario.d.ts +0 -65
- package/dist/compare-scenario.d.ts.map +0 -1
- package/dist/compare-scenario.js +0 -325
- package/dist/compare-scenario.js.map +0 -1
- package/dist/failures.d.ts +0 -8
- package/dist/failures.d.ts.map +0 -1
- package/dist/failures.js +0 -7
- package/dist/failures.js.map +0 -1
- package/dist/scenario-story.d.ts +0 -41
- package/dist/scenario-story.d.ts.map +0 -1
- package/dist/scenario-story.js +0 -477
- package/dist/scenario-story.js.map +0 -1
- package/dist/scenario-usage.d.ts +0 -15
- package/dist/scenario-usage.d.ts.map +0 -1
- package/dist/scenario-usage.js +0 -18
- package/dist/scenario-usage.js.map +0 -1
- package/dist/sdk/viewer-results.d.ts +0 -43
- package/dist/sdk/viewer-results.d.ts.map +0 -1
- package/dist/sdk/viewer-results.js +0 -126
- package/dist/sdk/viewer-results.js.map +0 -1
- package/dist/types.d.ts +0 -328
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -2
- package/dist/types.js.map +0 -1
- package/dist/viewer/catalog.d.ts +0 -66
- package/dist/viewer/catalog.d.ts.map +0 -1
- package/dist/viewer/catalog.js +0 -49
- package/dist/viewer/catalog.js.map +0 -1
- package/dist/viewer/client.d.ts +0 -7
- package/dist/viewer/client.d.ts.map +0 -1
- package/dist/viewer/client.js +0 -14
- package/dist/viewer/client.js.map +0 -1
- package/dist/viewer/events.d.ts +0 -118
- package/dist/viewer/events.d.ts.map +0 -1
- package/dist/viewer/events.js +0 -51
- package/dist/viewer/events.js.map +0 -1
- package/dist/viewer/run-controller.d.ts +0 -43
- package/dist/viewer/run-controller.d.ts.map +0 -1
- package/dist/viewer/run-controller.js +0 -475
- package/dist/viewer/run-controller.js.map +0 -1
- package/dist/worker-pool.d.ts +0 -12
- package/dist/worker-pool.d.ts.map +0 -1
- package/dist/worker-pool.js +0 -26
- package/dist/worker-pool.js.map +0 -1
|
@@ -0,0 +1,1862 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as stylex from "@stylexjs/stylex";
|
|
3
|
+
import { useMutation, useQueries, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
4
|
+
import { createRootRoute, createRoute, createRouter, Link, Outlet, useNavigate, } from "@tanstack/react-router";
|
|
5
|
+
import { createContext, useContext, useState } from "react";
|
|
6
|
+
import Markdown from "react-markdown";
|
|
7
|
+
import { viewerApi } from "./generated-api.js";
|
|
8
|
+
import { assertionComparison, conversationPlaceholder, stripAnsi } from "./presentation.js";
|
|
9
|
+
const SENTENCE_BOUNDARY = /(?<=[.!?])\s+/;
|
|
10
|
+
const LOCAL_PATH_LINK = /\[([^\]]+)\]\(<local-path>[^)]*\)/g;
|
|
11
|
+
const runningPulse = stylex.keyframes({
|
|
12
|
+
"0%, 60%, 100%": { opacity: 0.3, transform: "translateY(0)" },
|
|
13
|
+
"30%": { opacity: 1, transform: "translateY(-2px)" },
|
|
14
|
+
});
|
|
15
|
+
const CAMEL_CASE_BOUNDARY = /([a-z])([A-Z])/g;
|
|
16
|
+
const INITIAL_CHARACTER = /^./;
|
|
17
|
+
const WorkerContext = createContext({ workers: 1, setWorkers: () => undefined });
|
|
18
|
+
const rootRoute = createRootRoute({ component: ViewerLayout });
|
|
19
|
+
const indexRoute = createRoute({
|
|
20
|
+
getParentRoute: () => rootRoute,
|
|
21
|
+
path: "/",
|
|
22
|
+
component: TestCatalogPage,
|
|
23
|
+
});
|
|
24
|
+
const testRoute = createRoute({
|
|
25
|
+
getParentRoute: () => rootRoute,
|
|
26
|
+
path: "/tests/$testId",
|
|
27
|
+
validateSearch: (search) => ({
|
|
28
|
+
execution: typeof search.execution === "string" ? search.execution : undefined,
|
|
29
|
+
view: search.view === "setup" || search.view === "history" || search.view === "current"
|
|
30
|
+
? search.view
|
|
31
|
+
: undefined,
|
|
32
|
+
}),
|
|
33
|
+
component: TestPage,
|
|
34
|
+
});
|
|
35
|
+
const executionRoute = createRoute({
|
|
36
|
+
getParentRoute: () => rootRoute,
|
|
37
|
+
path: "/executions/$executionId",
|
|
38
|
+
component: ExecutionPage,
|
|
39
|
+
});
|
|
40
|
+
const compareRoute = createRoute({
|
|
41
|
+
getParentRoute: () => rootRoute,
|
|
42
|
+
path: "/compare/$left/$right",
|
|
43
|
+
component: ComparePage,
|
|
44
|
+
});
|
|
45
|
+
export const viewerRouter = createRouter({
|
|
46
|
+
routeTree: rootRoute.addChildren([indexRoute, testRoute, executionRoute, compareRoute]),
|
|
47
|
+
});
|
|
48
|
+
const styles = stylex.create({
|
|
49
|
+
skipLink: {
|
|
50
|
+
position: "fixed",
|
|
51
|
+
top: "0.75rem",
|
|
52
|
+
left: "0.75rem",
|
|
53
|
+
zIndex: 10,
|
|
54
|
+
padding: "0.55rem 0.75rem",
|
|
55
|
+
borderRadius: 8,
|
|
56
|
+
backgroundColor: "var(--accent)",
|
|
57
|
+
color: "oklch(0.18 0.03 175)",
|
|
58
|
+
fontSize: "0.8rem",
|
|
59
|
+
fontWeight: 750,
|
|
60
|
+
textDecoration: "none",
|
|
61
|
+
transform: { default: "translateY(-200%)", ":focus": "translateY(0)" },
|
|
62
|
+
transition: {
|
|
63
|
+
default: "transform 120ms ease",
|
|
64
|
+
"@media (prefers-reduced-motion: reduce)": "none",
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
shell: {
|
|
68
|
+
display: "grid",
|
|
69
|
+
gridTemplateColumns: {
|
|
70
|
+
default: "18rem minmax(0, 1fr)",
|
|
71
|
+
"@media (max-width: 820px)": "14rem minmax(0, 1fr)",
|
|
72
|
+
"@media (max-width: 620px)": "1fr",
|
|
73
|
+
},
|
|
74
|
+
height: "100dvh",
|
|
75
|
+
minHeight: 0,
|
|
76
|
+
},
|
|
77
|
+
shellCollapsed: { gridTemplateColumns: "3.75rem minmax(0, 1fr)" },
|
|
78
|
+
sidebar: {
|
|
79
|
+
borderRight: "1px solid var(--border)",
|
|
80
|
+
overflow: "hidden",
|
|
81
|
+
display: "flex",
|
|
82
|
+
flexDirection: "column",
|
|
83
|
+
padding: "1rem 0 0",
|
|
84
|
+
backgroundColor: "var(--sidebar)",
|
|
85
|
+
minHeight: 0,
|
|
86
|
+
height: { default: "100dvh", "@media (max-width: 620px)": "auto" },
|
|
87
|
+
maxHeight: { default: "none", "@media (max-width: 620px)": "18rem" },
|
|
88
|
+
},
|
|
89
|
+
sidebarCollapsed: { paddingTop: "1rem", height: "100dvh", maxHeight: "none" },
|
|
90
|
+
main: {
|
|
91
|
+
overflow: "auto",
|
|
92
|
+
minWidth: 0,
|
|
93
|
+
padding: {
|
|
94
|
+
default: "2rem clamp(1.5rem, 3vw, 3rem) 3rem",
|
|
95
|
+
"@media (max-width: 820px)": "1.5rem 1.25rem 3rem",
|
|
96
|
+
"@media (max-width: 620px)": "1rem 0.85rem 2rem",
|
|
97
|
+
},
|
|
98
|
+
maxWidth: "88rem",
|
|
99
|
+
width: "100%",
|
|
100
|
+
margin: "0 auto",
|
|
101
|
+
},
|
|
102
|
+
brand: {
|
|
103
|
+
color: "var(--accent)",
|
|
104
|
+
fontSize: "0.66rem",
|
|
105
|
+
fontWeight: 750,
|
|
106
|
+
letterSpacing: "0.11em",
|
|
107
|
+
textTransform: "uppercase",
|
|
108
|
+
},
|
|
109
|
+
sidebarHeader: {
|
|
110
|
+
display: "grid",
|
|
111
|
+
gap: "0.65rem",
|
|
112
|
+
padding: "0 0.45rem 1rem",
|
|
113
|
+
margin: "0 0.8rem",
|
|
114
|
+
borderBottom: "1px solid var(--border)",
|
|
115
|
+
},
|
|
116
|
+
sidebarHeaderCollapsed: {
|
|
117
|
+
padding: 0,
|
|
118
|
+
margin: 0,
|
|
119
|
+
borderBottom: 0,
|
|
120
|
+
display: "flex",
|
|
121
|
+
justifyContent: "center",
|
|
122
|
+
},
|
|
123
|
+
toggleButton: {
|
|
124
|
+
width: "1.85rem",
|
|
125
|
+
height: "1.85rem",
|
|
126
|
+
display: "inline-grid",
|
|
127
|
+
placeItems: "center",
|
|
128
|
+
flex: "none",
|
|
129
|
+
padding: 0,
|
|
130
|
+
borderRadius: 8,
|
|
131
|
+
backgroundColor: {
|
|
132
|
+
default: "var(--panel-2)",
|
|
133
|
+
":hover": "var(--panel-3)",
|
|
134
|
+
":active": "var(--panel-3)",
|
|
135
|
+
},
|
|
136
|
+
color: "var(--text)",
|
|
137
|
+
cursor: "pointer",
|
|
138
|
+
fontSize: "0.95rem",
|
|
139
|
+
lineHeight: 1,
|
|
140
|
+
boxShadow: "none",
|
|
141
|
+
},
|
|
142
|
+
sidebarTitleRow: {
|
|
143
|
+
display: "flex",
|
|
144
|
+
alignItems: "center",
|
|
145
|
+
justifyContent: "space-between",
|
|
146
|
+
gap: "0.75rem",
|
|
147
|
+
},
|
|
148
|
+
sidebarTitleIdentity: { display: "flex", alignItems: "center", gap: "0.65rem" },
|
|
149
|
+
suiteRunButton: {
|
|
150
|
+
width: "fit-content",
|
|
151
|
+
minHeight: "1.8rem",
|
|
152
|
+
padding: "0.3rem 0.55rem",
|
|
153
|
+
borderWidth: 1,
|
|
154
|
+
borderStyle: "solid",
|
|
155
|
+
borderColor: "var(--border)",
|
|
156
|
+
borderRadius: 8,
|
|
157
|
+
backgroundColor: {
|
|
158
|
+
default: "var(--panel-2)",
|
|
159
|
+
":hover": "var(--panel-3)",
|
|
160
|
+
":disabled": "var(--panel-2)",
|
|
161
|
+
},
|
|
162
|
+
color: "var(--text)",
|
|
163
|
+
cursor: { default: "pointer", ":disabled": "wait" },
|
|
164
|
+
display: "flex",
|
|
165
|
+
alignItems: "center",
|
|
166
|
+
justifyContent: "center",
|
|
167
|
+
gap: "0.45rem",
|
|
168
|
+
fontSize: "0.7rem",
|
|
169
|
+
fontWeight: 700,
|
|
170
|
+
},
|
|
171
|
+
suiteControls: {
|
|
172
|
+
display: "grid",
|
|
173
|
+
gridTemplateColumns: "max-content minmax(0, 1fr)",
|
|
174
|
+
alignItems: "center",
|
|
175
|
+
columnGap: "0.75rem",
|
|
176
|
+
},
|
|
177
|
+
workerControl: {
|
|
178
|
+
display: "flex",
|
|
179
|
+
alignItems: "center",
|
|
180
|
+
justifySelf: "end",
|
|
181
|
+
gap: "0.35rem",
|
|
182
|
+
color: "var(--muted)",
|
|
183
|
+
fontSize: "0.68rem",
|
|
184
|
+
fontWeight: 650,
|
|
185
|
+
},
|
|
186
|
+
workerInput: {
|
|
187
|
+
width: "2.8rem",
|
|
188
|
+
height: "1.8rem",
|
|
189
|
+
padding: "0.25rem 0.35rem",
|
|
190
|
+
borderWidth: 1,
|
|
191
|
+
borderStyle: "solid",
|
|
192
|
+
borderColor: { default: "var(--border)", ":focus": "var(--accent)" },
|
|
193
|
+
borderRadius: 7,
|
|
194
|
+
backgroundColor: "var(--panel-2)",
|
|
195
|
+
color: "var(--text)",
|
|
196
|
+
fontSize: "0.72rem",
|
|
197
|
+
fontVariantNumeric: "tabular-nums",
|
|
198
|
+
outline: "none",
|
|
199
|
+
},
|
|
200
|
+
groupHeaderActions: { display: "flex", alignItems: "center", gap: "0.4rem" },
|
|
201
|
+
groupRunButton: {
|
|
202
|
+
width: "1.45rem",
|
|
203
|
+
height: "1.45rem",
|
|
204
|
+
padding: 0,
|
|
205
|
+
borderRadius: 6,
|
|
206
|
+
backgroundColor: { default: "transparent", ":hover": "var(--panel-3)" },
|
|
207
|
+
color: "var(--accent)",
|
|
208
|
+
cursor: { default: "pointer", ":disabled": "wait" },
|
|
209
|
+
fontSize: "0.62rem",
|
|
210
|
+
lineHeight: 1,
|
|
211
|
+
},
|
|
212
|
+
countBadge: {
|
|
213
|
+
padding: "0.22rem 0.55rem",
|
|
214
|
+
borderRadius: 999,
|
|
215
|
+
backgroundColor: "var(--panel-3)",
|
|
216
|
+
color: "var(--muted)",
|
|
217
|
+
fontSize: "0.72rem",
|
|
218
|
+
fontWeight: 700,
|
|
219
|
+
fontVariantNumeric: "tabular-nums",
|
|
220
|
+
},
|
|
221
|
+
title: {
|
|
222
|
+
margin: 0,
|
|
223
|
+
fontSize: { default: "clamp(1.08rem, 1.5vw, 1.3rem)", "@media (max-width: 620px)": "1.08rem" },
|
|
224
|
+
lineHeight: 1.18,
|
|
225
|
+
letterSpacing: "-0.025em",
|
|
226
|
+
fontWeight: 720,
|
|
227
|
+
},
|
|
228
|
+
sidebarTitle: { fontSize: "1.08rem" },
|
|
229
|
+
sectionTitle: { margin: 0, fontSize: "0.92rem", letterSpacing: "-0.01em" },
|
|
230
|
+
section: { display: "grid", gap: "0.75rem", marginTop: "1.5rem" },
|
|
231
|
+
list: { display: "grid", gap: "0.45rem" },
|
|
232
|
+
card: {
|
|
233
|
+
border: "1px solid var(--border)",
|
|
234
|
+
borderRadius: 14,
|
|
235
|
+
backgroundColor: "var(--panel-2)",
|
|
236
|
+
padding: "0.75rem",
|
|
237
|
+
},
|
|
238
|
+
link: { color: "var(--text)", textDecoration: "none" },
|
|
239
|
+
buttonReset: {
|
|
240
|
+
appearance: "none",
|
|
241
|
+
borderWidth: 0,
|
|
242
|
+
borderStyle: "solid",
|
|
243
|
+
borderColor: "transparent",
|
|
244
|
+
outlineWidth: { default: 0, ":focus-visible": 2 },
|
|
245
|
+
outlineStyle: "solid",
|
|
246
|
+
outlineColor: "var(--accent)",
|
|
247
|
+
outlineOffset: 2,
|
|
248
|
+
},
|
|
249
|
+
button: {
|
|
250
|
+
minHeight: "2.5rem",
|
|
251
|
+
padding: "0.6rem 0.95rem",
|
|
252
|
+
borderRadius: 8,
|
|
253
|
+
backgroundColor: {
|
|
254
|
+
default: "var(--accent)",
|
|
255
|
+
":hover": "oklch(0.82 0.14 175)",
|
|
256
|
+
":active": "oklch(0.72 0.14 175)",
|
|
257
|
+
},
|
|
258
|
+
color: "oklch(0.18 0.03 175)",
|
|
259
|
+
fontSize: "0.82rem",
|
|
260
|
+
fontWeight: 720,
|
|
261
|
+
letterSpacing: "0.01em",
|
|
262
|
+
display: "inline-flex",
|
|
263
|
+
alignItems: "center",
|
|
264
|
+
justifyContent: "center",
|
|
265
|
+
gap: "0.4rem",
|
|
266
|
+
cursor: "pointer",
|
|
267
|
+
boxShadow: "0 1px 2px oklch(0.08 0.02 258 / 0.35)",
|
|
268
|
+
transition: "background-color 120ms ease, border-color 120ms ease, transform 120ms ease",
|
|
269
|
+
transform: { default: "translateY(0)", ":active": "translateY(1px)" },
|
|
270
|
+
},
|
|
271
|
+
secondaryButton: {
|
|
272
|
+
borderWidth: 1,
|
|
273
|
+
borderStyle: "solid",
|
|
274
|
+
borderColor: { default: "var(--border)", ":hover": "var(--border-strong)" },
|
|
275
|
+
backgroundColor: {
|
|
276
|
+
default: "var(--panel-2)",
|
|
277
|
+
":hover": "var(--panel-3)",
|
|
278
|
+
":active": "var(--panel)",
|
|
279
|
+
},
|
|
280
|
+
color: "var(--text)",
|
|
281
|
+
boxShadow: "none",
|
|
282
|
+
},
|
|
283
|
+
buttonIcon: { fontSize: "0.68rem", opacity: 0.8 },
|
|
284
|
+
navigation: {
|
|
285
|
+
overflow: "auto",
|
|
286
|
+
minHeight: 0,
|
|
287
|
+
padding: "0.75rem 0.65rem 1rem",
|
|
288
|
+
display: "grid",
|
|
289
|
+
alignContent: "start",
|
|
290
|
+
gap: "0.75rem",
|
|
291
|
+
},
|
|
292
|
+
navSection: {
|
|
293
|
+
display: "grid",
|
|
294
|
+
gap: "0.18rem",
|
|
295
|
+
padding: "0.35rem",
|
|
296
|
+
borderWidth: 1,
|
|
297
|
+
borderStyle: "solid",
|
|
298
|
+
borderColor: "var(--border)",
|
|
299
|
+
borderRadius: 10,
|
|
300
|
+
backgroundColor: "var(--bg)",
|
|
301
|
+
},
|
|
302
|
+
groupHeader: {
|
|
303
|
+
display: "flex",
|
|
304
|
+
alignItems: "center",
|
|
305
|
+
justifyContent: "space-between",
|
|
306
|
+
gap: "0.75rem",
|
|
307
|
+
padding: "0.48rem 0.52rem 0.55rem",
|
|
308
|
+
borderBottom: "1px solid var(--border)",
|
|
309
|
+
marginBottom: "0.08rem",
|
|
310
|
+
},
|
|
311
|
+
groupLabel: {
|
|
312
|
+
color: "var(--text)",
|
|
313
|
+
fontSize: "0.66rem",
|
|
314
|
+
fontWeight: 780,
|
|
315
|
+
letterSpacing: "0.08em",
|
|
316
|
+
textTransform: "uppercase",
|
|
317
|
+
},
|
|
318
|
+
groupCount: { color: "var(--subtle)", fontSize: "0.66rem", fontVariantNumeric: "tabular-nums" },
|
|
319
|
+
navLink: {
|
|
320
|
+
display: "block",
|
|
321
|
+
padding: "0.55rem 0.6rem",
|
|
322
|
+
borderRadius: 8,
|
|
323
|
+
fontSize: "0.78rem",
|
|
324
|
+
fontWeight: 540,
|
|
325
|
+
lineHeight: 1.38,
|
|
326
|
+
color: "var(--muted)",
|
|
327
|
+
textDecoration: "none",
|
|
328
|
+
border: "1px solid transparent",
|
|
329
|
+
backgroundColor: { default: "transparent", ":hover": "var(--panel)" },
|
|
330
|
+
},
|
|
331
|
+
navItemHeader: {
|
|
332
|
+
display: "grid",
|
|
333
|
+
gridTemplateColumns: "0.65rem minmax(0, 1fr)",
|
|
334
|
+
alignItems: "flex-start",
|
|
335
|
+
gap: "0.5rem",
|
|
336
|
+
},
|
|
337
|
+
navItemTitle: { minWidth: 0 },
|
|
338
|
+
navStatus: {
|
|
339
|
+
display: "grid",
|
|
340
|
+
placeItems: "center",
|
|
341
|
+
width: "0.65rem",
|
|
342
|
+
height: "1.1rem",
|
|
343
|
+
},
|
|
344
|
+
navStatusDot: { width: 7, height: 7, borderRadius: 999, backgroundColor: "var(--muted)" },
|
|
345
|
+
navStatusDotPass: { backgroundColor: "var(--pass)" },
|
|
346
|
+
navStatusDotFail: { backgroundColor: "var(--fail)" },
|
|
347
|
+
navStatusDotRunning: { backgroundColor: "var(--skip)", boxShadow: "0 0 0 3px var(--skip-soft)" },
|
|
348
|
+
active: {
|
|
349
|
+
backgroundColor: "var(--panel-2)",
|
|
350
|
+
color: "var(--text)",
|
|
351
|
+
borderColor: "transparent",
|
|
352
|
+
boxShadow: "none",
|
|
353
|
+
},
|
|
354
|
+
hero: {
|
|
355
|
+
padding: { default: "1.1rem 1.25rem", "@media (max-width: 620px)": "1rem" },
|
|
356
|
+
border: "1px solid var(--border)",
|
|
357
|
+
borderRadius: 12,
|
|
358
|
+
backgroundColor: "var(--panel)",
|
|
359
|
+
display: "grid",
|
|
360
|
+
gap: "0.7rem",
|
|
361
|
+
boxShadow: "0 10px 30px oklch(0.08 0.02 258 / 0.14)",
|
|
362
|
+
},
|
|
363
|
+
heroTop: {
|
|
364
|
+
display: "grid",
|
|
365
|
+
gridTemplateColumns: {
|
|
366
|
+
default: "minmax(0, 1fr) max-content",
|
|
367
|
+
"@media (max-width: 620px)": "1fr",
|
|
368
|
+
},
|
|
369
|
+
alignItems: "flex-start",
|
|
370
|
+
gap: "1rem",
|
|
371
|
+
},
|
|
372
|
+
heroCopy: { display: "grid", gap: "0.35rem", maxWidth: "56rem", minWidth: 0 },
|
|
373
|
+
heroAction: {
|
|
374
|
+
justifySelf: { default: "end", "@media (max-width: 620px)": "start" },
|
|
375
|
+
alignSelf: "start",
|
|
376
|
+
},
|
|
377
|
+
description: { color: "var(--muted)", fontSize: "0.82rem", lineHeight: 1.5, maxWidth: "54rem" },
|
|
378
|
+
path: {
|
|
379
|
+
color: "var(--subtle)",
|
|
380
|
+
fontSize: "0.7rem",
|
|
381
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
|
|
382
|
+
wordBreak: "break-word",
|
|
383
|
+
paddingTop: "0.6rem",
|
|
384
|
+
borderTopWidth: 1,
|
|
385
|
+
borderTopStyle: "solid",
|
|
386
|
+
borderTopColor: "var(--border)",
|
|
387
|
+
},
|
|
388
|
+
meta: { color: "var(--muted)", fontSize: "0.8rem", lineHeight: 1.45 },
|
|
389
|
+
contextPanel: {
|
|
390
|
+
border: "1px solid var(--border)",
|
|
391
|
+
borderRadius: 12,
|
|
392
|
+
backgroundColor: "var(--panel)",
|
|
393
|
+
overflow: "hidden",
|
|
394
|
+
},
|
|
395
|
+
contextHeader: {
|
|
396
|
+
display: "flex",
|
|
397
|
+
alignItems: "flex-start",
|
|
398
|
+
justifyContent: "space-between",
|
|
399
|
+
gap: "1rem",
|
|
400
|
+
padding: "0.75rem 0.9rem",
|
|
401
|
+
borderBottom: "1px solid var(--border)",
|
|
402
|
+
},
|
|
403
|
+
contextIntro: { display: "grid", gap: "0.2rem" },
|
|
404
|
+
resourceCount: { color: "var(--accent)", fontSize: "0.75rem", fontWeight: 700 },
|
|
405
|
+
detailsBody: { padding: "0.75rem", display: "grid", gap: "0.6rem" },
|
|
406
|
+
setupBody: { padding: "0.85rem 0.9rem", display: "grid", gap: "1.15rem" },
|
|
407
|
+
setupSection: { display: "grid", gap: "0.55rem" },
|
|
408
|
+
setupSectionHeader: {
|
|
409
|
+
display: "flex",
|
|
410
|
+
alignItems: "flex-start",
|
|
411
|
+
justifyContent: "space-between",
|
|
412
|
+
gap: "1rem",
|
|
413
|
+
},
|
|
414
|
+
setupSectionCopy: { display: "grid", gap: "0.12rem" },
|
|
415
|
+
resourceGrid: {
|
|
416
|
+
display: "grid",
|
|
417
|
+
gridTemplateColumns: "repeat(auto-fill, minmax(min(17rem, 100%), 22rem))",
|
|
418
|
+
gap: "0.6rem",
|
|
419
|
+
},
|
|
420
|
+
resourceCard: {
|
|
421
|
+
display: "grid",
|
|
422
|
+
alignContent: "start",
|
|
423
|
+
gap: "0.5rem",
|
|
424
|
+
padding: "0.7rem 0.75rem",
|
|
425
|
+
},
|
|
426
|
+
resourceHeader: {
|
|
427
|
+
display: "flex",
|
|
428
|
+
alignItems: "center",
|
|
429
|
+
justifyContent: "space-between",
|
|
430
|
+
gap: "0.75rem",
|
|
431
|
+
},
|
|
432
|
+
resourceKind: {
|
|
433
|
+
color: "var(--accent)",
|
|
434
|
+
backgroundColor: "var(--accent-soft)",
|
|
435
|
+
borderRadius: 999,
|
|
436
|
+
padding: "0.16rem 0.48rem",
|
|
437
|
+
fontSize: "0.65rem",
|
|
438
|
+
fontWeight: 750,
|
|
439
|
+
textTransform: "uppercase",
|
|
440
|
+
letterSpacing: "0.05em",
|
|
441
|
+
},
|
|
442
|
+
resourceBody: { display: "grid", gap: "0.5rem" },
|
|
443
|
+
resourceFacts: { display: "grid", gap: "0.22rem" },
|
|
444
|
+
resourceDescription: {
|
|
445
|
+
color: "var(--text)",
|
|
446
|
+
fontSize: "0.77rem",
|
|
447
|
+
lineHeight: 1.5,
|
|
448
|
+
margin: 0,
|
|
449
|
+
},
|
|
450
|
+
resourceFact: {
|
|
451
|
+
display: "grid",
|
|
452
|
+
gridTemplateColumns: "4.5rem minmax(0, 1fr)",
|
|
453
|
+
gap: "0.65rem",
|
|
454
|
+
alignItems: "baseline",
|
|
455
|
+
},
|
|
456
|
+
resourceFactLabel: {
|
|
457
|
+
color: "var(--subtle)",
|
|
458
|
+
fontSize: "0.7rem",
|
|
459
|
+
fontWeight: 700,
|
|
460
|
+
textTransform: "uppercase",
|
|
461
|
+
letterSpacing: "0.04em",
|
|
462
|
+
},
|
|
463
|
+
resourceFactValue: { color: "var(--muted)", fontSize: "0.78rem", wordBreak: "break-word" },
|
|
464
|
+
resourcePrompt: {
|
|
465
|
+
marginTop: "0.5rem",
|
|
466
|
+
padding: "0.55rem",
|
|
467
|
+
borderRadius: 8,
|
|
468
|
+
border: "1px solid var(--border)",
|
|
469
|
+
backgroundColor: "var(--bg)",
|
|
470
|
+
display: "grid",
|
|
471
|
+
gap: "0.25rem",
|
|
472
|
+
},
|
|
473
|
+
disclosureIcon: { color: "var(--accent)", fontSize: "0.8rem" },
|
|
474
|
+
workspaceRow: {
|
|
475
|
+
padding: "0.65rem 0.75rem",
|
|
476
|
+
border: "1px solid var(--border)",
|
|
477
|
+
borderRadius: 9,
|
|
478
|
+
backgroundColor: "var(--panel-2)",
|
|
479
|
+
display: "grid",
|
|
480
|
+
gap: "0.25rem",
|
|
481
|
+
},
|
|
482
|
+
tabList: {
|
|
483
|
+
display: "flex",
|
|
484
|
+
gap: "1.25rem",
|
|
485
|
+
marginTop: "0.75rem",
|
|
486
|
+
padding: "0 0.25rem",
|
|
487
|
+
borderBottomWidth: 1,
|
|
488
|
+
borderBottomStyle: "solid",
|
|
489
|
+
borderBottomColor: "var(--border)",
|
|
490
|
+
overflowX: "auto",
|
|
491
|
+
overflowY: "hidden",
|
|
492
|
+
},
|
|
493
|
+
tab: {
|
|
494
|
+
flex: "0 0 auto",
|
|
495
|
+
minHeight: "2.35rem",
|
|
496
|
+
marginBottom: -1,
|
|
497
|
+
padding: "0.7rem 0.15rem 0.65rem",
|
|
498
|
+
borderBottomWidth: 2,
|
|
499
|
+
borderBottomColor: "transparent",
|
|
500
|
+
borderRadius: 0,
|
|
501
|
+
backgroundColor: "transparent",
|
|
502
|
+
color: "var(--muted)",
|
|
503
|
+
fontSize: "0.8rem",
|
|
504
|
+
fontWeight: 680,
|
|
505
|
+
cursor: "pointer",
|
|
506
|
+
whiteSpace: "nowrap",
|
|
507
|
+
},
|
|
508
|
+
tabActive: {
|
|
509
|
+
color: "var(--text)",
|
|
510
|
+
borderBottomColor: "var(--accent)",
|
|
511
|
+
},
|
|
512
|
+
tabPanel: { marginTop: "0.7rem" },
|
|
513
|
+
tabSection: { display: "grid", gap: "1rem" },
|
|
514
|
+
historyList: { display: "grid", gap: "0.65rem", marginTop: "1rem" },
|
|
515
|
+
historyButton: {
|
|
516
|
+
width: "100%",
|
|
517
|
+
padding: "0.65rem 0.8rem",
|
|
518
|
+
borderWidth: 1,
|
|
519
|
+
borderStyle: "solid",
|
|
520
|
+
borderColor: { default: "var(--border)", ":hover": "var(--border-strong)" },
|
|
521
|
+
borderRadius: 10,
|
|
522
|
+
backgroundColor: { default: "var(--panel-2)", ":hover": "var(--panel-3)" },
|
|
523
|
+
color: "var(--text)",
|
|
524
|
+
cursor: "pointer",
|
|
525
|
+
display: "flex",
|
|
526
|
+
alignItems: "center",
|
|
527
|
+
justifyContent: "space-between",
|
|
528
|
+
gap: "1rem",
|
|
529
|
+
textAlign: "left",
|
|
530
|
+
},
|
|
531
|
+
historyIdentity: { display: "grid", gap: "0.2rem", minWidth: 0 },
|
|
532
|
+
historyDate: { color: "var(--muted)", fontSize: "0.78rem" },
|
|
533
|
+
historyId: {
|
|
534
|
+
color: "var(--subtle)",
|
|
535
|
+
fontSize: "0.72rem",
|
|
536
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
|
|
537
|
+
},
|
|
538
|
+
sectionHeading: {
|
|
539
|
+
display: "flex",
|
|
540
|
+
alignItems: "flex-end",
|
|
541
|
+
justifyContent: "space-between",
|
|
542
|
+
gap: "1rem",
|
|
543
|
+
flexWrap: "wrap",
|
|
544
|
+
},
|
|
545
|
+
quietHeader: {
|
|
546
|
+
display: "flex",
|
|
547
|
+
justifyContent: "flex-end",
|
|
548
|
+
marginBottom: "0.75rem",
|
|
549
|
+
},
|
|
550
|
+
statusPanel: {
|
|
551
|
+
display: "grid",
|
|
552
|
+
gap: "0.85rem",
|
|
553
|
+
},
|
|
554
|
+
runControls: { display: "flex", justifyContent: "flex-end" },
|
|
555
|
+
row: { display: "flex", alignItems: "flex-start", justifyContent: "space-between", gap: "1rem" },
|
|
556
|
+
attemptActions: { display: "flex", alignItems: "center", gap: "0.55rem", flex: "none" },
|
|
557
|
+
copyFailureButton: {
|
|
558
|
+
minHeight: "1.75rem",
|
|
559
|
+
padding: "0.3rem 0.55rem",
|
|
560
|
+
borderWidth: 1,
|
|
561
|
+
borderStyle: "solid",
|
|
562
|
+
borderColor: "var(--border)",
|
|
563
|
+
borderRadius: 7,
|
|
564
|
+
backgroundColor: { default: "var(--panel-2)", ":hover": "var(--panel-3)" },
|
|
565
|
+
color: "var(--text)",
|
|
566
|
+
fontSize: "0.68rem",
|
|
567
|
+
fontWeight: 680,
|
|
568
|
+
cursor: "pointer",
|
|
569
|
+
},
|
|
570
|
+
attemptCard: {
|
|
571
|
+
border: "1px solid var(--border)",
|
|
572
|
+
borderRadius: 12,
|
|
573
|
+
backgroundColor: "var(--panel)",
|
|
574
|
+
padding: "0.85rem",
|
|
575
|
+
display: "grid",
|
|
576
|
+
gap: "0.7rem",
|
|
577
|
+
},
|
|
578
|
+
attemptTitle: { fontSize: "0.84rem", lineHeight: 1.4 },
|
|
579
|
+
resultPanel: {
|
|
580
|
+
display: "grid",
|
|
581
|
+
gap: "0.55rem",
|
|
582
|
+
padding: "0.75rem",
|
|
583
|
+
borderRadius: 10,
|
|
584
|
+
backgroundColor: "var(--panel-2)",
|
|
585
|
+
border: "1px solid var(--border)",
|
|
586
|
+
},
|
|
587
|
+
contentHeading: { margin: 0, fontSize: "0.79rem", color: "var(--text)" },
|
|
588
|
+
resultOutput: {
|
|
589
|
+
margin: 0,
|
|
590
|
+
whiteSpace: "pre-wrap",
|
|
591
|
+
wordBreak: "break-word",
|
|
592
|
+
fontSize: "0.82rem",
|
|
593
|
+
lineHeight: 1.6,
|
|
594
|
+
color: "var(--text)",
|
|
595
|
+
},
|
|
596
|
+
assertionCard: {
|
|
597
|
+
display: "grid",
|
|
598
|
+
gap: "0.4rem",
|
|
599
|
+
marginTop: "-0.1rem",
|
|
600
|
+
marginLeft: "1.5rem",
|
|
601
|
+
padding: "0.15rem 0 0.15rem 0.75rem",
|
|
602
|
+
borderLeftWidth: 2,
|
|
603
|
+
borderLeftStyle: "solid",
|
|
604
|
+
borderLeftColor: "var(--fail)",
|
|
605
|
+
},
|
|
606
|
+
assertionTitle: { color: "var(--fail)", fontSize: "0.74rem" },
|
|
607
|
+
assertionValues: {
|
|
608
|
+
display: "grid",
|
|
609
|
+
gap: "0.35rem",
|
|
610
|
+
margin: 0,
|
|
611
|
+
},
|
|
612
|
+
assertionValue: {
|
|
613
|
+
display: "grid",
|
|
614
|
+
gridTemplateColumns: "5rem minmax(0, 1fr)",
|
|
615
|
+
alignItems: "baseline",
|
|
616
|
+
gap: "0.65rem",
|
|
617
|
+
},
|
|
618
|
+
assertionLabel: {
|
|
619
|
+
color: "var(--subtle)",
|
|
620
|
+
fontSize: "0.65rem",
|
|
621
|
+
fontWeight: 750,
|
|
622
|
+
letterSpacing: "0.05em",
|
|
623
|
+
textTransform: "uppercase",
|
|
624
|
+
},
|
|
625
|
+
assertionCode: {
|
|
626
|
+
margin: 0,
|
|
627
|
+
whiteSpace: "pre-wrap",
|
|
628
|
+
wordBreak: "break-word",
|
|
629
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
|
|
630
|
+
fontSize: "0.75rem",
|
|
631
|
+
lineHeight: 1.5,
|
|
632
|
+
color: "var(--text)",
|
|
633
|
+
},
|
|
634
|
+
metricGrid: {
|
|
635
|
+
display: "grid",
|
|
636
|
+
gridTemplateColumns: "repeat(auto-fit, minmax(6rem, 1fr))",
|
|
637
|
+
gap: "0.4rem",
|
|
638
|
+
},
|
|
639
|
+
metric: {
|
|
640
|
+
display: "grid",
|
|
641
|
+
gap: "0.15rem",
|
|
642
|
+
padding: "0.5rem 0.6rem",
|
|
643
|
+
borderRadius: 8,
|
|
644
|
+
backgroundColor: "var(--bg)",
|
|
645
|
+
border: "1px solid var(--border)",
|
|
646
|
+
},
|
|
647
|
+
metricValue: { color: "var(--text)", fontSize: "0.77rem", fontWeight: 700 },
|
|
648
|
+
conversation: {
|
|
649
|
+
display: "grid",
|
|
650
|
+
gap: "0.55rem",
|
|
651
|
+
padding: "0.75rem",
|
|
652
|
+
border: "1px solid var(--border)",
|
|
653
|
+
borderRadius: 10,
|
|
654
|
+
backgroundColor: "var(--bg)",
|
|
655
|
+
},
|
|
656
|
+
conversationSwitcher: {
|
|
657
|
+
display: "flex",
|
|
658
|
+
alignItems: "center",
|
|
659
|
+
gap: "0.35rem",
|
|
660
|
+
padding: "0 0.15rem",
|
|
661
|
+
},
|
|
662
|
+
conversationHeader: {
|
|
663
|
+
display: "flex",
|
|
664
|
+
alignItems: "center",
|
|
665
|
+
justifyContent: "space-between",
|
|
666
|
+
gap: "0.75rem",
|
|
667
|
+
},
|
|
668
|
+
runTabs: { display: "inline-flex", alignItems: "center", gap: "0.12rem" },
|
|
669
|
+
runTab: {
|
|
670
|
+
padding: "0.12rem 0.3rem",
|
|
671
|
+
borderRadius: 4,
|
|
672
|
+
backgroundColor: { default: "transparent", ":hover": "var(--panel-3)" },
|
|
673
|
+
color: "var(--subtle)",
|
|
674
|
+
fontSize: "0.5rem",
|
|
675
|
+
fontWeight: 750,
|
|
676
|
+
letterSpacing: "0.04em",
|
|
677
|
+
textTransform: "uppercase",
|
|
678
|
+
cursor: "pointer",
|
|
679
|
+
},
|
|
680
|
+
runTabActive: { backgroundColor: "var(--accent-soft)", color: "var(--accent)" },
|
|
681
|
+
conversationTabs: { display: "flex", flexWrap: "wrap", gap: "0.25rem" },
|
|
682
|
+
conversationTab: {
|
|
683
|
+
display: "inline-flex",
|
|
684
|
+
alignItems: "center",
|
|
685
|
+
gap: "0.2rem",
|
|
686
|
+
boxSizing: "border-box",
|
|
687
|
+
height: "1.1rem",
|
|
688
|
+
minHeight: 0,
|
|
689
|
+
lineHeight: 1,
|
|
690
|
+
padding: "0.08rem 0.32rem",
|
|
691
|
+
fontSize: "0.5rem",
|
|
692
|
+
fontWeight: 750,
|
|
693
|
+
letterSpacing: "0.04em",
|
|
694
|
+
textTransform: "uppercase",
|
|
695
|
+
borderColor: "var(--border)",
|
|
696
|
+
backgroundColor: { default: "transparent", ":hover": "var(--panel-3)" },
|
|
697
|
+
color: "var(--muted)",
|
|
698
|
+
cursor: "pointer",
|
|
699
|
+
},
|
|
700
|
+
conversationTabActive: {
|
|
701
|
+
borderColor: "var(--pass)",
|
|
702
|
+
backgroundColor: "var(--pass-soft)",
|
|
703
|
+
color: "var(--pass)",
|
|
704
|
+
},
|
|
705
|
+
conversationTabDot: {
|
|
706
|
+
width: "0.28rem",
|
|
707
|
+
height: "0.28rem",
|
|
708
|
+
borderRadius: 999,
|
|
709
|
+
backgroundColor: "var(--skip)",
|
|
710
|
+
animationName: runningPulse,
|
|
711
|
+
animationDuration: {
|
|
712
|
+
default: "1.2s",
|
|
713
|
+
"@media (prefers-reduced-motion: reduce)": "0.01ms",
|
|
714
|
+
},
|
|
715
|
+
animationIterationCount: {
|
|
716
|
+
default: "infinite",
|
|
717
|
+
"@media (prefers-reduced-motion: reduce)": 1,
|
|
718
|
+
},
|
|
719
|
+
animationTimingFunction: "ease-in-out",
|
|
720
|
+
},
|
|
721
|
+
conversationThread: { display: "grid", gap: "0.55rem" },
|
|
722
|
+
runningIndicator: {
|
|
723
|
+
display: "inline-flex",
|
|
724
|
+
alignItems: "baseline",
|
|
725
|
+
justifySelf: "start",
|
|
726
|
+
gap: "0.35rem",
|
|
727
|
+
padding: "0.48rem 0.65rem",
|
|
728
|
+
border: "1px solid var(--border)",
|
|
729
|
+
borderRadius: 999,
|
|
730
|
+
backgroundColor: "var(--panel-2)",
|
|
731
|
+
color: "var(--muted)",
|
|
732
|
+
fontSize: "0.74rem",
|
|
733
|
+
fontWeight: 650,
|
|
734
|
+
},
|
|
735
|
+
runningDots: { display: "inline-flex", gap: "0.15rem", color: "var(--accent)" },
|
|
736
|
+
runningDot: {
|
|
737
|
+
animationName: runningPulse,
|
|
738
|
+
animationDuration: {
|
|
739
|
+
default: "1.2s",
|
|
740
|
+
"@media (prefers-reduced-motion: reduce)": "0.01ms",
|
|
741
|
+
},
|
|
742
|
+
animationIterationCount: {
|
|
743
|
+
default: "infinite",
|
|
744
|
+
"@media (prefers-reduced-motion: reduce)": 1,
|
|
745
|
+
},
|
|
746
|
+
animationTimingFunction: "ease-in-out",
|
|
747
|
+
},
|
|
748
|
+
runningDotSecond: { animationDelay: "0.16s" },
|
|
749
|
+
runningDotThird: { animationDelay: "0.32s" },
|
|
750
|
+
message: {
|
|
751
|
+
display: "grid",
|
|
752
|
+
gap: "0.28rem",
|
|
753
|
+
padding: "0.65rem 0.75rem",
|
|
754
|
+
borderRadius: 10,
|
|
755
|
+
border: "1px solid var(--border)",
|
|
756
|
+
backgroundColor: "var(--panel-2)",
|
|
757
|
+
maxWidth: "78%",
|
|
758
|
+
},
|
|
759
|
+
messageUser: {
|
|
760
|
+
justifySelf: "end",
|
|
761
|
+
backgroundColor: "var(--accent-soft)",
|
|
762
|
+
borderColor: "oklch(0.75 0.12 175 / 0.3)",
|
|
763
|
+
},
|
|
764
|
+
messageAssistant: { justifySelf: "start", backgroundColor: "var(--panel-2)" },
|
|
765
|
+
messageJudge: {
|
|
766
|
+
justifySelf: "start",
|
|
767
|
+
backgroundColor: "var(--accent-soft)",
|
|
768
|
+
borderColor: "oklch(0.75 0.12 175 / 0.3)",
|
|
769
|
+
},
|
|
770
|
+
messageRole: {
|
|
771
|
+
color: "var(--subtle)",
|
|
772
|
+
fontSize: "0.61rem",
|
|
773
|
+
fontWeight: 750,
|
|
774
|
+
letterSpacing: "0.06em",
|
|
775
|
+
textTransform: "uppercase",
|
|
776
|
+
},
|
|
777
|
+
messageContent: { margin: 0, color: "var(--text)", fontSize: "0.79rem", lineHeight: 1.5 },
|
|
778
|
+
judgeResponse: {
|
|
779
|
+
display: "grid",
|
|
780
|
+
justifySelf: "start",
|
|
781
|
+
gap: "0.4rem",
|
|
782
|
+
padding: "0.65rem 0.7rem",
|
|
783
|
+
border: "1px solid var(--border)",
|
|
784
|
+
borderRadius: 10,
|
|
785
|
+
backgroundColor: "var(--panel-2)",
|
|
786
|
+
maxWidth: "78%",
|
|
787
|
+
},
|
|
788
|
+
judgeResponseHeading: {
|
|
789
|
+
margin: 0,
|
|
790
|
+
color: "var(--subtle)",
|
|
791
|
+
fontSize: "0.61rem",
|
|
792
|
+
fontWeight: 750,
|
|
793
|
+
letterSpacing: "0.06em",
|
|
794
|
+
textTransform: "uppercase",
|
|
795
|
+
},
|
|
796
|
+
judgeOutcomeList: { display: "grid", gap: "0.25rem" },
|
|
797
|
+
judgeOutcome: {
|
|
798
|
+
display: "grid",
|
|
799
|
+
gridTemplateColumns: "0.9rem minmax(0, 1fr)",
|
|
800
|
+
gap: "0.15rem 0.6rem",
|
|
801
|
+
},
|
|
802
|
+
judgeOutcomeLabel: { color: "var(--text)", fontSize: "0.75rem", lineHeight: 1.35 },
|
|
803
|
+
judgeOutcomeExplanation: {
|
|
804
|
+
gridColumn: 2,
|
|
805
|
+
margin: 0,
|
|
806
|
+
color: "var(--muted)",
|
|
807
|
+
fontSize: "0.75rem",
|
|
808
|
+
lineHeight: 1.5,
|
|
809
|
+
},
|
|
810
|
+
toolEvent: {
|
|
811
|
+
display: "grid",
|
|
812
|
+
gridTemplateColumns: "1.5rem minmax(0, 1fr) max-content",
|
|
813
|
+
alignItems: "center",
|
|
814
|
+
gap: "0.55rem",
|
|
815
|
+
width: "min(86%, 46rem)",
|
|
816
|
+
padding: "0.5rem 0.65rem",
|
|
817
|
+
borderRadius: 8,
|
|
818
|
+
border: "1px solid var(--border)",
|
|
819
|
+
backgroundColor: "var(--panel)",
|
|
820
|
+
},
|
|
821
|
+
toolIcon: {
|
|
822
|
+
width: "1.5rem",
|
|
823
|
+
height: "1.5rem",
|
|
824
|
+
display: "grid",
|
|
825
|
+
placeItems: "center",
|
|
826
|
+
borderRadius: 6,
|
|
827
|
+
backgroundColor: "var(--panel-3)",
|
|
828
|
+
color: "var(--accent)",
|
|
829
|
+
fontSize: "0.7rem",
|
|
830
|
+
},
|
|
831
|
+
toolCopy: { display: "grid", gap: "0.08rem", minWidth: 0 },
|
|
832
|
+
toolTitle: { color: "var(--text)", fontSize: "0.74rem", fontWeight: 680 },
|
|
833
|
+
toolDetail: {
|
|
834
|
+
color: "var(--muted)",
|
|
835
|
+
fontSize: "0.69rem",
|
|
836
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
|
|
837
|
+
overflow: "hidden",
|
|
838
|
+
textOverflow: "ellipsis",
|
|
839
|
+
whiteSpace: "nowrap",
|
|
840
|
+
},
|
|
841
|
+
toolOutcome: { color: "var(--pass)", fontSize: "0.64rem", fontWeight: 700 },
|
|
842
|
+
toolOutcomeFail: { color: "var(--fail)" },
|
|
843
|
+
toolActions: {
|
|
844
|
+
display: "flex",
|
|
845
|
+
alignItems: "center",
|
|
846
|
+
justifyContent: "flex-end",
|
|
847
|
+
gap: "0.45rem",
|
|
848
|
+
},
|
|
849
|
+
toolResultSummary: {
|
|
850
|
+
padding: "0.14rem 0.3rem",
|
|
851
|
+
borderRadius: 4,
|
|
852
|
+
backgroundColor: { default: "transparent", ":hover": "var(--accent-soft)" },
|
|
853
|
+
color: { default: "var(--accent)", ":hover": "var(--accent)" },
|
|
854
|
+
cursor: "pointer",
|
|
855
|
+
fontSize: "0.66rem",
|
|
856
|
+
fontWeight: 700,
|
|
857
|
+
whiteSpace: "nowrap",
|
|
858
|
+
},
|
|
859
|
+
toolResultPre: {
|
|
860
|
+
gridColumn: "2 / -1",
|
|
861
|
+
margin: 0,
|
|
862
|
+
paddingTop: "0.4rem",
|
|
863
|
+
borderTop: "1px solid var(--border)",
|
|
864
|
+
maxHeight: "12rem",
|
|
865
|
+
overflow: "auto",
|
|
866
|
+
whiteSpace: "pre-wrap",
|
|
867
|
+
wordBreak: "break-word",
|
|
868
|
+
fontSize: "0.66rem",
|
|
869
|
+
lineHeight: 1.45,
|
|
870
|
+
color: "var(--muted)",
|
|
871
|
+
},
|
|
872
|
+
criteriaPanel: {
|
|
873
|
+
display: "grid",
|
|
874
|
+
gap: "0.55rem",
|
|
875
|
+
padding: "0.75rem 0.9rem",
|
|
876
|
+
borderBottom: "1px solid var(--border)",
|
|
877
|
+
},
|
|
878
|
+
criteriaList: { display: "grid", gap: "0.55rem", margin: 0, padding: 0, listStyle: "none" },
|
|
879
|
+
criterion: { display: "flex", gap: "0.6rem", color: "var(--muted)", fontSize: "0.82rem" },
|
|
880
|
+
criterionIcon: { color: "var(--accent)", fontWeight: 800 },
|
|
881
|
+
passReasonList: { display: "grid", gap: "0.35rem", margin: 0, padding: 0, listStyle: "none" },
|
|
882
|
+
passReason: { display: "flex", gap: "0.5rem", color: "var(--text)", fontSize: "0.76rem" },
|
|
883
|
+
passReasonIcon: { color: "var(--pass)", fontWeight: 800 },
|
|
884
|
+
criterionResults: { display: "grid" },
|
|
885
|
+
criterionResultList: {
|
|
886
|
+
display: "grid",
|
|
887
|
+
gap: "0.55rem",
|
|
888
|
+
margin: 0,
|
|
889
|
+
padding: 0,
|
|
890
|
+
listStyle: "none",
|
|
891
|
+
},
|
|
892
|
+
criterionResult: {
|
|
893
|
+
display: "grid",
|
|
894
|
+
gap: "0.45rem",
|
|
895
|
+
},
|
|
896
|
+
criterionResultHeader: {
|
|
897
|
+
display: "flex",
|
|
898
|
+
alignItems: "flex-start",
|
|
899
|
+
gap: "0.6rem",
|
|
900
|
+
color: "var(--muted)",
|
|
901
|
+
fontSize: "0.82rem",
|
|
902
|
+
},
|
|
903
|
+
criterionExplanation: {
|
|
904
|
+
margin: "0 0 0 1.5rem",
|
|
905
|
+
color: "var(--subtle)",
|
|
906
|
+
fontSize: "0.75rem",
|
|
907
|
+
lineHeight: 1.45,
|
|
908
|
+
},
|
|
909
|
+
criterionOutcome: {
|
|
910
|
+
display: "inline-flex",
|
|
911
|
+
justifyContent: "center",
|
|
912
|
+
width: "0.9rem",
|
|
913
|
+
flex: "0 0 0.9rem",
|
|
914
|
+
fontSize: "0.8rem",
|
|
915
|
+
fontWeight: 800,
|
|
916
|
+
lineHeight: 1.25,
|
|
917
|
+
},
|
|
918
|
+
criterionOutcomePass: { color: "var(--pass)" },
|
|
919
|
+
criterionOutcomeFail: { color: "var(--fail)" },
|
|
920
|
+
criterionOutcomePending: { color: "var(--skip)" },
|
|
921
|
+
criterionOutcomeUnknown: { color: "var(--subtle)" },
|
|
922
|
+
status: {
|
|
923
|
+
fontSize: "0.68rem",
|
|
924
|
+
fontWeight: 750,
|
|
925
|
+
letterSpacing: "0.06em",
|
|
926
|
+
textTransform: "uppercase",
|
|
927
|
+
padding: "0.2rem 0.55rem",
|
|
928
|
+
borderRadius: 999,
|
|
929
|
+
border: "1px solid var(--border)",
|
|
930
|
+
color: "var(--muted)",
|
|
931
|
+
},
|
|
932
|
+
statusPass: {
|
|
933
|
+
color: "var(--pass)",
|
|
934
|
+
borderColor: "var(--pass)",
|
|
935
|
+
backgroundColor: "var(--pass-soft)",
|
|
936
|
+
},
|
|
937
|
+
statusFail: {
|
|
938
|
+
color: "var(--fail)",
|
|
939
|
+
borderColor: "var(--fail)",
|
|
940
|
+
backgroundColor: "var(--fail-soft)",
|
|
941
|
+
},
|
|
942
|
+
statusRunning: {
|
|
943
|
+
color: "var(--skip)",
|
|
944
|
+
borderColor: "var(--skip)",
|
|
945
|
+
backgroundColor: "var(--skip-soft)",
|
|
946
|
+
},
|
|
947
|
+
error: {
|
|
948
|
+
margin: 0,
|
|
949
|
+
padding: "0.85rem 1rem",
|
|
950
|
+
border: "1px solid oklch(0.73 0.18 25 / 0.36)",
|
|
951
|
+
borderRadius: 9,
|
|
952
|
+
backgroundColor: "var(--fail-soft)",
|
|
953
|
+
color: "oklch(0.88 0.08 25)",
|
|
954
|
+
},
|
|
955
|
+
evidence: { borderTop: "1px solid var(--border)", paddingTop: "0.7rem" },
|
|
956
|
+
evidenceSummary: {
|
|
957
|
+
display: "flex",
|
|
958
|
+
alignItems: "center",
|
|
959
|
+
gap: "0.5rem",
|
|
960
|
+
cursor: "pointer",
|
|
961
|
+
color: "var(--muted)",
|
|
962
|
+
fontSize: "0.82rem",
|
|
963
|
+
fontWeight: 650,
|
|
964
|
+
padding: "0.2rem 0",
|
|
965
|
+
},
|
|
966
|
+
pre: {
|
|
967
|
+
margin: "0.7rem 0 0",
|
|
968
|
+
overflow: "auto",
|
|
969
|
+
whiteSpace: "pre-wrap",
|
|
970
|
+
wordBreak: "break-word",
|
|
971
|
+
fontSize: "0.76rem",
|
|
972
|
+
lineHeight: 1.55,
|
|
973
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
|
|
974
|
+
color: "oklch(0.86 0.02 255)",
|
|
975
|
+
backgroundColor: "var(--bg)",
|
|
976
|
+
border: "1px solid var(--border)",
|
|
977
|
+
borderRadius: 9,
|
|
978
|
+
padding: "0.85rem",
|
|
979
|
+
},
|
|
980
|
+
empty: { color: "var(--muted)", fontStyle: "italic", padding: "1rem 0" },
|
|
981
|
+
});
|
|
982
|
+
function ViewerLayout() {
|
|
983
|
+
const [sidebarOpen, setSidebarOpen] = useState(true);
|
|
984
|
+
const [workers, setWorkers] = useState(1);
|
|
985
|
+
return (_jsx(WorkerContext.Provider, { value: { workers, setWorkers }, children: _jsxs("div", { ...stylex.props(styles.shell, !sidebarOpen && styles.shellCollapsed), children: [_jsx("a", { href: "#viewer-main", ...stylex.props(styles.skipLink), children: "Skip to content" }), _jsx(ViewerSidebar, { open: sidebarOpen, onToggle: () => setSidebarOpen((open) => !open) }), _jsx("main", { id: "viewer-main", tabIndex: -1, ...stylex.props(styles.main), children: _jsx(Outlet, {}) })] }) }));
|
|
986
|
+
}
|
|
987
|
+
function useCatalog() {
|
|
988
|
+
return useQuery({ queryKey: ["test-catalog"], queryFn: fetchTestCatalog });
|
|
989
|
+
}
|
|
990
|
+
function ViewerSidebar({ open, onToggle }) {
|
|
991
|
+
const catalog = useCatalog();
|
|
992
|
+
const history = useExecutionHistory();
|
|
993
|
+
const groups = groupTests(catalog.data?.tests ?? []);
|
|
994
|
+
const statuses = latestTestStatuses(history.data ?? []);
|
|
995
|
+
return (_jsxs("aside", { ...stylex.props(styles.sidebar, !open && styles.sidebarCollapsed), children: [_jsx(SidebarHeader, { open: open, count: catalog.data?.tests.length ?? 0, onToggle: onToggle }), open ? (_jsx(SidebarNavigation, { groups: groups, statuses: statuses, error: catalog.isError })) : null] }));
|
|
996
|
+
}
|
|
997
|
+
function SidebarHeader({ open, count, onToggle, }) {
|
|
998
|
+
const { workers } = useContext(WorkerContext);
|
|
999
|
+
const navigate = useNavigate();
|
|
1000
|
+
const client = useQueryClient();
|
|
1001
|
+
const run = useMutation({
|
|
1002
|
+
mutationFn: () => startSuite(workers),
|
|
1003
|
+
onSuccess: ({ executionId }) => {
|
|
1004
|
+
void client.invalidateQueries({ queryKey: ["execution-history"] });
|
|
1005
|
+
void navigate({ to: "/executions/$executionId", params: { executionId } });
|
|
1006
|
+
},
|
|
1007
|
+
});
|
|
1008
|
+
return (_jsx("header", { ...stylex.props(styles.sidebarHeader, !open && styles.sidebarHeaderCollapsed), children: open ? (_jsxs(_Fragment, { children: [_jsxs("div", { ...stylex.props(styles.sidebarTitleRow), children: [_jsxs("div", { ...stylex.props(styles.sidebarTitleIdentity), children: [_jsx("h1", { ...stylex.props(styles.title, styles.sidebarTitle), children: "Tests" }), _jsx("span", { ...stylex.props(styles.countBadge), children: count })] }), _jsx(SidebarToggle, { open: open, onToggle: onToggle })] }), _jsxs("div", { ...stylex.props(styles.suiteControls), children: [_jsxs("button", { type: "button", ...stylex.props(styles.buttonReset, styles.suiteRunButton), onClick: () => run.mutate(), disabled: run.isPending || count === 0, children: [_jsx("span", { "aria-hidden": "true", children: run.isPending ? "●" : "▶" }), run.isPending ? "Starting suite…" : "Run all tests"] }), _jsx(WorkerControl, {})] }), run.isError ? _jsx("p", { role: "alert", children: run.error.message }) : null] })) : (_jsx(SidebarToggle, { open: open, onToggle: onToggle })) }));
|
|
1009
|
+
}
|
|
1010
|
+
function WorkerControl() {
|
|
1011
|
+
const { workers, setWorkers } = useContext(WorkerContext);
|
|
1012
|
+
return (_jsxs("label", { ...stylex.props(styles.workerControl), children: [_jsx("span", { children: "Workers" }), _jsx("input", { type: "number", "aria-label": "Concurrent workers", min: 1, max: 32, value: workers, ...stylex.props(styles.workerInput), onChange: (event) => {
|
|
1013
|
+
const next = Number(event.currentTarget.value);
|
|
1014
|
+
if (Number.isInteger(next))
|
|
1015
|
+
setWorkers(Math.min(32, Math.max(1, next)));
|
|
1016
|
+
} })] }));
|
|
1017
|
+
}
|
|
1018
|
+
function SidebarToggle({ open, onToggle }) {
|
|
1019
|
+
return (_jsx("button", { type: "button", "aria-controls": "test-navigation", "aria-expanded": open, "aria-label": open ? "Collapse test sidebar" : "Expand test sidebar", ...stylex.props(styles.buttonReset, styles.toggleButton), onClick: onToggle, children: open ? "←" : "→" }));
|
|
1020
|
+
}
|
|
1021
|
+
function SidebarNavigation({ groups, statuses, error, }) {
|
|
1022
|
+
return (_jsxs(_Fragment, { children: [error ? _jsx("p", { role: "alert", children: "Test discovery is unavailable." }) : null, _jsx("nav", { id: "test-navigation", "aria-label": "Tests", ...stylex.props(styles.navigation), children: [...groups].map(([name, tests]) => (_jsxs("section", { "aria-label": `${name} tests`, ...stylex.props(styles.navSection), children: [_jsxs("div", { ...stylex.props(styles.groupHeader), children: [_jsx("strong", { ...stylex.props(styles.groupLabel), children: name }), _jsxs("div", { ...stylex.props(styles.groupHeaderActions), children: [_jsx("span", { ...stylex.props(styles.groupCount), children: tests.length }), _jsx(RunTestGroupButton, { name: name, tests: tests })] })] }), tests.map((test) => (_jsx(TestLink, { test: test, status: statuses.get(test.id) }, test.id)))] }, name))) })] }));
|
|
1023
|
+
}
|
|
1024
|
+
function RunTestGroupButton({ name, tests }) {
|
|
1025
|
+
const { workers } = useContext(WorkerContext);
|
|
1026
|
+
const navigate = useNavigate();
|
|
1027
|
+
const client = useQueryClient();
|
|
1028
|
+
const run = useMutation({
|
|
1029
|
+
mutationFn: () => startTestGroup(tests.map((test) => test.id), workers),
|
|
1030
|
+
onSuccess: ({ executionId }) => {
|
|
1031
|
+
void client.invalidateQueries({ queryKey: ["execution-history"] });
|
|
1032
|
+
void navigate({ to: "/executions/$executionId", params: { executionId } });
|
|
1033
|
+
},
|
|
1034
|
+
});
|
|
1035
|
+
return (_jsx("button", { type: "button", "aria-label": `Run ${name} suite`, title: `Run ${name} suite`, ...stylex.props(styles.buttonReset, styles.groupRunButton), onClick: () => run.mutate(), disabled: run.isPending, children: run.isPending ? "●" : "▶" }));
|
|
1036
|
+
}
|
|
1037
|
+
function TestLink({ test, status }) {
|
|
1038
|
+
return (_jsxs(Link, { to: "/tests/$testId", params: { testId: test.id }, search: {}, ...stylex.props(styles.navLink), activeProps: stylex.props(styles.navLink, styles.active), children: [_jsxs("div", { ...stylex.props(styles.navItemHeader), children: [status ? _jsx(TestStatus, { status: status }) : _jsx("span", { "aria-hidden": "true" }), _jsx("span", { ...stylex.props(styles.navItemTitle), children: test.title.at(-1) })] }), test.project !== "default" ? _jsx("div", { ...stylex.props(styles.meta), children: test.project }) : null] }));
|
|
1039
|
+
}
|
|
1040
|
+
function TestStatus({ status }) {
|
|
1041
|
+
return (_jsx("span", { role: "img", "aria-label": `Latest execution: ${status}`, title: `Latest execution: ${status}`, ...stylex.props(styles.navStatus), children: _jsx("span", { "aria-hidden": "true", ...stylex.props(styles.navStatusDot, status === "passed" && styles.navStatusDotPass, status === "failed" && styles.navStatusDotFail, status === "running" && styles.navStatusDotRunning) }) }));
|
|
1042
|
+
}
|
|
1043
|
+
function TestCatalogPage() {
|
|
1044
|
+
return (_jsxs("section", { ...stylex.props(styles.hero), children: [_jsx("div", { ...stylex.props(styles.brand), children: "Test explorer" }), _jsx("h2", { ...stylex.props(styles.title), children: "Choose a test from the sidebar" }), _jsx("p", { ...stylex.props(styles.description), children: "Read what it checks, see its agents and judges, then start a run or inspect a saved execution." })] }));
|
|
1045
|
+
}
|
|
1046
|
+
function TestPage() {
|
|
1047
|
+
const { testId } = testRoute.useParams();
|
|
1048
|
+
const catalog = useCatalog();
|
|
1049
|
+
if (catalog.isPending)
|
|
1050
|
+
return _jsx("p", { children: "Loading test\u2026" });
|
|
1051
|
+
const test = catalog.data?.tests.find((item) => item.id === testId);
|
|
1052
|
+
if (!test)
|
|
1053
|
+
return (_jsx("p", { role: "alert", children: "This test is no longer available. Choose another test in the sidebar." }));
|
|
1054
|
+
return _jsx(TestDetail, { test: test }, test.id);
|
|
1055
|
+
}
|
|
1056
|
+
function TestDetail({ test }) {
|
|
1057
|
+
const { execution, view } = testRoute.useSearch();
|
|
1058
|
+
const history = useExecutionHistory();
|
|
1059
|
+
const navigate = useNavigate();
|
|
1060
|
+
const runs = history.data?.filter((item) => item.testIds?.includes(test.id)) ?? [];
|
|
1061
|
+
const selected = execution ?? runs[0]?.id;
|
|
1062
|
+
const activeView = view ?? "current";
|
|
1063
|
+
const chooseExecution = (id) => void navigate({
|
|
1064
|
+
to: "/tests/$testId",
|
|
1065
|
+
params: { testId: test.id },
|
|
1066
|
+
search: { execution: id },
|
|
1067
|
+
});
|
|
1068
|
+
const chooseView = (next) => void navigate({
|
|
1069
|
+
to: "/tests/$testId",
|
|
1070
|
+
params: { testId: test.id },
|
|
1071
|
+
search: { execution, view: next === "current" ? undefined : next },
|
|
1072
|
+
});
|
|
1073
|
+
return (_jsxs(_Fragment, { children: [_jsx(TestHeader, { test: test, onStarted: chooseExecution }), _jsx(TestTabs, { active: activeView, onChange: chooseView }), _jsx(TestViewPanel, { view: activeView, test: test, runs: runs, selected: selected, onChooseExecution: chooseExecution })] }));
|
|
1074
|
+
}
|
|
1075
|
+
function TestHeader({ test, onStarted }) {
|
|
1076
|
+
return (_jsxs("header", { ...stylex.props(styles.hero), children: [_jsxs("div", { ...stylex.props(styles.heroTop), children: [_jsxs("div", { ...stylex.props(styles.heroCopy), children: [_jsx("div", { ...stylex.props(styles.brand), children: test.title.slice(0, -1).join(" / ") }), _jsx("h2", { ...stylex.props(styles.title), children: test.title.at(-1) }), _jsx("p", { ...stylex.props(styles.description), children: test.description ?? "This test has no additional description." })] }), _jsx(RunTestButton, { test: test, onStarted: onStarted })] }), _jsxs("div", { ...stylex.props(styles.path), children: [test.project, " \u00B7 ", test.file] })] }));
|
|
1077
|
+
}
|
|
1078
|
+
const TEST_VIEWS = [
|
|
1079
|
+
{ id: "current", label: "Current run" },
|
|
1080
|
+
{ id: "setup", label: "Test setup" },
|
|
1081
|
+
{ id: "history", label: "Run history" },
|
|
1082
|
+
];
|
|
1083
|
+
function TestTabs({ active, onChange }) {
|
|
1084
|
+
return (_jsx("div", { role: "tablist", "aria-label": "Test views", ...stylex.props(styles.tabList), children: TEST_VIEWS.map((view) => (_jsx("button", { id: `test-tab-${view.id}`, type: "button", role: "tab", "aria-controls": `test-panel-${view.id}`, "aria-selected": active === view.id, tabIndex: active === view.id ? 0 : -1, ...stylex.props(styles.buttonReset, styles.tab, active === view.id && styles.tabActive), onClick: () => onChange(view.id), onKeyDown: (event) => handleTabKeyDown(event, view.id, onChange), children: view.label }, view.id))) }));
|
|
1085
|
+
}
|
|
1086
|
+
function handleTabKeyDown(event, active, onChange) {
|
|
1087
|
+
if (!["ArrowLeft", "ArrowRight", "Home", "End"].includes(event.key))
|
|
1088
|
+
return;
|
|
1089
|
+
event.preventDefault();
|
|
1090
|
+
const index = TEST_VIEWS.findIndex((view) => view.id === active);
|
|
1091
|
+
const nextIndex = event.key === "Home"
|
|
1092
|
+
? 0
|
|
1093
|
+
: event.key === "End"
|
|
1094
|
+
? TEST_VIEWS.length - 1
|
|
1095
|
+
: (index + (event.key === "ArrowRight" ? 1 : -1) + TEST_VIEWS.length) % TEST_VIEWS.length;
|
|
1096
|
+
const next = TEST_VIEWS[nextIndex];
|
|
1097
|
+
if (!next)
|
|
1098
|
+
return;
|
|
1099
|
+
onChange(next.id);
|
|
1100
|
+
document.getElementById(`test-tab-${next.id}`)?.focus();
|
|
1101
|
+
}
|
|
1102
|
+
function TestViewPanel(props) {
|
|
1103
|
+
return (_jsxs("div", { id: `test-panel-${props.view}`, role: "tabpanel", "aria-labelledby": `test-tab-${props.view}`, ...stylex.props(styles.tabPanel), children: [props.view === "setup" ? _jsx(TestResources, { test: props.test }) : null, props.view === "current" ? (_jsx(CurrentRun, { test: props.test, executionId: props.selected })) : null, props.view === "history" ? (_jsx(RunHistory, { runs: props.runs, onChoose: props.onChooseExecution })) : null] }));
|
|
1104
|
+
}
|
|
1105
|
+
function CurrentRun({ test, executionId }) {
|
|
1106
|
+
return (_jsx("section", { ...stylex.props(styles.tabSection), children: executionId ? (_jsx(TestExecution, { id: executionId, test: test })) : (_jsx("p", { ...stylex.props(styles.empty), children: "No runs yet. Start this test to see its progress here." })) }));
|
|
1107
|
+
}
|
|
1108
|
+
function RunHistory({ runs, onChoose, }) {
|
|
1109
|
+
return (_jsxs("section", { ...stylex.props(styles.tabSection), children: [_jsx("div", { ...stylex.props(styles.quietHeader), children: _jsxs("span", { ...stylex.props(styles.resourceCount), children: [runs.length, " executions"] }) }), runs.length ? (_jsx("div", { ...stylex.props(styles.historyList), children: runs.map((run) => (_jsx(HistoryItem, { run: run, onChoose: onChoose }, run.id))) })) : (_jsx("p", { ...stylex.props(styles.empty), children: "No saved runs for this test." }))] }));
|
|
1110
|
+
}
|
|
1111
|
+
function HistoryItem({ run, onChoose }) {
|
|
1112
|
+
return (_jsxs("button", { type: "button", "aria-label": `Open ${run.status} execution ${run.id.slice(0, 8)}`, ...stylex.props(styles.buttonReset, styles.historyButton), onClick: () => onChoose(run.id), children: [_jsxs("span", { ...stylex.props(styles.historyIdentity), children: [_jsx("span", { ...stylex.props(styles.historyDate), children: new Date(run.startedAt).toLocaleString() }), _jsx("span", { ...stylex.props(styles.historyId), children: run.id.slice(0, 8) })] }), _jsx("span", { ...stylex.props(styles.status, run.status === "passed" && styles.statusPass, run.status === "failed" && styles.statusFail, run.status === "running" && styles.statusRunning), children: run.status })] }));
|
|
1113
|
+
}
|
|
1114
|
+
function RunTestButton({ test, onStarted }) {
|
|
1115
|
+
const { workers } = useContext(WorkerContext);
|
|
1116
|
+
const client = useQueryClient();
|
|
1117
|
+
const run = useMutation({
|
|
1118
|
+
mutationFn: () => startTest(test.id, workers),
|
|
1119
|
+
onSuccess: ({ executionId }) => {
|
|
1120
|
+
onStarted(executionId);
|
|
1121
|
+
void client.invalidateQueries({ queryKey: ["execution-history"] });
|
|
1122
|
+
},
|
|
1123
|
+
});
|
|
1124
|
+
return (_jsxs("div", { ...stylex.props(styles.heroAction), children: [_jsxs("button", { type: "button", ...stylex.props(styles.buttonReset, styles.button), onClick: () => run.mutate(), disabled: run.isPending, children: [_jsx("span", { "aria-hidden": "true", ...stylex.props(styles.buttonIcon), children: run.isPending ? "●" : "▶" }), run.isPending ? "Starting…" : "Run this test"] }), run.isError ? _jsx("p", { role: "alert", children: run.error.message }) : null] }));
|
|
1125
|
+
}
|
|
1126
|
+
function TestResources({ test }) {
|
|
1127
|
+
const resources = test.resources ?? [];
|
|
1128
|
+
const agents = resources.filter((resource) => resource.kind === "agent");
|
|
1129
|
+
const judges = resources.filter((resource) => resource.kind === "judge");
|
|
1130
|
+
return (_jsxs("section", { "aria-label": "Test setup details", ...stylex.props(styles.contextPanel), children: [_jsx(CriteriaSetup, { test: test }), _jsxs("div", { ...stylex.props(styles.setupBody), children: [_jsx(ResourceSection, { title: "Agents", description: "Task agents this test can start.", resources: agents }), _jsx(ResourceSection, { title: "Judges", description: "Reviewers that evaluate agent output.", resources: judges }), _jsx(WorkspaceSetup, { test: test })] })] }));
|
|
1131
|
+
}
|
|
1132
|
+
function CriteriaSetup({ test }) {
|
|
1133
|
+
const criteria = testCriteria(test);
|
|
1134
|
+
return (_jsxs("section", { "aria-labelledby": "setup-criteria", ...stylex.props(styles.criteriaPanel), children: [_jsx("h3", { id: "setup-criteria", ...stylex.props(styles.contentHeading), children: "Pass criteria" }), criteria.length ? (_jsx("ul", { ...stylex.props(styles.criteriaList), children: criteria.map((criterion) => (_jsxs("li", { ...stylex.props(styles.criterion), children: [_jsx("span", { "aria-hidden": "true", ...stylex.props(styles.criterionIcon), children: "\u2713" }), _jsx("span", { children: criterion })] }, criterion))) })) : (_jsx("p", { ...stylex.props(styles.meta), children: "No explicit pass criteria are declared." }))] }));
|
|
1135
|
+
}
|
|
1136
|
+
function ResourceSection({ title, description, resources, }) {
|
|
1137
|
+
const id = `setup-${title.toLowerCase()}`;
|
|
1138
|
+
const noun = title === "Agents" ? "agent" : "judge";
|
|
1139
|
+
return (_jsxs("section", { "aria-labelledby": id, ...stylex.props(styles.setupSection), children: [_jsxs("header", { ...stylex.props(styles.setupSectionHeader), children: [_jsxs("div", { ...stylex.props(styles.setupSectionCopy), children: [_jsx("h3", { id: id, ...stylex.props(styles.contentHeading), children: title }), _jsx("p", { ...stylex.props(styles.meta), children: description })] }), _jsxs("span", { ...stylex.props(styles.resourceCount), children: [resources.length, " ", pluralize(resources.length, noun)] })] }), resources.length ? (_jsx("div", { ...stylex.props(styles.resourceGrid), children: resources.map((resource) => (_jsx(ResourceCard, { resource: resource }, resource.name))) })) : (_jsx("p", { ...stylex.props(styles.meta), children: "None declared." }))] }));
|
|
1140
|
+
}
|
|
1141
|
+
function ResourceCard({ resource }) {
|
|
1142
|
+
return (_jsxs("article", { ...stylex.props(styles.card, styles.resourceCard), children: [_jsx("div", { ...stylex.props(styles.resourceHeader), children: _jsx("strong", { children: resource.name }) }), _jsx(ResourceContext, { resource: resource })] }));
|
|
1143
|
+
}
|
|
1144
|
+
function WorkspaceSetup({ test }) {
|
|
1145
|
+
return (_jsxs("section", { "aria-labelledby": "setup-workspace", ...stylex.props(styles.setupSection), children: [_jsxs("div", { ...stylex.props(styles.setupSectionCopy), children: [_jsx("h3", { id: "setup-workspace", ...stylex.props(styles.contentHeading), children: "Workspace" }), _jsx("p", { ...stylex.props(styles.meta), children: "Starting files and execution target for this test." })] }), _jsxs("div", { ...stylex.props(styles.workspaceRow), children: [_jsx(ResourceFact, { label: "Source folder", value: test.workspace ?? "Project directory" }), _jsx(ResourceFact, { label: "Project", value: test.project }), _jsx(ResourceFact, { label: "Test file", value: test.file })] })] }));
|
|
1146
|
+
}
|
|
1147
|
+
function testCriteria(test) {
|
|
1148
|
+
if (test.criteria?.length)
|
|
1149
|
+
return test.criteria;
|
|
1150
|
+
return test.description ? [test.description] : [];
|
|
1151
|
+
}
|
|
1152
|
+
function ResourceContext({ resource }) {
|
|
1153
|
+
return (_jsxs("div", { ...stylex.props(styles.resourceBody), children: [resource.description ? (_jsx("p", { ...stylex.props(styles.resourceDescription), children: resource.description })) : null, _jsxs("div", { ...stylex.props(styles.resourceFacts), children: [_jsx(ResourceFact, { label: "Host", value: resource.host ?? "Not configured" }), _jsx(ResourceFact, { label: "Model", value: resource.model ?? "Host default" }), resource.workspace ? _jsx(ResourceFact, { label: "Workspace", value: resource.workspace }) : null, resource.skills.length ? (_jsx(ResourceFact, { label: "Skills", value: resource.skills.join(", ") })) : null, resource.mcpServers.length ? (_jsx(ResourceFact, { label: "MCP", value: resource.mcpServers.join(", ") })) : null] }), resource.prompt ? (_jsxs("div", { ...stylex.props(styles.resourcePrompt), children: [_jsx("span", { ...stylex.props(styles.resourceFactLabel), children: "Prompt" }), _jsx("p", { ...stylex.props(styles.resourceFactValue), children: resource.prompt })] })) : null] }));
|
|
1154
|
+
}
|
|
1155
|
+
function ResourceFact({ label, value }) {
|
|
1156
|
+
return (_jsxs("div", { ...stylex.props(styles.resourceFact), children: [_jsx("span", { ...stylex.props(styles.resourceFactLabel), children: label }), _jsx("span", { ...stylex.props(styles.resourceFactValue), children: value })] }));
|
|
1157
|
+
}
|
|
1158
|
+
function TestExecution({ id, test }) {
|
|
1159
|
+
const detail = useQuery({
|
|
1160
|
+
queryKey: ["execution", id],
|
|
1161
|
+
queryFn: () => fetchExecution(id),
|
|
1162
|
+
});
|
|
1163
|
+
if (detail.isPending)
|
|
1164
|
+
return _jsx("p", { children: "Loading execution\u2026" });
|
|
1165
|
+
if (!detail.data)
|
|
1166
|
+
return _jsx("p", { role: "alert", children: "Execution is unavailable." });
|
|
1167
|
+
const attempts = detail.data.attempts.filter((attempt) => attempt.testId === test.id);
|
|
1168
|
+
if (detail.data.testIds && !detail.data.testIds.includes(test.id))
|
|
1169
|
+
return _jsx("p", { children: "This execution does not contain this test." });
|
|
1170
|
+
return (_jsx(ExecutionDetailView, { execution: { ...detail.data, attempts }, criteria: testCriteria(test) }));
|
|
1171
|
+
}
|
|
1172
|
+
function ExecutionPage() {
|
|
1173
|
+
const { executionId } = executionRoute.useParams();
|
|
1174
|
+
const detail = useQuery({
|
|
1175
|
+
queryKey: ["execution", executionId],
|
|
1176
|
+
queryFn: () => fetchExecution(executionId),
|
|
1177
|
+
});
|
|
1178
|
+
if (detail.isLoading)
|
|
1179
|
+
return _jsx("p", { ...stylex.props(styles.empty), children: "Loading execution\u2026" });
|
|
1180
|
+
if (detail.isError || !detail.data)
|
|
1181
|
+
return _jsx("p", { ...stylex.props(styles.empty), children: "Execution is unavailable." });
|
|
1182
|
+
return _jsx(ExecutionDetailView, { execution: detail.data });
|
|
1183
|
+
}
|
|
1184
|
+
function ExecutionDetailView({ execution, criteria = [], }) {
|
|
1185
|
+
const client = useQueryClient();
|
|
1186
|
+
const cancel = useMutation({
|
|
1187
|
+
mutationFn: () => cancelExecution(execution.id),
|
|
1188
|
+
onSuccess: () => client.invalidateQueries({ queryKey: ["execution", execution.id] }),
|
|
1189
|
+
});
|
|
1190
|
+
const stopping = execution.status === "running" && (cancel.isPending || cancel.isSuccess);
|
|
1191
|
+
const stopLabel = (execution.testIds?.length ?? 0) > 1 ? "Stop suite run" : "Stop this run";
|
|
1192
|
+
return (_jsxs("div", { ...stylex.props(styles.statusPanel), children: [execution.status === "running" ? (_jsx("div", { ...stylex.props(styles.runControls), children: _jsx("button", { type: "button", ...stylex.props(styles.buttonReset, styles.button, styles.secondaryButton), onClick: () => cancel.mutate(), disabled: stopping, children: stopping ? "Stopping…" : stopLabel }) })) : null, cancel.isError ? _jsx("p", { role: "alert", children: "The run could not be stopped." }) : null, _jsxs("section", { ...stylex.props(styles.list), children: [execution.attempts.map((attempt) => (_jsx(AttemptCard, { attempt: attempt, criteria: criteria }, attempt.id))), execution.attempts.length === 0 ? (_jsx("p", { ...stylex.props(styles.empty), children: emptyExecutionMessage(execution, stopping) })) : null] })] }));
|
|
1193
|
+
}
|
|
1194
|
+
function emptyExecutionMessage(execution, stopping) {
|
|
1195
|
+
if (stopping)
|
|
1196
|
+
return "Stopping this run…";
|
|
1197
|
+
if (execution.status === "interrupted")
|
|
1198
|
+
return "Run stopped before the first test started.";
|
|
1199
|
+
if (execution.status === "failed")
|
|
1200
|
+
return "Run failed before the first test started.";
|
|
1201
|
+
if (execution.status === "passed")
|
|
1202
|
+
return "Run completed without starting a test.";
|
|
1203
|
+
const count = execution.testIds?.length ?? 0;
|
|
1204
|
+
return count ? `Starting ${count} ${pluralize(count, "test")}…` : "Starting the test run…";
|
|
1205
|
+
}
|
|
1206
|
+
function ComparePage() {
|
|
1207
|
+
const { left, right } = compareRoute.useParams();
|
|
1208
|
+
const [first, second] = useQueries({
|
|
1209
|
+
queries: [left, right].map((id) => ({
|
|
1210
|
+
queryKey: ["execution", id],
|
|
1211
|
+
queryFn: () => fetchExecution(id),
|
|
1212
|
+
})),
|
|
1213
|
+
});
|
|
1214
|
+
if (first.isLoading || second.isLoading)
|
|
1215
|
+
return _jsx("p", { ...stylex.props(styles.empty), children: "Loading saved runs\u2026" });
|
|
1216
|
+
if (!first.data || !second.data)
|
|
1217
|
+
return _jsx("p", { ...stylex.props(styles.empty), children: "A selected execution is unavailable." });
|
|
1218
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", { ...stylex.props(styles.brand), children: "Saved run comparison" }), _jsx("h2", { ...stylex.props(styles.title), children: "Two execution records" }), _jsxs("section", { ...stylex.props(styles.section), children: [_jsx(ComparisonColumn, { label: "First", execution: first.data }), _jsx(ComparisonColumn, { label: "Second", execution: second.data })] })] }));
|
|
1219
|
+
}
|
|
1220
|
+
function ComparisonColumn({ execution, label }) {
|
|
1221
|
+
return (_jsxs("article", { ...stylex.props(styles.card), children: [_jsxs("strong", { children: [label, ": ", execution.status] }), _jsx("p", { ...stylex.props(styles.meta), children: execution.id.slice(0, 8) }), execution.attempts.map((attempt) => (_jsx(AttemptCard, { attempt: attempt }, attempt.id)))] }));
|
|
1222
|
+
}
|
|
1223
|
+
function AttemptCard({ attempt, criteria = [] }) {
|
|
1224
|
+
const output = [...attempt.output.stdout, ...attempt.output.stderr].join("\n");
|
|
1225
|
+
const result = operationResult(attempt.operations);
|
|
1226
|
+
const title = attempt.title.filter(Boolean).at(-1) ?? "Unnamed test";
|
|
1227
|
+
const [selectedConversationId, setSelectedConversationId] = useState(attempt.operations[0]?.id);
|
|
1228
|
+
const selectedConversation = attempt.operations.find((operation) => operation.id === selectedConversationId) ??
|
|
1229
|
+
attempt.operations[0];
|
|
1230
|
+
return (_jsxs("article", { ...stylex.props(styles.attemptCard), children: [_jsxs("div", { ...stylex.props(styles.row), children: [_jsxs("div", { children: [_jsx("strong", { ...stylex.props(styles.attemptTitle), children: title }), _jsxs("p", { ...stylex.props(styles.meta), children: [attempt.project || "default", " \u00B7 ", attempt.operations.length, " named", " ", pluralize(attempt.operations.length, "operation")] })] }), _jsxs("div", { ...stylex.props(styles.attemptActions), children: [attempt.status === "failed" ? (_jsx(CopyFailureButton, { attempt: attempt, criteria: criteria })) : null, _jsx("span", { ...stylex.props(styles.status, attempt.status === "passed" && styles.statusPass, attempt.status === "failed" && styles.statusFail, attempt.status === "running" && styles.statusRunning), children: attempt.status })] })] }), _jsx(OperationList, { operations: attempt.operations }), _jsx(RunResult, { result: result, status: attempt.status, criteria: criteria, explanations: judgeCriterionExplanations(attempt.operations), errors: attempt.errors, criterionResults: attempt.criterionResults }), attempt.operations.length > 0 ? (_jsx(ConversationTabs, { operations: attempt.operations, selected: selectedConversation, select: setSelectedConversationId, attemptStatus: attempt.status })) : null, _jsx(Conversation, { operation: selectedConversation, operations: attempt.operations, select: setSelectedConversationId, status: attempt.status === "running"
|
|
1231
|
+
? (selectedConversation?.status ?? attempt.status)
|
|
1232
|
+
: attempt.status }), _jsx(TechnicalDetails, { operations: attempt.operations, output: output })] }));
|
|
1233
|
+
}
|
|
1234
|
+
function CopyFailureButton({ attempt, criteria }) {
|
|
1235
|
+
const [state, setState] = useState("idle");
|
|
1236
|
+
const copy = async () => {
|
|
1237
|
+
try {
|
|
1238
|
+
await navigator.clipboard.writeText(failureDebugText(attempt, criteria));
|
|
1239
|
+
setState("copied");
|
|
1240
|
+
}
|
|
1241
|
+
catch {
|
|
1242
|
+
setState("failed");
|
|
1243
|
+
}
|
|
1244
|
+
};
|
|
1245
|
+
return (_jsx("button", { type: "button", "aria-label": "Copy failure details", ...stylex.props(styles.buttonReset, styles.copyFailureButton), onClick: () => void copy(), children: state === "copied" ? "Copied" : state === "failed" ? "Copy failed" : "Copy details" }));
|
|
1246
|
+
}
|
|
1247
|
+
function failureDebugText(attempt, criteria) {
|
|
1248
|
+
const result = operationResult(attempt.operations);
|
|
1249
|
+
const title = attempt.title.filter(Boolean);
|
|
1250
|
+
const output = [...attempt.output.stdout, ...attempt.output.stderr].join("\n");
|
|
1251
|
+
return [
|
|
1252
|
+
"Fix this agent test failure.",
|
|
1253
|
+
"Use the evidence below. Preserve the test's intent unless its expectation is incorrect.",
|
|
1254
|
+
"",
|
|
1255
|
+
`Test: ${title.at(-1) ?? "Unnamed test"}`,
|
|
1256
|
+
`Title path: ${title.join(" › ")}`,
|
|
1257
|
+
`Attempt: ${attempt.id}`,
|
|
1258
|
+
`Project: ${attempt.project || "default"}`,
|
|
1259
|
+
`Status: ${attempt.status}`,
|
|
1260
|
+
"",
|
|
1261
|
+
"Criteria:",
|
|
1262
|
+
...failureCriterionLines(attempt, criteria),
|
|
1263
|
+
"",
|
|
1264
|
+
"Errors:",
|
|
1265
|
+
...(attempt.errors.length
|
|
1266
|
+
? attempt.errors.map((error) => error.message ?? "Test failed")
|
|
1267
|
+
: ["(none)"]),
|
|
1268
|
+
"",
|
|
1269
|
+
"Conversation and tools:",
|
|
1270
|
+
...(result.timeline.length ? result.timeline.map(debugTimelineLine) : ["(none recorded)"]),
|
|
1271
|
+
"",
|
|
1272
|
+
"Test process output:",
|
|
1273
|
+
output || "(none)",
|
|
1274
|
+
].join("\n");
|
|
1275
|
+
}
|
|
1276
|
+
function failureCriterionLines(attempt, criteria) {
|
|
1277
|
+
return criteria.map((criterion, index) => {
|
|
1278
|
+
const outcome = criterionDisplayOutcome({
|
|
1279
|
+
criterion,
|
|
1280
|
+
index,
|
|
1281
|
+
results: attempt.criterionResults,
|
|
1282
|
+
status: attempt.status,
|
|
1283
|
+
errors: attempt.errors,
|
|
1284
|
+
});
|
|
1285
|
+
return `- [${outcome}] ${criterion}`;
|
|
1286
|
+
});
|
|
1287
|
+
}
|
|
1288
|
+
function debugTimelineLine(event) {
|
|
1289
|
+
if (event.kind === "message")
|
|
1290
|
+
return `${event.message.role}: ${event.message.content}`;
|
|
1291
|
+
const args = event.tool.args ? ` ${JSON.stringify(event.tool.args)}` : "";
|
|
1292
|
+
const result = event.tool.result ? `\n result: ${event.tool.result}` : "";
|
|
1293
|
+
return `tool ${event.tool.name}:${args}${result}`;
|
|
1294
|
+
}
|
|
1295
|
+
function TechnicalDetails({ operations, output, }) {
|
|
1296
|
+
return (_jsxs("details", { ...stylex.props(styles.evidence), children: [_jsxs("summary", { ...stylex.props(styles.evidenceSummary), children: [_jsx("span", { ...stylex.props(styles.disclosureIcon), children: "\u203A" }), "Technical details"] }), _jsx("p", { ...stylex.props(styles.meta), children: "Low-level evidence for debugging the test runner, separate from the agent conversation." }), _jsx(EvidencePanel, { label: "Test process logs (stdout / stderr)", value: output, empty: "The test process did not write to stdout or stderr." }), _jsx(EvidencePanel, { label: "Diagnostics", value: JSON.stringify(operations, null, 2), empty: "No diagnostics were captured." })] }));
|
|
1297
|
+
}
|
|
1298
|
+
function EvidencePanel({ label, value, empty }) {
|
|
1299
|
+
return (_jsxs("details", { ...stylex.props(styles.evidence), children: [_jsxs("summary", { ...stylex.props(styles.evidenceSummary), children: [_jsx("span", { ...stylex.props(styles.disclosureIcon), children: "\u203A" }), label] }), value ? (_jsx("pre", { ...stylex.props(styles.pre), children: value })) : (_jsx("p", { ...stylex.props(styles.meta), children: empty }))] }));
|
|
1300
|
+
}
|
|
1301
|
+
function messagesFromOperation(value) {
|
|
1302
|
+
if (!isRecord(value))
|
|
1303
|
+
return [];
|
|
1304
|
+
const trace = isRecord(value.trace)
|
|
1305
|
+
? value.trace
|
|
1306
|
+
: isRecord(value.conversation)
|
|
1307
|
+
? value.conversation
|
|
1308
|
+
: undefined;
|
|
1309
|
+
if (!trace || !Array.isArray(trace.messages))
|
|
1310
|
+
return [];
|
|
1311
|
+
return uniqueMessages(trace.messages.flatMap((message) => isRecord(message) && typeof message.role === "string" && typeof message.content === "string"
|
|
1312
|
+
? [{ role: message.role, content: message.content, seq: optionalNumber(message.seq) }]
|
|
1313
|
+
: []));
|
|
1314
|
+
}
|
|
1315
|
+
function toolCallsFromOperation(value) {
|
|
1316
|
+
if (!isRecord(value))
|
|
1317
|
+
return [];
|
|
1318
|
+
const trace = isRecord(value.trace)
|
|
1319
|
+
? value.trace
|
|
1320
|
+
: isRecord(value.conversation)
|
|
1321
|
+
? value.conversation
|
|
1322
|
+
: undefined;
|
|
1323
|
+
if (!trace || !Array.isArray(trace.toolCalls))
|
|
1324
|
+
return [];
|
|
1325
|
+
return trace.toolCalls.flatMap((call) => {
|
|
1326
|
+
if (!isRecord(call) || typeof call.name !== "string")
|
|
1327
|
+
return [];
|
|
1328
|
+
return [
|
|
1329
|
+
{
|
|
1330
|
+
name: call.name,
|
|
1331
|
+
args: isRecord(call.args) ? call.args : undefined,
|
|
1332
|
+
result: optionalString(call.result),
|
|
1333
|
+
succeeded: typeof call.succeeded === "boolean" ? call.succeeded : undefined,
|
|
1334
|
+
exitCode: optionalNumber(call.exitCode),
|
|
1335
|
+
seq: optionalNumber(call.seq),
|
|
1336
|
+
},
|
|
1337
|
+
];
|
|
1338
|
+
});
|
|
1339
|
+
}
|
|
1340
|
+
function operationResult(operations) {
|
|
1341
|
+
const records = operations.flatMap((operation) => operation.data).filter(isRecord);
|
|
1342
|
+
const completed = [...records].reverse().find((value) => value.output !== undefined);
|
|
1343
|
+
const source = completed ?? records.at(-1);
|
|
1344
|
+
if (!source)
|
|
1345
|
+
return { timeline: [] };
|
|
1346
|
+
const prompt = records.map((record) => optionalString(record.prompt)).find(Boolean);
|
|
1347
|
+
return {
|
|
1348
|
+
prompt,
|
|
1349
|
+
output: conversationOutput(source.output),
|
|
1350
|
+
durationMs: optionalNumber(source.durationMs),
|
|
1351
|
+
totalTokens: nestedNumber(source.usage, "tokens", "total"),
|
|
1352
|
+
toolCallCount: optionalArrayLength(source.toolCalls),
|
|
1353
|
+
changedPathCount: nestedArrayLength(source.workspace, "changedPaths"),
|
|
1354
|
+
timeline: completed
|
|
1355
|
+
? conversationTimeline(source, prompt)
|
|
1356
|
+
: liveConversationTimeline(records, prompt),
|
|
1357
|
+
};
|
|
1358
|
+
}
|
|
1359
|
+
function conversationOutput(value) {
|
|
1360
|
+
if (typeof value === "string")
|
|
1361
|
+
return value;
|
|
1362
|
+
if (!isRecord(value))
|
|
1363
|
+
return undefined;
|
|
1364
|
+
const reason = optionalString(value.reason);
|
|
1365
|
+
const facts = Object.entries(value)
|
|
1366
|
+
.filter(([key]) => key !== "reason")
|
|
1367
|
+
.map(([key, item]) => `${humanizeKey(key)}: ${formatConversationValue(item)}`);
|
|
1368
|
+
return [reason, ...facts].filter(Boolean).join("\n\n");
|
|
1369
|
+
}
|
|
1370
|
+
function humanizeKey(value) {
|
|
1371
|
+
return value
|
|
1372
|
+
.replace(CAMEL_CASE_BOUNDARY, "$1 $2")
|
|
1373
|
+
.replace(INITIAL_CHARACTER, (letter) => letter.toUpperCase());
|
|
1374
|
+
}
|
|
1375
|
+
function formatConversationValue(value) {
|
|
1376
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean")
|
|
1377
|
+
return String(value);
|
|
1378
|
+
return JSON.stringify(value);
|
|
1379
|
+
}
|
|
1380
|
+
function liveConversationTimeline(records, prompt) {
|
|
1381
|
+
const timeline = prompt
|
|
1382
|
+
? [{ kind: "message", message: { role: "user", content: prompt, seq: -1 } }]
|
|
1383
|
+
: [];
|
|
1384
|
+
for (const [index, record] of records.entries()) {
|
|
1385
|
+
const tool = liveToolEvent(record, index);
|
|
1386
|
+
if (tool)
|
|
1387
|
+
timeline.push(tool);
|
|
1388
|
+
if (record.type === "text" && typeof record.text === "string")
|
|
1389
|
+
appendLiveText(timeline, record.text, index);
|
|
1390
|
+
}
|
|
1391
|
+
return timeline;
|
|
1392
|
+
}
|
|
1393
|
+
function liveToolEvent(record, seq) {
|
|
1394
|
+
if (record.type !== "tool" || typeof record.name !== "string")
|
|
1395
|
+
return undefined;
|
|
1396
|
+
return {
|
|
1397
|
+
kind: "tool",
|
|
1398
|
+
tool: {
|
|
1399
|
+
name: record.name,
|
|
1400
|
+
args: isRecord(record.args) ? record.args : undefined,
|
|
1401
|
+
result: optionalString(record.result),
|
|
1402
|
+
exitCode: optionalNumber(record.exitCode),
|
|
1403
|
+
succeeded: typeof record.succeeded === "boolean" ? record.succeeded : undefined,
|
|
1404
|
+
seq,
|
|
1405
|
+
},
|
|
1406
|
+
};
|
|
1407
|
+
}
|
|
1408
|
+
function appendLiveText(timeline, content, seq) {
|
|
1409
|
+
const last = timeline.at(-1);
|
|
1410
|
+
if (last?.kind === "message" && last.message.role === "assistant") {
|
|
1411
|
+
last.message.content = content;
|
|
1412
|
+
return;
|
|
1413
|
+
}
|
|
1414
|
+
timeline.push({ kind: "message", message: { role: "assistant", content, seq } });
|
|
1415
|
+
}
|
|
1416
|
+
function conversationTimeline(source, prompt) {
|
|
1417
|
+
const tools = toolCallsFromOperation(source);
|
|
1418
|
+
const messages = messagesFromOperation(source).filter((message) => message.role !== "tool" || tools.length === 0);
|
|
1419
|
+
const judgeInput = judgeInputMessages(source.input);
|
|
1420
|
+
if (prompt && !messages.some((message) => message.role === "user" && message.content === prompt))
|
|
1421
|
+
messages.unshift({ role: "user", content: prompt, seq: -1 });
|
|
1422
|
+
const output = conversationOutput(source.output);
|
|
1423
|
+
if (judgeInput.length && output && !messages.some((message) => message.role === "assistant"))
|
|
1424
|
+
messages.push({ role: "assistant", content: output, seq: 1 });
|
|
1425
|
+
return [
|
|
1426
|
+
...judgeInput.map((message) => ({ kind: "message", message })),
|
|
1427
|
+
...messages.map((message) => ({ kind: "message", message })),
|
|
1428
|
+
...tools.map((tool) => ({ kind: "tool", tool })),
|
|
1429
|
+
].sort((left, right) => eventOrder(left) - eventOrder(right));
|
|
1430
|
+
}
|
|
1431
|
+
function judgeInputMessages(value) {
|
|
1432
|
+
if (!isRecord(value))
|
|
1433
|
+
return [];
|
|
1434
|
+
return Object.entries(value).flatMap(([key, item], index) => {
|
|
1435
|
+
if (typeof item !== "string")
|
|
1436
|
+
return [];
|
|
1437
|
+
return [
|
|
1438
|
+
{
|
|
1439
|
+
role: key === "answer" ? "Agent response" : humanizeKey(key),
|
|
1440
|
+
content: item,
|
|
1441
|
+
seq: index - Object.keys(value).length - 1,
|
|
1442
|
+
},
|
|
1443
|
+
];
|
|
1444
|
+
});
|
|
1445
|
+
}
|
|
1446
|
+
function eventOrder(event) {
|
|
1447
|
+
const value = event.kind === "message" ? event.message.seq : event.tool.seq;
|
|
1448
|
+
if (value !== undefined)
|
|
1449
|
+
return value;
|
|
1450
|
+
if (event.kind === "tool")
|
|
1451
|
+
return 0;
|
|
1452
|
+
return event.message.role === "user" ? -1 : 1;
|
|
1453
|
+
}
|
|
1454
|
+
function optionalString(value) {
|
|
1455
|
+
return typeof value === "string" ? value : undefined;
|
|
1456
|
+
}
|
|
1457
|
+
function optionalNumber(value) {
|
|
1458
|
+
return typeof value === "number" ? value : undefined;
|
|
1459
|
+
}
|
|
1460
|
+
function optionalArrayLength(value) {
|
|
1461
|
+
return Array.isArray(value) ? value.length : undefined;
|
|
1462
|
+
}
|
|
1463
|
+
function nestedNumber(value, parent, child) {
|
|
1464
|
+
if (!isRecord(value) || !isRecord(value[parent]))
|
|
1465
|
+
return undefined;
|
|
1466
|
+
return optionalNumber(value[parent][child]);
|
|
1467
|
+
}
|
|
1468
|
+
function nestedArrayLength(value, key) {
|
|
1469
|
+
return isRecord(value) ? optionalArrayLength(value[key]) : undefined;
|
|
1470
|
+
}
|
|
1471
|
+
function RunResult({ result, status, criteria, explanations, errors, criterionResults, }) {
|
|
1472
|
+
const presentations = criterionPresentations({
|
|
1473
|
+
criteria,
|
|
1474
|
+
explanations,
|
|
1475
|
+
results: criterionResults,
|
|
1476
|
+
status,
|
|
1477
|
+
errors,
|
|
1478
|
+
});
|
|
1479
|
+
const assignedFailures = new Set(presentations.map((item) => item.failure).filter(Boolean));
|
|
1480
|
+
return (_jsxs("section", { "aria-label": "Result", ...stylex.props(styles.resultPanel), children: [_jsx("h3", { ...stylex.props(styles.contentHeading), children: "Result" }), _jsx(ResultVerdict, { status: status }), _jsx(CriterionResults, { presentations: presentations }), errors
|
|
1481
|
+
.filter((error) => !assignedFailures.has(error.message))
|
|
1482
|
+
.map((error, index) => (_jsx(FailureDetails, { message: error.message ?? "Test failed" }, index))), _jsx(ResultMetrics, { result: result })] }));
|
|
1483
|
+
}
|
|
1484
|
+
function FailureDetails({ message }) {
|
|
1485
|
+
const comparison = assertionComparison(message);
|
|
1486
|
+
if (!comparison)
|
|
1487
|
+
return _jsx("pre", { ...stylex.props(styles.pre, styles.error), children: stripAnsi(message) });
|
|
1488
|
+
return (_jsxs("section", { "aria-label": "Expected vs received", ...stylex.props(styles.assertionCard), children: [_jsx("strong", { ...stylex.props(styles.assertionTitle), children: "Expected vs received" }), _jsxs("dl", { ...stylex.props(styles.assertionValues), children: [_jsx(AssertionValue, { label: "Expected", value: comparison.expected }), _jsx(AssertionValue, { label: "Received", value: comparison.received })] })] }));
|
|
1489
|
+
}
|
|
1490
|
+
function AssertionValue({ label, value }) {
|
|
1491
|
+
return (_jsxs("div", { ...stylex.props(styles.assertionValue), children: [_jsx("dt", { ...stylex.props(styles.assertionLabel), children: label }), _jsx("dd", { ...stylex.props(styles.assertionCode), children: value || "(empty)" })] }));
|
|
1492
|
+
}
|
|
1493
|
+
function ResultVerdict({ status }) {
|
|
1494
|
+
return status === "running" ? (_jsx("p", { ...stylex.props(styles.resultOutput), children: "The test is still running." })) : null;
|
|
1495
|
+
}
|
|
1496
|
+
function criterionPresentations({ criteria, explanations, results, status, errors, }) {
|
|
1497
|
+
const presentations = criteria.map((criterion, index) => ({
|
|
1498
|
+
criterion,
|
|
1499
|
+
explanation: explanations[index],
|
|
1500
|
+
outcome: criterionDisplayOutcome({ criterion, index, results, status, errors }),
|
|
1501
|
+
}));
|
|
1502
|
+
const failed = presentations.filter((item) => item.outcome === "failed");
|
|
1503
|
+
return presentations.map((item) => {
|
|
1504
|
+
const matched = errors.find((error) => criterionMatchesError(item.criterion, error.message));
|
|
1505
|
+
const onlyFailure = failed.length === 1 && errors.length === 1 ? errors[0] : undefined;
|
|
1506
|
+
return {
|
|
1507
|
+
...item,
|
|
1508
|
+
failure: item.outcome === "failed" ? (matched?.message ?? onlyFailure?.message) : undefined,
|
|
1509
|
+
};
|
|
1510
|
+
});
|
|
1511
|
+
}
|
|
1512
|
+
function CriterionResults({ presentations }) {
|
|
1513
|
+
if (!presentations.length)
|
|
1514
|
+
return null;
|
|
1515
|
+
return (_jsx("section", { "aria-label": "Criterion results", ...stylex.props(styles.criterionResults), children: _jsx("ul", { ...stylex.props(styles.criterionResultList), children: presentations.map((presentation) => (_jsx(CriterionResultRow, { criterion: presentation.criterion, outcome: presentation.outcome, explanation: presentation.explanation, failure: presentation.failure }, presentation.criterion))) }) }));
|
|
1516
|
+
}
|
|
1517
|
+
function criterionDisplayOutcome(input) {
|
|
1518
|
+
const outcome = criterionOutcome(input);
|
|
1519
|
+
if (outcome !== "not-recorded" || input.status !== "failed")
|
|
1520
|
+
return outcome;
|
|
1521
|
+
return input.errors.some((error) => criterionMatchesError(input.criterion, error.message))
|
|
1522
|
+
? "failed"
|
|
1523
|
+
: outcome;
|
|
1524
|
+
}
|
|
1525
|
+
function criterionMatchesError(criterion, message) {
|
|
1526
|
+
if (!message)
|
|
1527
|
+
return false;
|
|
1528
|
+
const comparison = assertionComparison(message);
|
|
1529
|
+
const expected = comparison?.expected.trim();
|
|
1530
|
+
return Boolean(expected && criterion.includes(expected));
|
|
1531
|
+
}
|
|
1532
|
+
function criterionOutcome({ criterion, index, results, status, }) {
|
|
1533
|
+
const recorded = results.find((result) => result.criterion === criterion) ?? results[index];
|
|
1534
|
+
if (recorded)
|
|
1535
|
+
return recorded.status;
|
|
1536
|
+
if (status === "passed")
|
|
1537
|
+
return "passed";
|
|
1538
|
+
if (status === "running")
|
|
1539
|
+
return "pending";
|
|
1540
|
+
return "not-recorded";
|
|
1541
|
+
}
|
|
1542
|
+
function CriterionResultRow({ criterion, outcome, explanation, failure, }) {
|
|
1543
|
+
const label = outcome === "not-recorded" ? "Not recorded" : capitalize(outcome);
|
|
1544
|
+
return (_jsxs("li", { ...stylex.props(styles.criterionResult), children: [_jsxs("div", { ...stylex.props(styles.criterionResultHeader), children: [_jsx(CriterionOutcomeIcon, { outcome: outcome, label: label }), _jsx("span", { children: criterion })] }), explanation ? _jsx("p", { ...stylex.props(styles.criterionExplanation), children: explanation }) : null, failure ? _jsx(FailureDetails, { message: failure }) : null] }));
|
|
1545
|
+
}
|
|
1546
|
+
function CriterionOutcomeIcon({ outcome, label }) {
|
|
1547
|
+
return (_jsx("span", { role: "img", "aria-label": label, ...stylex.props(styles.criterionOutcome, outcome === "passed" && styles.criterionOutcomePass, outcome === "failed" && styles.criterionOutcomeFail, outcome === "pending" && styles.criterionOutcomePending, outcome === "not-recorded" && styles.criterionOutcomeUnknown), children: criterionSymbol(outcome) }));
|
|
1548
|
+
}
|
|
1549
|
+
function criterionSymbol(outcome) {
|
|
1550
|
+
if (outcome === "passed")
|
|
1551
|
+
return "✓";
|
|
1552
|
+
if (outcome === "failed")
|
|
1553
|
+
return "×";
|
|
1554
|
+
if (outcome === "pending")
|
|
1555
|
+
return "…";
|
|
1556
|
+
return "–";
|
|
1557
|
+
}
|
|
1558
|
+
function capitalize(value) {
|
|
1559
|
+
return `${value.charAt(0).toUpperCase()}${value.slice(1)}`;
|
|
1560
|
+
}
|
|
1561
|
+
function ResultMetrics({ result }) {
|
|
1562
|
+
const metrics = [
|
|
1563
|
+
["Duration", result.durationMs === undefined ? "—" : formatDuration(result.durationMs)],
|
|
1564
|
+
["Tokens", result.totalTokens === undefined ? "—" : result.totalTokens.toLocaleString()],
|
|
1565
|
+
["Tool calls", result.toolCallCount === undefined ? "—" : String(result.toolCallCount)],
|
|
1566
|
+
[
|
|
1567
|
+
"Files changed",
|
|
1568
|
+
result.changedPathCount === undefined ? "—" : String(result.changedPathCount),
|
|
1569
|
+
],
|
|
1570
|
+
];
|
|
1571
|
+
return (_jsx("div", { ...stylex.props(styles.metricGrid), children: metrics.map(([label, value]) => (_jsxs("div", { ...stylex.props(styles.metric), children: [_jsx("span", { ...stylex.props(styles.resourceFactLabel), children: label }), _jsx("span", { ...stylex.props(styles.metricValue), children: value })] }, label))) }));
|
|
1572
|
+
}
|
|
1573
|
+
function Conversation({ operation, operations, select, status, }) {
|
|
1574
|
+
const { timeline, judge } = conversationContent(operation, operations);
|
|
1575
|
+
return (_jsxs("section", { "aria-label": "Conversation", ...stylex.props(styles.conversation), children: [_jsxs("header", { ...stylex.props(styles.conversationHeader), children: [_jsx("h3", { ...stylex.props(styles.contentHeading), children: "Conversation" }), _jsx(ConversationRunTabs, { operation: operation, operations: operations, select: select })] }), _jsxs("div", { ...stylex.props(styles.conversationThread), children: [_jsx(ConversationEvents, { timeline: timeline }), _jsx(JudgeResponse, { review: judge })] }), timeline.length === 0 && status !== "running" ? (_jsx("p", { ...stylex.props(styles.meta), children: conversationPlaceholder(status) })) : null, status === "running" ? _jsx(RunningIndicator, {}) : null] }));
|
|
1576
|
+
}
|
|
1577
|
+
function conversationContent(operation, operations) {
|
|
1578
|
+
if (operation?.kind === "evaluation") {
|
|
1579
|
+
const judge = judgeReviewData(operation);
|
|
1580
|
+
return {
|
|
1581
|
+
judge,
|
|
1582
|
+
timeline: judge.question
|
|
1583
|
+
? [
|
|
1584
|
+
{
|
|
1585
|
+
kind: "message",
|
|
1586
|
+
message: { role: "Judge question", content: judge.question, seq: -1 },
|
|
1587
|
+
},
|
|
1588
|
+
]
|
|
1589
|
+
: [],
|
|
1590
|
+
};
|
|
1591
|
+
}
|
|
1592
|
+
const result = operationResult(operation ? [operation] : []);
|
|
1593
|
+
return {
|
|
1594
|
+
timeline: [...legacyJudgeInput(operation, operations), ...recordedTimeline(result)],
|
|
1595
|
+
};
|
|
1596
|
+
}
|
|
1597
|
+
function recordedTimeline(result) {
|
|
1598
|
+
if (result.timeline.length)
|
|
1599
|
+
return result.timeline;
|
|
1600
|
+
if (!result.output)
|
|
1601
|
+
return [];
|
|
1602
|
+
return [{ kind: "message", message: { role: "assistant", content: result.output } }];
|
|
1603
|
+
}
|
|
1604
|
+
function ConversationEvents({ timeline }) {
|
|
1605
|
+
return timeline.map((event, index) => event.kind === "tool" ? (_jsx(ToolActivity, { tool: event.tool }, `tool:${event.tool.seq ?? index}:${event.tool.name}`)) : (_jsx(MessageBubble, { message: event.message }, `message:${event.message.seq ?? index}:${event.message.role}`)));
|
|
1606
|
+
}
|
|
1607
|
+
function JudgeResponse({ review }) {
|
|
1608
|
+
if (!review || (!review.outcomes.length && !review.reason))
|
|
1609
|
+
return null;
|
|
1610
|
+
return _jsx(JudgeFindings, { outcomes: review.outcomes, reason: review.reason });
|
|
1611
|
+
}
|
|
1612
|
+
function JudgeFindings({ outcomes, reason, }) {
|
|
1613
|
+
return (_jsxs("section", { "aria-label": "Judge response", ...stylex.props(styles.judgeResponse), children: [_jsx("h4", { ...stylex.props(styles.judgeResponseHeading), children: "Judge response" }), _jsx("div", { ...stylex.props(styles.judgeOutcomeList), children: outcomes.map((outcome) => (_jsxs("div", { ...stylex.props(styles.judgeOutcome), children: [_jsx(CriterionOutcomeIcon, { outcome: outcome.passed ? "passed" : "failed", label: outcome.passed ? "Passed" : "Failed" }), _jsx("span", { ...stylex.props(styles.judgeOutcomeLabel), children: outcome.label }), outcome.explanation ? (_jsx("p", { ...stylex.props(styles.judgeOutcomeExplanation), children: outcome.explanation })) : null] }, outcome.label))) }), reason && !outcomes.length ? (_jsx("p", { ...stylex.props(styles.judgeOutcomeExplanation), children: reason })) : null] }));
|
|
1614
|
+
}
|
|
1615
|
+
function judgeReviewData(operation) {
|
|
1616
|
+
const records = operation.data.filter(isRecord);
|
|
1617
|
+
const record = [...records].reverse().find((item) => item.output !== undefined) ?? records.at(-1);
|
|
1618
|
+
const output = isRecord(record?.output) ? record.output : {};
|
|
1619
|
+
const reason = optionalString(output.reason) ?? conversationOutput(record?.output);
|
|
1620
|
+
return {
|
|
1621
|
+
question: judgeQuestion(record),
|
|
1622
|
+
outcomes: judgeOutcomes(output, reason),
|
|
1623
|
+
reason,
|
|
1624
|
+
};
|
|
1625
|
+
}
|
|
1626
|
+
function judgeQuestion(record) {
|
|
1627
|
+
const evaluation = isRecord(record?.evaluation) ? record.evaluation : undefined;
|
|
1628
|
+
return optionalString(evaluation?.prompt);
|
|
1629
|
+
}
|
|
1630
|
+
function judgeOutcomes(output, fallbackExplanation) {
|
|
1631
|
+
const entries = Object.entries(output).filter((entry) => typeof entry[1] === "boolean");
|
|
1632
|
+
const fallbacks = splitJudgeExplanation(fallbackExplanation, entries.length);
|
|
1633
|
+
return entries.map(([key, passed], index) => ({
|
|
1634
|
+
label: humanizeKey(key),
|
|
1635
|
+
passed,
|
|
1636
|
+
explanation: judgeOutcomeExplanation(output, key) ?? fallbacks[index],
|
|
1637
|
+
}));
|
|
1638
|
+
}
|
|
1639
|
+
function splitJudgeExplanation(value, count) {
|
|
1640
|
+
if (!value || count < 1)
|
|
1641
|
+
return [];
|
|
1642
|
+
const sentences = value.split(SENTENCE_BOUNDARY).filter(Boolean);
|
|
1643
|
+
if (sentences.length < count)
|
|
1644
|
+
return Array.from({ length: count }, () => value);
|
|
1645
|
+
return Array.from({ length: count }, (_, index) => index === count - 1 ? sentences.slice(index).join(" ") : (sentences[index] ?? value));
|
|
1646
|
+
}
|
|
1647
|
+
function judgeOutcomeExplanation(output, key) {
|
|
1648
|
+
const explanations = isRecord(output.explanations) ? output.explanations : {};
|
|
1649
|
+
return (optionalString(explanations[key]) ??
|
|
1650
|
+
optionalString(output[`${key}Explanation`]) ??
|
|
1651
|
+
optionalString(output[`${key}Reason`]));
|
|
1652
|
+
}
|
|
1653
|
+
function judgeCriterionExplanations(operations) {
|
|
1654
|
+
return operations
|
|
1655
|
+
.flatMap((operation) => operation.kind === "evaluation" ? judgeReviewData(operation).outcomes : [])
|
|
1656
|
+
.map((outcome) => outcome.explanation);
|
|
1657
|
+
}
|
|
1658
|
+
function legacyJudgeInput(operation, operations) {
|
|
1659
|
+
if (!operation || operation.kind !== "evaluation")
|
|
1660
|
+
return [];
|
|
1661
|
+
if (operation.data.some((item) => isRecord(item) && isRecord(item.input)))
|
|
1662
|
+
return [];
|
|
1663
|
+
const index = operations.findIndex((item) => item.id === operation.id);
|
|
1664
|
+
const agent = operations
|
|
1665
|
+
.slice(0, index)
|
|
1666
|
+
.reverse()
|
|
1667
|
+
.find((item) => item.kind === "agent");
|
|
1668
|
+
if (!agent)
|
|
1669
|
+
return [];
|
|
1670
|
+
const result = operationResult([agent]);
|
|
1671
|
+
const timeline = [];
|
|
1672
|
+
if (result.prompt)
|
|
1673
|
+
timeline.push({
|
|
1674
|
+
kind: "message",
|
|
1675
|
+
message: { role: "Task", content: result.prompt, seq: -3 },
|
|
1676
|
+
});
|
|
1677
|
+
if (result.output)
|
|
1678
|
+
timeline.push({
|
|
1679
|
+
kind: "message",
|
|
1680
|
+
message: { role: "Agent response", content: result.output, seq: -2 },
|
|
1681
|
+
});
|
|
1682
|
+
return timeline;
|
|
1683
|
+
}
|
|
1684
|
+
function ConversationTabs({ operations, selected, select, attemptStatus, }) {
|
|
1685
|
+
if (!operations.length)
|
|
1686
|
+
return null;
|
|
1687
|
+
const groups = conversationGroups(operations);
|
|
1688
|
+
const representatives = groups.map((group) => group.operations[0]);
|
|
1689
|
+
const selectedGroup = selected ? operationIdentity(selected) : undefined;
|
|
1690
|
+
return (_jsx("div", { role: "tablist", "aria-label": "Conversation participants", ...stylex.props(styles.conversationSwitcher, styles.conversationTabs), children: groups.map((group, index) => (_jsx(ConversationTab, { operation: group.operations[0], active: group.key === selectedGroup, running: attemptStatus === "running" &&
|
|
1691
|
+
group.operations.some((operation) => operation.status === "running"), onSelect: () => select(group.operations[0].id), onKeyDown: (event) => selectConversationWithKeyboard({
|
|
1692
|
+
event,
|
|
1693
|
+
operations: representatives,
|
|
1694
|
+
index,
|
|
1695
|
+
select,
|
|
1696
|
+
}) }, group.key))) }));
|
|
1697
|
+
}
|
|
1698
|
+
function ConversationTab({ operation, active, running, onSelect, onKeyDown, }) {
|
|
1699
|
+
return (_jsxs("button", { type: "button", role: "tab", "aria-label": conversationLabel(operation), "aria-selected": active, ...stylex.props(styles.buttonReset, styles.status, styles.conversationTab, active && styles.conversationTabActive), onClick: onSelect, onKeyDown: onKeyDown, children: [running ? (_jsx("span", { role: "status", "aria-label": `${operation?.name ?? "Agent"} is running`, ...stylex.props(styles.conversationTabDot) })) : null, conversationLabel(operation)] }));
|
|
1700
|
+
}
|
|
1701
|
+
function conversationLabel(operation) {
|
|
1702
|
+
return `${operation?.name ?? "Unnamed"} · ${operation?.kind === "evaluation" ? "Judge" : "Agent"}`;
|
|
1703
|
+
}
|
|
1704
|
+
function conversationGroups(operations) {
|
|
1705
|
+
const groups = new Map();
|
|
1706
|
+
for (const operation of operations) {
|
|
1707
|
+
const key = operationIdentity(operation);
|
|
1708
|
+
const group = groups.get(key);
|
|
1709
|
+
if (group)
|
|
1710
|
+
group.operations.push(operation);
|
|
1711
|
+
else
|
|
1712
|
+
groups.set(key, { key, operations: [operation] });
|
|
1713
|
+
}
|
|
1714
|
+
return [...groups.values()];
|
|
1715
|
+
}
|
|
1716
|
+
function operationIdentity(operation) {
|
|
1717
|
+
return `${operation.name ?? "Unnamed"}\u0000${operation.kind}`;
|
|
1718
|
+
}
|
|
1719
|
+
function ConversationRunTabs({ operation, operations, select, }) {
|
|
1720
|
+
if (!operation)
|
|
1721
|
+
return null;
|
|
1722
|
+
const runs = operations.filter((item) => operationIdentity(item) === operationIdentity(operation));
|
|
1723
|
+
if (runs.length < 2)
|
|
1724
|
+
return null;
|
|
1725
|
+
return (_jsx("div", { role: "tablist", "aria-label": `${operation.name ?? "Agent"} runs`, ...stylex.props(styles.runTabs), children: runs.map((run, index) => (_jsxs("button", { type: "button", role: "tab", "aria-selected": run.id === operation.id, ...stylex.props(styles.buttonReset, styles.runTab, run.id === operation.id && styles.runTabActive), onClick: () => select(run.id), onKeyDown: (event) => selectConversationWithKeyboard({ event, operations: runs, index, select }), children: ["Run ", index + 1] }, run.id))) }));
|
|
1726
|
+
}
|
|
1727
|
+
function selectConversationWithKeyboard(input) {
|
|
1728
|
+
const { event, operations, index, select } = input;
|
|
1729
|
+
if (event.key !== "ArrowLeft" && event.key !== "ArrowRight")
|
|
1730
|
+
return;
|
|
1731
|
+
event.preventDefault();
|
|
1732
|
+
const direction = event.key === "ArrowRight" ? 1 : -1;
|
|
1733
|
+
const next = operations[(index + direction + operations.length) % operations.length];
|
|
1734
|
+
if (!next)
|
|
1735
|
+
return;
|
|
1736
|
+
select(next.id);
|
|
1737
|
+
const tabs = event.currentTarget.parentElement?.querySelectorAll("[role=tab]");
|
|
1738
|
+
tabs?.[(index + direction + operations.length) % operations.length]?.focus();
|
|
1739
|
+
}
|
|
1740
|
+
function RunningIndicator() {
|
|
1741
|
+
return (_jsxs("div", { role: "status", "aria-label": "Agent is running", ...stylex.props(styles.runningIndicator), children: [_jsx("span", { children: "Running" }), _jsxs("span", { "aria-hidden": "true", ...stylex.props(styles.runningDots), children: [_jsx("span", { ...stylex.props(styles.runningDot), children: "\u2022" }), _jsx("span", { ...stylex.props(styles.runningDot, styles.runningDotSecond), children: "\u2022" }), _jsx("span", { ...stylex.props(styles.runningDot, styles.runningDotThird), children: "\u2022" })] })] }));
|
|
1742
|
+
}
|
|
1743
|
+
function ToolActivity({ tool }) {
|
|
1744
|
+
const presentation = toolPresentation(tool);
|
|
1745
|
+
const [outputOpen, setOutputOpen] = useState(false);
|
|
1746
|
+
return (_jsxs("article", { ...stylex.props(styles.toolEvent), children: [_jsx("span", { "aria-hidden": "true", ...stylex.props(styles.toolIcon), children: presentation.icon }), _jsxs("div", { ...stylex.props(styles.toolCopy), children: [_jsx("strong", { ...stylex.props(styles.toolTitle), children: presentation.title }), presentation.detail ? (_jsx("span", { ...stylex.props(styles.toolDetail), children: presentation.detail })) : null] }), _jsxs("div", { role: "group", "aria-label": "Tool controls", ...stylex.props(styles.toolActions), children: [_jsx("span", { ...stylex.props(styles.toolOutcome, presentation.failed && styles.toolOutcomeFail), children: presentation.outcome }), tool.result ? (_jsx("button", { type: "button", ...stylex.props(styles.buttonReset, styles.toolResultSummary), onClick: () => setOutputOpen((open) => !open), children: outputOpen ? "Hide output" : "View output" })) : null] }), tool.result && outputOpen ? (_jsx("pre", { ...stylex.props(styles.toolResultPre), children: tool.result })) : null] }));
|
|
1747
|
+
}
|
|
1748
|
+
function toolPresentation(tool) {
|
|
1749
|
+
const name = tool.name.toLowerCase();
|
|
1750
|
+
const failed = tool.succeeded === false || (tool.exitCode !== undefined && tool.exitCode !== 0);
|
|
1751
|
+
const outcome = tool.exitCode !== undefined ? `Exit ${tool.exitCode}` : failed ? "Failed" : "Completed";
|
|
1752
|
+
if (name === "read" || name.includes("read_file"))
|
|
1753
|
+
return { icon: "↗", title: "Read file", detail: argument(tool, "path"), outcome, failed };
|
|
1754
|
+
if (["shell", "bash", "exec_command"].includes(name))
|
|
1755
|
+
return { icon: ">", title: "Run command", detail: argument(tool, "command"), outcome, failed };
|
|
1756
|
+
if (name.includes("edit") || name.includes("write"))
|
|
1757
|
+
return { icon: "✎", title: "Change file", detail: argument(tool, "path"), outcome, failed };
|
|
1758
|
+
return { icon: "◆", title: tool.name, detail: summarizeArgs(tool.args), outcome, failed };
|
|
1759
|
+
}
|
|
1760
|
+
function argument(tool, key) {
|
|
1761
|
+
const value = tool.args?.[key];
|
|
1762
|
+
return typeof value === "string" ? value : summarizeArgs(tool.args);
|
|
1763
|
+
}
|
|
1764
|
+
function summarizeArgs(args) {
|
|
1765
|
+
if (!args || Object.keys(args).length === 0)
|
|
1766
|
+
return "";
|
|
1767
|
+
const value = JSON.stringify(args);
|
|
1768
|
+
return value.length > 140 ? `${value.slice(0, 137)}…` : value;
|
|
1769
|
+
}
|
|
1770
|
+
function MessageBubble({ message }) {
|
|
1771
|
+
return (_jsxs("div", { ...stylex.props(styles.message, (message.role === "user" || message.role === "Task" || message.role === "Judge question") &&
|
|
1772
|
+
styles.messageUser, (message.role === "assistant" || message.role === "Agent response") &&
|
|
1773
|
+
styles.messageAssistant, message.role === "Judge response" && styles.messageJudge), children: [_jsx("span", { ...stylex.props(styles.messageRole), children: message.role }), _jsx("div", { ...stylex.props(styles.messageContent), children: _jsx("div", { className: "message-markdown", children: _jsx(Markdown, { children: normalizeTranscriptMarkdown(message.content) }) }) })] }));
|
|
1774
|
+
}
|
|
1775
|
+
function normalizeTranscriptMarkdown(content) {
|
|
1776
|
+
return content.replace(LOCAL_PATH_LINK, (_match, label) => `\`${label}\``);
|
|
1777
|
+
}
|
|
1778
|
+
function uniqueMessages(messages) {
|
|
1779
|
+
const seen = new Set();
|
|
1780
|
+
return messages.filter((message) => {
|
|
1781
|
+
const key = `${message.role}\u0000${message.content}`;
|
|
1782
|
+
if (seen.has(key))
|
|
1783
|
+
return false;
|
|
1784
|
+
seen.add(key);
|
|
1785
|
+
return true;
|
|
1786
|
+
});
|
|
1787
|
+
}
|
|
1788
|
+
function formatDuration(durationMs) {
|
|
1789
|
+
return durationMs < 1_000 ? `${durationMs} ms` : `${(durationMs / 1_000).toFixed(1)} s`;
|
|
1790
|
+
}
|
|
1791
|
+
function pluralize(count, noun) {
|
|
1792
|
+
return count === 1 ? noun : `${noun}s`;
|
|
1793
|
+
}
|
|
1794
|
+
function isRecord(value) {
|
|
1795
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1796
|
+
}
|
|
1797
|
+
function OperationList({ operations }) {
|
|
1798
|
+
if (operations.length === 0)
|
|
1799
|
+
return null;
|
|
1800
|
+
const summaries = summarizeOperations(operations);
|
|
1801
|
+
return (_jsx("div", { ...stylex.props(styles.list), children: summaries.map((summary) => (_jsxs("div", { ...stylex.props(styles.meta), children: [summary.name, " \u00B7 ", summary.status, summary.count > 1 ? ` ×${summary.count}` : ""] }, summary.key))) }));
|
|
1802
|
+
}
|
|
1803
|
+
function summarizeOperations(operations) {
|
|
1804
|
+
const summaries = new Map();
|
|
1805
|
+
for (const operation of operations) {
|
|
1806
|
+
const name = operation.name ?? operation.kind;
|
|
1807
|
+
const key = `${operationIdentity(operation)}\u0000${operation.status}`;
|
|
1808
|
+
const existing = summaries.get(key);
|
|
1809
|
+
if (existing)
|
|
1810
|
+
existing.count++;
|
|
1811
|
+
else
|
|
1812
|
+
summaries.set(key, { key, name, status: operation.status, count: 1 });
|
|
1813
|
+
}
|
|
1814
|
+
return [...summaries.values()];
|
|
1815
|
+
}
|
|
1816
|
+
function useExecutionHistory() {
|
|
1817
|
+
return useQuery({
|
|
1818
|
+
queryKey: ["execution-history"],
|
|
1819
|
+
queryFn: fetchExecutionHistory,
|
|
1820
|
+
});
|
|
1821
|
+
}
|
|
1822
|
+
async function fetchTestCatalog() {
|
|
1823
|
+
return viewerApi.getTestCatalog();
|
|
1824
|
+
}
|
|
1825
|
+
async function fetchExecutionHistory() {
|
|
1826
|
+
return (await viewerApi.listExecutions()).executions;
|
|
1827
|
+
}
|
|
1828
|
+
async function fetchExecution(id) {
|
|
1829
|
+
return (await viewerApi.getExecution(id)).execution;
|
|
1830
|
+
}
|
|
1831
|
+
async function startTest(testId, workers) {
|
|
1832
|
+
return viewerApi.startExecution(testId, workers);
|
|
1833
|
+
}
|
|
1834
|
+
async function startSuite(workers) {
|
|
1835
|
+
return viewerApi.startSuiteExecution(workers);
|
|
1836
|
+
}
|
|
1837
|
+
async function startTestGroup(testIds, workers) {
|
|
1838
|
+
return viewerApi.startTestGroup(testIds, workers);
|
|
1839
|
+
}
|
|
1840
|
+
async function cancelExecution(id) {
|
|
1841
|
+
await viewerApi.cancelExecution(id);
|
|
1842
|
+
}
|
|
1843
|
+
function latestTestStatuses(executions) {
|
|
1844
|
+
const statuses = new Map();
|
|
1845
|
+
for (const execution of executions) {
|
|
1846
|
+
for (const testId of execution.testIds ?? []) {
|
|
1847
|
+
if (statuses.has(testId))
|
|
1848
|
+
continue;
|
|
1849
|
+
statuses.set(testId, execution.testStatuses?.[testId] ?? execution.status);
|
|
1850
|
+
}
|
|
1851
|
+
}
|
|
1852
|
+
return statuses;
|
|
1853
|
+
}
|
|
1854
|
+
function groupTests(tests) {
|
|
1855
|
+
const groups = new Map();
|
|
1856
|
+
for (const test of tests) {
|
|
1857
|
+
const name = test.title.slice(0, -1).join(" › ") || test.file;
|
|
1858
|
+
groups.set(name, [...(groups.get(name) ?? []), test]);
|
|
1859
|
+
}
|
|
1860
|
+
return groups;
|
|
1861
|
+
}
|
|
1862
|
+
//# sourceMappingURL=v2-client.js.map
|