@pome-sh/cli 0.42.4 → 0.43.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/README.md +238 -117
- package/dist/build-info.json +3 -3
- package/dist/{checks-BKMTBJSO.js → checks-V442KL5O.js} +9 -14
- package/dist/{chunk-RPPF2KDQ.js → chunk-4DXTT3RV.js} +7 -7
- package/dist/{chunk-6KJC4BTO.js → chunk-5KFDRR53.js} +2 -2
- package/dist/{chunk-5NPGY73F.js → chunk-64AWQJ7R.js} +2 -2
- package/dist/{chunk-STMGQ7GU.js → chunk-A6AM6KS4.js} +1405 -172
- package/dist/{chunk-NNXVR46L.js → chunk-CS7O2ZXB.js} +114 -2
- package/dist/{chunk-VPXIGCZW.js → chunk-GQSNU3YP.js} +1 -1
- package/dist/{chunk-HRAD7MRX.js → chunk-TWURH7YM.js} +34 -10
- package/dist/{runTrialGroup-BP446HIE.js → runTrialGroup-HYGGBLMM.js} +20 -10
- package/dist/{server-GDK4TBTL.js → server-2WHSHTUD.js} +2 -2
- package/dist/src/cli/main.js +488 -226
- package/dist/{src-Z4C4SSDR.js → src-DBOHIQNB.js} +2 -2
- package/dist/{src-FUPOFZI4.js → src-FRPUTB2H.js} +2 -2
- package/dist/{src-UY4Y75BD.js → src-G6CMFUR6.js} +2 -2
- package/dist/{src-SNSK5ENY.js → src-SJDGRXC5.js} +2 -2
- package/dist/{src-V3RUKDMQ.js → src-VBXONWR3.js} +2 -2
- package/dist/twinHarness-33MAVAXV.js +6 -0
- package/dist/{twinSeed-X6VHBOLM.js → twinSeed-J7UAY3GM.js} +1 -1
- package/dist/{twinStart-QQU6OIO4.js → twinStart-3Q74IURZ.js} +21 -17
- package/package.json +1 -2
- package/dist/agent-Q2UTRJYL.js +0 -408
- package/dist/chunk-46POYRLY.js +0 -1240
- package/dist/chunk-DFOQGAKS.js +0 -116
- package/dist/chunk-JNXZBK3O.js +0 -17
- package/dist/chunk-WERG4AUH.js +0 -462
- package/dist/chunk-ZX4WNSZ5.js +0 -71
- package/dist/runDemo-DRDMCG25.js +0 -408
- package/dist/twinHarness-ATYQTDA5.js +0 -6
package/dist/runDemo-DRDMCG25.js
DELETED
|
@@ -1,408 +0,0 @@
|
|
|
1
|
-
import { newGroupId } from './chunk-JNXZBK3O.js';
|
|
2
|
-
import { DemoCapacityError, capacityLabel, parseCapacityMarker, capacityKindFrom } from './chunk-ZX4WNSZ5.js';
|
|
3
|
-
import { runTask, demoTaskPath, DEMO_TASK_NAME, DEMO_REPO } from './chunk-WERG4AUH.js';
|
|
4
|
-
import { createHostedClient, parseTaskFile, uploadRunBlobs, scoreFromFinalizeResponse, scoreStatus, isNarrated, outcomeOf, criterionPhrase, narratorReadingLines } from './chunk-STMGQ7GU.js';
|
|
5
|
-
import './chunk-NW7HGA2K.js';
|
|
6
|
-
import './chunk-PASFBRK4.js';
|
|
7
|
-
import './chunk-3FZY376K.js';
|
|
8
|
-
import { bootTwin } from './chunk-5NPGY73F.js';
|
|
9
|
-
import './chunk-RPPF2KDQ.js';
|
|
10
|
-
import { getAvailablePort } from './chunk-XDU6TD4O.js';
|
|
11
|
-
import { HostedQuotaError, HostedOrchError } from './chunk-NNXVR46L.js';
|
|
12
|
-
import './chunk-CBFKZZBR.js';
|
|
13
|
-
import './chunk-NBOQN5VX.js';
|
|
14
|
-
import './chunk-YBWG5JK2.js';
|
|
15
|
-
import './chunk-HRAD7MRX.js';
|
|
16
|
-
import './chunk-6KJC4BTO.js';
|
|
17
|
-
import './chunk-SG6ZTIMT.js';
|
|
18
|
-
import './chunk-2K6BJ3PI.js';
|
|
19
|
-
import './chunk-FBSA5L36.js';
|
|
20
|
-
import { readFile } from 'node:fs/promises';
|
|
21
|
-
import { join } from 'node:path';
|
|
22
|
-
import { z } from 'zod';
|
|
23
|
-
|
|
24
|
-
var demoSessionSchema = z.object({
|
|
25
|
-
session_id: z.string().min(1),
|
|
26
|
-
demo_token: z.string().min(1),
|
|
27
|
-
expires_at: z.string()
|
|
28
|
-
});
|
|
29
|
-
async function mintDemoSessions(options) {
|
|
30
|
-
const sessions = [];
|
|
31
|
-
for (let i = 0; i < options.count; i += 1) {
|
|
32
|
-
sessions.push(await mintOne(options));
|
|
33
|
-
}
|
|
34
|
-
return sessions;
|
|
35
|
-
}
|
|
36
|
-
async function mintOne(options) {
|
|
37
|
-
const doFetch = options.fetchImpl ?? fetch;
|
|
38
|
-
const ctrl = new AbortController();
|
|
39
|
-
const timer = setTimeout(() => ctrl.abort(), options.timeoutMs ?? 3e4);
|
|
40
|
-
let res;
|
|
41
|
-
try {
|
|
42
|
-
res = await doFetch(`${options.apiBase}/v1/demo/sessions`, {
|
|
43
|
-
method: "POST",
|
|
44
|
-
headers: { "content-type": "application/json" },
|
|
45
|
-
body: JSON.stringify({
|
|
46
|
-
task_name: options.taskName,
|
|
47
|
-
task_hash: "",
|
|
48
|
-
group_id: options.groupId
|
|
49
|
-
}),
|
|
50
|
-
signal: ctrl.signal
|
|
51
|
-
});
|
|
52
|
-
} catch (err) {
|
|
53
|
-
throw new HostedOrchError(
|
|
54
|
-
err instanceof Error ? err.message : "network error"
|
|
55
|
-
);
|
|
56
|
-
} finally {
|
|
57
|
-
clearTimeout(timer);
|
|
58
|
-
}
|
|
59
|
-
const text = await res.text();
|
|
60
|
-
let json = {};
|
|
61
|
-
try {
|
|
62
|
-
json = text.length ? JSON.parse(text) : {};
|
|
63
|
-
} catch {
|
|
64
|
-
throw new HostedOrchError(
|
|
65
|
-
`POST /v1/demo/sessions returned non-JSON (status ${res.status})`
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
if (!res.ok) {
|
|
69
|
-
const envelope = json.error;
|
|
70
|
-
let kind = capacityKindFrom(res.status, envelope?.details?.kind);
|
|
71
|
-
if (kind === "unknown_capacity") {
|
|
72
|
-
kind = res.status === 429 ? "demo_ip_mint_cap" : "demo_mint_quota";
|
|
73
|
-
}
|
|
74
|
-
if (kind) {
|
|
75
|
-
throw new DemoCapacityError(kind, envelope?.message ?? capacityLabel(kind));
|
|
76
|
-
}
|
|
77
|
-
throw new HostedOrchError(
|
|
78
|
-
envelope?.message ?? `POST /v1/demo/sessions \u2192 HTTP ${res.status}`,
|
|
79
|
-
void 0,
|
|
80
|
-
res.status
|
|
81
|
-
);
|
|
82
|
-
}
|
|
83
|
-
const parsed = demoSessionSchema.safeParse(json);
|
|
84
|
-
if (!parsed.success) {
|
|
85
|
-
throw new HostedOrchError(
|
|
86
|
-
`POST /v1/demo/sessions returned an unexpected shape: ${parsed.error.message}`
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
return parsed.data;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// src/demo/render.ts
|
|
93
|
-
function reassuranceBox() {
|
|
94
|
-
const lines = [
|
|
95
|
-
"pome demo \xB7 running locally",
|
|
96
|
-
"No signup. No API keys.",
|
|
97
|
-
"The GitHub twin runs on your machine; model calls go through pome's",
|
|
98
|
-
"anonymous demo gateway; the trace is evaluated in pome cloud.",
|
|
99
|
-
"Your repo and your data are never touched."
|
|
100
|
-
];
|
|
101
|
-
const width = Math.max(...lines.map((line) => line.length));
|
|
102
|
-
const top = `\u250C${"\u2500".repeat(width + 2)}\u2510`;
|
|
103
|
-
const bottom = `\u2514${"\u2500".repeat(width + 2)}\u2518`;
|
|
104
|
-
return [top, ...lines.map((line) => `\u2502 ${line.padEnd(width)} \u2502`), bottom];
|
|
105
|
-
}
|
|
106
|
-
function twinReadyLine(seconds) {
|
|
107
|
-
return `spinning up github twin \u2026 ready (${seconds.toFixed(1)}s)`;
|
|
108
|
-
}
|
|
109
|
-
function trialsHeaderLine(count, taskName) {
|
|
110
|
-
return `running ${count} isolated trials of ${taskName} \u2026`;
|
|
111
|
-
}
|
|
112
|
-
function evaluatingLine(index) {
|
|
113
|
-
return `trial ${index} \u2026 evaluating in the cloud \u2026`;
|
|
114
|
-
}
|
|
115
|
-
function trialLine(index, verdict) {
|
|
116
|
-
switch (verdict.kind) {
|
|
117
|
-
case "passed":
|
|
118
|
-
return `trial ${index} \u2713 passed ${formatSeconds(verdict.seconds)} ${checksPhrase(verdict.checks)}`;
|
|
119
|
-
case "failed":
|
|
120
|
-
return `trial ${index} \u2717 failed ${formatSeconds(verdict.seconds)} ${checksPhrase(verdict.checks)} ${verdict.note}`;
|
|
121
|
-
case "errored":
|
|
122
|
-
return `trial ${index} \u26A0 errored ${verdict.reason} \u2014 excluded`;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
function checksPhrase(checks) {
|
|
126
|
-
return `${checks.passed} of ${checks.total} checks`;
|
|
127
|
-
}
|
|
128
|
-
function formatSeconds(seconds) {
|
|
129
|
-
return `${seconds.toFixed(1)}s`;
|
|
130
|
-
}
|
|
131
|
-
function summaryLines(input) {
|
|
132
|
-
const passed = input.verdicts.filter((v) => v.kind === "passed").length;
|
|
133
|
-
const failed = input.verdicts.filter((v) => v.kind === "failed").length;
|
|
134
|
-
const errored = input.verdicts.filter(
|
|
135
|
-
(v) => v.kind === "errored"
|
|
136
|
-
);
|
|
137
|
-
const denominator = passed + failed;
|
|
138
|
-
const lines = ["\u2500\u2500\u2500\u2500\u2500"];
|
|
139
|
-
let fraction;
|
|
140
|
-
if (denominator === 0) {
|
|
141
|
-
fraction = "no trials were evaluated";
|
|
142
|
-
} else {
|
|
143
|
-
fraction = `${passed} of ${denominator} passed`;
|
|
144
|
-
}
|
|
145
|
-
if (errored.length > 0) {
|
|
146
|
-
const reason = errored[0].reason;
|
|
147
|
-
const noun = errored.length === 1 ? "trial" : "trials";
|
|
148
|
-
fraction += ` \xB7 ${errored.length} ${noun} errored on ${reason}, excluded from the fraction`;
|
|
149
|
-
}
|
|
150
|
-
lines.push(fraction);
|
|
151
|
-
lines.push(...narratorReadingLines(input.narrated ?? []));
|
|
152
|
-
if (input.failingCriterionPhrase && typeof input.failingCriterionCount === "number" && input.failingCriterionCount > 0 && denominator > 0) {
|
|
153
|
-
lines.push(
|
|
154
|
-
`${input.failingCriterionPhrase} in ${input.failingCriterionCount} of ${denominator} \u2014 start there`
|
|
155
|
-
);
|
|
156
|
-
}
|
|
157
|
-
if (denominator > 0) {
|
|
158
|
-
lines.push("see the full breakdown \u2014 read-only, still no account:");
|
|
159
|
-
lines.push(`\u2192 ${input.previewUrl}`);
|
|
160
|
-
}
|
|
161
|
-
return lines;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// src/demo/runDemo.ts
|
|
165
|
-
var DEMO_FINALIZE_TIMEOUT_MS = 6e4;
|
|
166
|
-
async function runDemo(options) {
|
|
167
|
-
const out = options.out ?? ((line) => console.error(line));
|
|
168
|
-
const trials = options.trials ?? 5;
|
|
169
|
-
const artifactsDir = options.artifactsDir ?? "runs";
|
|
170
|
-
const runTaskFn = options.runTaskFn ?? runTask;
|
|
171
|
-
const mintFn = options.mintFn ?? mintDemoSessions;
|
|
172
|
-
const trialClientFactory = options.trialClientFactory ?? ((session) => createHostedClient({
|
|
173
|
-
baseUrl: options.apiBase,
|
|
174
|
-
apiKey: session.demo_token,
|
|
175
|
-
authScheme: "bearer",
|
|
176
|
-
timeoutMs: DEMO_FINALIZE_TIMEOUT_MS,
|
|
177
|
-
finalizeTimeoutMs: DEMO_FINALIZE_TIMEOUT_MS
|
|
178
|
-
}));
|
|
179
|
-
const groupId = newGroupId();
|
|
180
|
-
const taskPath = demoTaskPath();
|
|
181
|
-
for (const line of reassuranceBox()) out(line);
|
|
182
|
-
out("");
|
|
183
|
-
let sessions;
|
|
184
|
-
try {
|
|
185
|
-
sessions = await mintFn({
|
|
186
|
-
apiBase: options.apiBase,
|
|
187
|
-
taskName: DEMO_TASK_NAME,
|
|
188
|
-
groupId,
|
|
189
|
-
count: trials
|
|
190
|
-
});
|
|
191
|
-
} catch (err) {
|
|
192
|
-
if (err instanceof DemoCapacityError) {
|
|
193
|
-
out(capacityLabel(err.kind));
|
|
194
|
-
return { exitCode: 4, groupId, verdicts: [] };
|
|
195
|
-
}
|
|
196
|
-
out(
|
|
197
|
-
`could not reach the pome demo service (${err instanceof Error ? err.message : String(err)})`
|
|
198
|
-
);
|
|
199
|
-
return { exitCode: 2, groupId, verdicts: [] };
|
|
200
|
-
}
|
|
201
|
-
if (options.skipTwinWarmup !== true) {
|
|
202
|
-
const scenario = await parseTaskFile(taskPath);
|
|
203
|
-
const warmupStart = Date.now();
|
|
204
|
-
const port = await getAvailablePort();
|
|
205
|
-
const harness = await bootTwin({
|
|
206
|
-
twin: "github",
|
|
207
|
-
seedState: scenario.seedState,
|
|
208
|
-
runId: "demo-warmup",
|
|
209
|
-
twinBaseUrl: `http://127.0.0.1:${port}`
|
|
210
|
-
});
|
|
211
|
-
await harness.close();
|
|
212
|
-
out(twinReadyLine((Date.now() - warmupStart) / 1e3));
|
|
213
|
-
}
|
|
214
|
-
out(trialsHeaderLine(trials, DEMO_TASK_NAME));
|
|
215
|
-
const agentCommand = options.agentCommand ?? defaultDemoAgentCommand(process.execPath, process.argv[1]);
|
|
216
|
-
const verdicts = [];
|
|
217
|
-
const collectedFailures = [];
|
|
218
|
-
const collectedReadings = [];
|
|
219
|
-
let capacityAbort = null;
|
|
220
|
-
for (let i = 0; i < trials; i += 1) {
|
|
221
|
-
const session = sessions[i];
|
|
222
|
-
const trialNumber = i + 1;
|
|
223
|
-
const client = trialClientFactory(session);
|
|
224
|
-
const progress = { finalized: false };
|
|
225
|
-
let verdict;
|
|
226
|
-
let abortCode = null;
|
|
227
|
-
try {
|
|
228
|
-
verdict = await runOneTrial({
|
|
229
|
-
trialNumber,
|
|
230
|
-
session,
|
|
231
|
-
taskPath,
|
|
232
|
-
agentCommand,
|
|
233
|
-
artifactsDir,
|
|
234
|
-
apiBase: options.apiBase,
|
|
235
|
-
runTaskFn,
|
|
236
|
-
client,
|
|
237
|
-
captureServerCommand: options.captureServerCommand,
|
|
238
|
-
out,
|
|
239
|
-
collectedFailures,
|
|
240
|
-
collectedReadings,
|
|
241
|
-
progress
|
|
242
|
-
});
|
|
243
|
-
} catch (err) {
|
|
244
|
-
if (err instanceof DemoCapacityError) {
|
|
245
|
-
abortCode = err.kind;
|
|
246
|
-
capacityAbort = capacityLabel(err.kind);
|
|
247
|
-
verdict = { kind: "errored", reason: "demo at capacity" };
|
|
248
|
-
} else if (isJudgeCapQuota(err)) {
|
|
249
|
-
abortCode = "daily_judge_cap";
|
|
250
|
-
capacityAbort = capacityLabel("daily_judge_cap");
|
|
251
|
-
verdict = { kind: "errored", reason: "demo at capacity" };
|
|
252
|
-
} else {
|
|
253
|
-
verdict = {
|
|
254
|
-
kind: "errored",
|
|
255
|
-
reason: shortReason(err instanceof Error ? err.message : String(err))
|
|
256
|
-
};
|
|
257
|
-
}
|
|
258
|
-
if (!progress.finalized) {
|
|
259
|
-
await abandonQuietly(client, session.session_id, abortCode ?? "trial_crashed");
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
verdicts.push(verdict);
|
|
263
|
-
out(trialLine(trialNumber, verdict));
|
|
264
|
-
if (capacityAbort) {
|
|
265
|
-
for (let j = i + 1; j < trials; j += 1) {
|
|
266
|
-
const orphan = sessions[j];
|
|
267
|
-
await abandonQuietly(
|
|
268
|
-
trialClientFactory(orphan),
|
|
269
|
-
orphan.session_id,
|
|
270
|
-
abortCode ?? "unknown_capacity"
|
|
271
|
-
);
|
|
272
|
-
}
|
|
273
|
-
break;
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
if (capacityAbort) out(capacityAbort);
|
|
277
|
-
const failing = mostCommonFailedCriterion(collectedFailures);
|
|
278
|
-
out("");
|
|
279
|
-
for (const line of summaryLines({
|
|
280
|
-
verdicts,
|
|
281
|
-
failingCriterionPhrase: failing?.phrase,
|
|
282
|
-
failingCriterionCount: failing?.count,
|
|
283
|
-
narrated: collectedReadings,
|
|
284
|
-
previewUrl: `${options.dashboardBase.replace(/\/$/, "")}/demo/${groupId}`
|
|
285
|
-
})) {
|
|
286
|
-
out(line);
|
|
287
|
-
}
|
|
288
|
-
const evaluated = verdicts.filter((v) => v.kind !== "errored").length;
|
|
289
|
-
const exitCode = evaluated > 0 ? 0 : capacityAbort ? 4 : 1;
|
|
290
|
-
return { exitCode, groupId, verdicts };
|
|
291
|
-
}
|
|
292
|
-
async function runOneTrial(input) {
|
|
293
|
-
const startedAt = Date.now();
|
|
294
|
-
const result = await input.runTaskFn({
|
|
295
|
-
taskPath: input.taskPath,
|
|
296
|
-
agentCommand: input.agentCommand,
|
|
297
|
-
artifactsDir: input.artifactsDir,
|
|
298
|
-
captureServerCommand: input.captureServerCommand,
|
|
299
|
-
extraAgentEnv: {
|
|
300
|
-
POME_DEMO_LLM_URL: `${input.apiBase}/v1/demo/sessions/${input.session.session_id}/llm`,
|
|
301
|
-
POME_DEMO_TOKEN: input.session.demo_token,
|
|
302
|
-
POME_DEMO_TASK_NAME: DEMO_TASK_NAME,
|
|
303
|
-
POME_DEMO_REPO: DEMO_REPO
|
|
304
|
-
},
|
|
305
|
-
egressExtraHosts: [new URL(input.apiBase).hostname]
|
|
306
|
-
});
|
|
307
|
-
const agentSeconds = (Date.now() - startedAt) / 1e3;
|
|
308
|
-
if (result.exitCode !== 0) {
|
|
309
|
-
const capacityKind = parseCapacityMarker(result.agent.stderr);
|
|
310
|
-
if (capacityKind) {
|
|
311
|
-
throw new DemoCapacityError(capacityKind, capacityLabel(capacityKind));
|
|
312
|
-
}
|
|
313
|
-
if (result.agent.timedOut) {
|
|
314
|
-
await abandonQuietly(input.client, input.session.session_id, "agent_timeout");
|
|
315
|
-
return { kind: "errored", reason: "trial timed out" };
|
|
316
|
-
}
|
|
317
|
-
await abandonQuietly(input.client, input.session.session_id, "agent_exit_nonzero");
|
|
318
|
-
return {
|
|
319
|
-
kind: "errored",
|
|
320
|
-
reason: shortReason(lastLine(result.agent.stderr) ?? "agent failed")
|
|
321
|
-
};
|
|
322
|
-
}
|
|
323
|
-
input.out(evaluatingLine(input.trialNumber));
|
|
324
|
-
const runDir = result.artifacts.runDir;
|
|
325
|
-
const [eventsJsonl, stateInitialJson, stateFinalJson, metaJson] = await Promise.all([
|
|
326
|
-
readFile(join(runDir, "events.jsonl"), "utf8"),
|
|
327
|
-
readFile(join(runDir, "state_initial.json"), "utf8"),
|
|
328
|
-
readFile(join(runDir, "state_final.json"), "utf8"),
|
|
329
|
-
// D18.1 — best-effort: a demo trial's verdict must never hinge on the
|
|
330
|
-
// meta.json sidecar being readable.
|
|
331
|
-
readFile(join(runDir, "meta.json"), "utf8").catch(() => "{}")
|
|
332
|
-
]);
|
|
333
|
-
const uploaded = await uploadRunBlobs(input.client, input.session.session_id, {
|
|
334
|
-
eventsJsonl,
|
|
335
|
-
stateInitialJson,
|
|
336
|
-
stateFinalJson,
|
|
337
|
-
signalsJsonl: "",
|
|
338
|
-
metaJson
|
|
339
|
-
});
|
|
340
|
-
const finalized = await input.client.finalize(input.session.session_id, {
|
|
341
|
-
stopReason: "completed",
|
|
342
|
-
exitCode: 0,
|
|
343
|
-
durationMs: Math.max(0, Math.round(agentSeconds * 1e3)),
|
|
344
|
-
agentModel: "demo-gateway",
|
|
345
|
-
agentSdk: null,
|
|
346
|
-
criteria: [],
|
|
347
|
-
taskName: DEMO_TASK_NAME,
|
|
348
|
-
taskHash: "",
|
|
349
|
-
taskPrompt: "",
|
|
350
|
-
expectedBehavior: "",
|
|
351
|
-
traceStorageKey: uploaded.eventsKey ?? void 0,
|
|
352
|
-
stateInitialStorageKey: uploaded.stateInitialKey ?? void 0,
|
|
353
|
-
stateFinalStorageKey: uploaded.stateFinalKey ?? void 0
|
|
354
|
-
});
|
|
355
|
-
input.progress.finalized = true;
|
|
356
|
-
const score = scoreFromFinalizeResponse(finalized);
|
|
357
|
-
const status = scoreStatus(score, 100);
|
|
358
|
-
const checks = { passed: score.passed, total: score.total_required };
|
|
359
|
-
if (status !== "incomplete") {
|
|
360
|
-
input.collectedReadings.push(...score.results.filter(isNarrated));
|
|
361
|
-
}
|
|
362
|
-
if (status === "pass") {
|
|
363
|
-
return { kind: "passed", seconds: agentSeconds, checks };
|
|
364
|
-
}
|
|
365
|
-
if (status === "fail") {
|
|
366
|
-
const failedResults = score.results.filter((r) => outcomeOf(r) === "failed");
|
|
367
|
-
for (const r of failedResults) input.collectedFailures.push(r.criterion.text);
|
|
368
|
-
const note = failedResults[0] ? criterionPhrase(failedResults[0].criterion.text) : "criterion not met";
|
|
369
|
-
return { kind: "failed", seconds: agentSeconds, note, checks };
|
|
370
|
-
}
|
|
371
|
-
return { kind: "errored", reason: "cloud could not evaluate the trace" };
|
|
372
|
-
}
|
|
373
|
-
async function abandonQuietly(client, sessionId, errorCode) {
|
|
374
|
-
try {
|
|
375
|
-
await client.abandonSession(sessionId, { errorCode });
|
|
376
|
-
} catch {
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
function isJudgeCapQuota(err) {
|
|
380
|
-
return err instanceof HostedQuotaError && capacityKindFrom(402, err.details?.kind) === "daily_judge_cap";
|
|
381
|
-
}
|
|
382
|
-
function mostCommonFailedCriterion(failures) {
|
|
383
|
-
if (failures.length === 0) return null;
|
|
384
|
-
const counts = /* @__PURE__ */ new Map();
|
|
385
|
-
for (const text2 of failures) {
|
|
386
|
-
counts.set(text2, (counts.get(text2) ?? 0) + 1);
|
|
387
|
-
}
|
|
388
|
-
const [text, count] = [...counts.entries()].sort((a, b) => b[1] - a[1])[0];
|
|
389
|
-
return { phrase: criterionPhrase(text), count };
|
|
390
|
-
}
|
|
391
|
-
function lastLine(text) {
|
|
392
|
-
const lines = text.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
|
|
393
|
-
return lines.length > 0 ? lines[lines.length - 1] : null;
|
|
394
|
-
}
|
|
395
|
-
function shortReason(reason) {
|
|
396
|
-
const flat = reason.replace(/\s+/g, " ").trim();
|
|
397
|
-
return flat.length > 72 ? `${flat.slice(0, 69)}\u2026` : flat;
|
|
398
|
-
}
|
|
399
|
-
function defaultDemoAgentCommand(execPath, scriptPath) {
|
|
400
|
-
if (!scriptPath || scriptPath.length === 0) {
|
|
401
|
-
throw new Error(
|
|
402
|
-
"Cannot determine the pome binary path for the demo agent (process.argv[1] is empty)."
|
|
403
|
-
);
|
|
404
|
-
}
|
|
405
|
-
return `"${execPath}" "${scriptPath}" demo-agent`;
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
export { defaultDemoAgentCommand, runDemo };
|