@pumped-fn/agent-sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,1281 @@
1
+ import { atom, flow, resource, tag, tags, typed } from "@pumped-fn/lite";
2
+ import { SuspendSignal, SuspenseSignal, extension as extension$1, formatSuspenseStepKey, stepCounter } from "@pumped-fn/lite-extension-suspense";
3
+ //#region src/index.ts
4
+ const step = tag({
5
+ label: "agent.step",
6
+ default: {}
7
+ });
8
+ const materialKind = tag({ label: "agent.materialKind" });
9
+ const workers = tag({ label: "agent.workerRegistry" });
10
+ var WorkerRegistry = class {
11
+ flows = /* @__PURE__ */ new Map();
12
+ register(flow, name = flow.name) {
13
+ if (!name) throw new Error("Worker flow must have a name");
14
+ this.flows.set(name, flow);
15
+ return this;
16
+ }
17
+ get(name) {
18
+ const found = this.flows.get(name);
19
+ if (!found) throw new Error(`Worker "${name}" not registered`);
20
+ return found;
21
+ }
22
+ list() {
23
+ return [...this.flows.keys()];
24
+ }
25
+ };
26
+ function workerRegistry(flows = []) {
27
+ const registry = new WorkerRegistry();
28
+ for (const workerFlow of flows) registry.register(workerFlow);
29
+ return registry;
30
+ }
31
+ function formatStepKey(key) {
32
+ return formatSuspenseStepKey(key);
33
+ }
34
+ const workflowRun = tag({ label: "workflow.run" });
35
+ const workflow = tag({ label: "workflow.runtime" });
36
+ const runtime = tag({ label: "agent.runtime" });
37
+ const abortSignal = tag({ label: "workflow.abortSignal" });
38
+ const activeWorkflowEvent = tag({ label: "workflow.event" });
39
+ async function delegateWorker(ctx, name, input) {
40
+ const registry = registryOf(ctx);
41
+ if (!registry) throw new Error("Worker registry not found");
42
+ const target = registry.get(name);
43
+ return ctx.exec({
44
+ flow: target,
45
+ input
46
+ });
47
+ }
48
+ function workflowExtension(options) {
49
+ const base = createWorkflowExtension({
50
+ name: "workflow",
51
+ options,
52
+ shouldHandle: shouldHandleWorkflowTarget,
53
+ run: (event, next) => runTimer(event.target, event.ctx, next)
54
+ });
55
+ return {
56
+ ...base,
57
+ async wrapExec(next, target, ctx) {
58
+ const wrapExec = base.wrapExec;
59
+ if (!wrapExec) return withRuntimeTag(ctx, workflow, workflowRuntimeOf(ctx, options), next);
60
+ return withRuntimeTag(ctx, workflow, workflowRuntimeOf(ctx, options), () => wrapExec(next, target, ctx));
61
+ }
62
+ };
63
+ }
64
+ function extension(options = {}) {
65
+ return {
66
+ name: "agent-sdk",
67
+ async wrapExec(next, target, ctx) {
68
+ return withRuntimeTag(ctx, runtime, runtimeOf(ctx), async () => {
69
+ if (stepOf(target, ctx).remote !== true) return next();
70
+ if (!options.remoteRunner) throw new Error("Remote step requires remoteRunner");
71
+ return options.remoteRunner.run(execEvent(target, ctx), next);
72
+ });
73
+ }
74
+ };
75
+ }
76
+ function createWorkflowExtension(options) {
77
+ return extension$1({
78
+ name: options.name,
79
+ log: options.options.log,
80
+ defaultTaskId: options.options.defaultTaskId,
81
+ defaultRunId: options.options.defaultRunId,
82
+ getKey: (ctx) => nextWorkflowKey(ctx, options.options),
83
+ shouldHandle: options.shouldHandle,
84
+ shouldSuspend: (event) => {
85
+ const config = stepOf(event.target, event.ctx);
86
+ return config.durable === true && config.remote !== true;
87
+ },
88
+ createPendingEntry: (event) => ({
89
+ status: "pending",
90
+ key: event.key,
91
+ targetName: event.targetName,
92
+ input: event.input,
93
+ kind: "durable"
94
+ }),
95
+ run: (event, next) => {
96
+ const previous = event.ctx.data.getTag(activeWorkflowEvent);
97
+ event.ctx.data.setTag(activeWorkflowEvent, event);
98
+ return options.run(event, next).finally(() => {
99
+ if (previous) event.ctx.data.setTag(activeWorkflowEvent, previous);
100
+ else event.ctx.data.deleteTag(activeWorkflowEvent);
101
+ });
102
+ }
103
+ });
104
+ }
105
+ function registryOf(ctx) {
106
+ return ctx.data.seekTag(workers);
107
+ }
108
+ function execEvent(target, ctx) {
109
+ return ctx.data.seekTag(activeWorkflowEvent) ?? {
110
+ target,
111
+ ctx,
112
+ targetName: targetNameOf(target, ctx),
113
+ input: ctx.input
114
+ };
115
+ }
116
+ function nextWorkflowKey(ctx, options) {
117
+ const config = ctx.data.seekTag(workflowRun);
118
+ const foundTaskId = config?.taskId ?? options.defaultTaskId ?? "default-task";
119
+ const foundRunId = config?.runId ?? options.defaultRunId ?? "default-run";
120
+ let counter = ctx.data.seekTag(stepCounter);
121
+ if (!counter) {
122
+ counter = { next: 0 };
123
+ rootContext(ctx).data.setTag(stepCounter, counter);
124
+ }
125
+ return {
126
+ taskId: foundTaskId,
127
+ runId: foundRunId,
128
+ step: counter.next++
129
+ };
130
+ }
131
+ function workflowRuntimeOf(ctx, options) {
132
+ const config = ctx.data.seekTag(workflowRun);
133
+ return {
134
+ taskId: config?.taskId ?? options.defaultTaskId ?? "default-task",
135
+ runId: config?.runId ?? options.defaultRunId ?? "default-run"
136
+ };
137
+ }
138
+ function runtimeOf(ctx) {
139
+ const config = ctx.data.seekTag(workflow);
140
+ if (!config) throw new Error("agent extension requires workflow extension");
141
+ return {
142
+ taskId: config.taskId,
143
+ runId: config.runId,
144
+ delegate: (name, input) => delegateWorker(ctx, name, input)
145
+ };
146
+ }
147
+ function withRuntimeTag(ctx, runtimeTag, value, next) {
148
+ const hadPrevious = ctx.data.hasTag(runtimeTag);
149
+ const previous = ctx.data.getTag(runtimeTag);
150
+ ctx.data.setTag(runtimeTag, value);
151
+ return next().finally(() => {
152
+ if (hadPrevious) ctx.data.setTag(runtimeTag, previous);
153
+ else ctx.data.deleteTag(runtimeTag);
154
+ });
155
+ }
156
+ function shouldHandleWorkflowTarget(target, ctx) {
157
+ const config = stepOf(target, ctx);
158
+ return config.workflow === true || config.durable === true || config.timeoutMs !== void 0;
159
+ }
160
+ function rootContext(ctx) {
161
+ let current = ctx;
162
+ while (current.parent) current = current.parent;
163
+ return current;
164
+ }
165
+ function targetNameOf(target, ctx) {
166
+ const name = ctx.name || target.name;
167
+ if (!name) throw new Error("Agent target must have a name");
168
+ return name;
169
+ }
170
+ function runTimer(target, ctx, next) {
171
+ const timeoutMs = stepOf(target, ctx).timeoutMs;
172
+ if (timeoutMs === void 0) return next();
173
+ const controller = new AbortController();
174
+ let timer;
175
+ return withRuntimeTag(ctx, abortSignal, controller.signal, () => Promise.race([next(), new Promise((_, reject) => {
176
+ timer = setTimeout(() => {
177
+ const error = /* @__PURE__ */ new Error(`Workflow step timed out after ${timeoutMs}ms`);
178
+ controller.abort(error);
179
+ reject(error);
180
+ }, timeoutMs);
181
+ })])).finally(() => {
182
+ if (timer) clearTimeout(timer);
183
+ });
184
+ }
185
+ function stepOf(target, ctx) {
186
+ return {
187
+ ...typeof target === "function" ? {} : step.find(target),
188
+ ...ctx.data.seekTag(step) ?? {}
189
+ };
190
+ }
191
+ const materialPatches = /* @__PURE__ */ new WeakMap();
192
+ var MaterialConflictError = class extends Error {
193
+ expectedRevision;
194
+ currentRevision;
195
+ name = "MaterialConflictError";
196
+ constructor(expectedRevision, currentRevision) {
197
+ super(`Material revision conflict: expected ${expectedRevision}, current ${currentRevision}`);
198
+ this.expectedRevision = expectedRevision;
199
+ this.currentRevision = currentRevision;
200
+ }
201
+ };
202
+ function material(name, options) {
203
+ return atom({
204
+ keepAlive: options.keepAlive ?? true,
205
+ tags: [materialKind(options.kind), ...options.tags ?? []],
206
+ factory: () => ({
207
+ name,
208
+ kind: options.kind,
209
+ revision: 0,
210
+ state: clone(options.initialState)
211
+ })
212
+ });
213
+ }
214
+ async function patchMaterial(ctx, target, ops, options = {}) {
215
+ return queueMaterialPatch(ctx, target, async () => {
216
+ const ctrl = ctx.scope.controller(target);
217
+ if (ctrl.state === "idle") await ctrl.resolve();
218
+ const current = ctrl.get();
219
+ if (current.kind !== "json") throw new Error(`Material "${current.name}" does not accept JSON Patch`);
220
+ if (options.expectedRevision !== void 0 && options.expectedRevision !== current.revision) throw new MaterialConflictError(options.expectedRevision, current.revision);
221
+ ctrl.set({
222
+ ...current,
223
+ revision: current.revision + 1,
224
+ state: applyJsonPatch(current.state, ops)
225
+ });
226
+ return ctrl.get();
227
+ });
228
+ }
229
+ function derivedMaterial(name, source, derive, options) {
230
+ return atom({
231
+ keepAlive: options.keepAlive ?? true,
232
+ deps: { source },
233
+ tags: [materialKind(options.kind), ...options.tags ?? []],
234
+ factory: (_ctx, deps) => ({
235
+ name,
236
+ kind: options.kind,
237
+ revision: deps.source.revision,
238
+ state: derive(deps.source.state)
239
+ })
240
+ });
241
+ }
242
+ function queueMaterialPatch(ctx, target, run) {
243
+ let scopePatches = materialPatches.get(ctx.scope);
244
+ if (!scopePatches) {
245
+ scopePatches = /* @__PURE__ */ new WeakMap();
246
+ materialPatches.set(ctx.scope, scopePatches);
247
+ }
248
+ const current = (scopePatches.get(target) ?? Promise.resolve()).catch(() => void 0).then(run);
249
+ const lock = current.then(() => void 0, () => void 0);
250
+ scopePatches.set(target, lock);
251
+ lock.then(() => {
252
+ if (scopePatches.get(target) === lock) scopePatches.delete(target);
253
+ });
254
+ return current;
255
+ }
256
+ function applyJsonPatch(source, ops) {
257
+ let document = clone(source);
258
+ for (const op of ops) {
259
+ if (op.path === "") {
260
+ if (op.op === "remove") document = null;
261
+ else document = clone(op.value);
262
+ continue;
263
+ }
264
+ const parts = splitPointer(op.path);
265
+ const key = parts.at(-1);
266
+ if (key === void 0) throw new Error("JSON Patch path cannot be empty");
267
+ const parent = findPatchParent(document, parts.slice(0, -1));
268
+ if (op.op === "remove") removeValue(parent, key);
269
+ else setValue(parent, key, clone(op.value), op.op);
270
+ }
271
+ return document;
272
+ }
273
+ function splitPointer(path) {
274
+ if (!path.startsWith("/")) throw new Error(`Invalid JSON Pointer "${path}"`);
275
+ return path.slice(1).split("/").map((part) => part.replace(/~1/g, "/").replace(/~0/g, "~"));
276
+ }
277
+ function findPatchParent(document, parts) {
278
+ let current = document;
279
+ for (const part of parts) {
280
+ if (Array.isArray(current)) {
281
+ current = current[Number(part)];
282
+ continue;
283
+ }
284
+ if (isRecord(current)) {
285
+ current = current[part];
286
+ continue;
287
+ }
288
+ throw new Error(`Cannot traverse JSON Patch path at "${part}"`);
289
+ }
290
+ return current;
291
+ }
292
+ function setValue(parent, key, value, op) {
293
+ if (Array.isArray(parent)) {
294
+ if (key === "-") {
295
+ parent.push(value);
296
+ return;
297
+ }
298
+ const index = Number(key);
299
+ if (op === "add") parent.splice(index, 0, value);
300
+ else parent[index] = value;
301
+ return;
302
+ }
303
+ if (!isRecord(parent)) throw new Error(`Cannot set JSON Patch path "${key}"`);
304
+ parent[key] = value;
305
+ }
306
+ function removeValue(parent, key) {
307
+ if (Array.isArray(parent)) {
308
+ parent.splice(Number(key), 1);
309
+ return;
310
+ }
311
+ if (!isRecord(parent)) throw new Error(`Cannot remove JSON Patch path "${key}"`);
312
+ delete parent[key];
313
+ }
314
+ function isRecord(value) {
315
+ return typeof value === "object" && value !== null && !Array.isArray(value);
316
+ }
317
+ function clone(value) {
318
+ return structuredClone(value);
319
+ }
320
+ var CliWorkerError = class extends Error {
321
+ result;
322
+ name = "CliWorkerError";
323
+ constructor(message, result) {
324
+ super(message);
325
+ this.result = result;
326
+ }
327
+ };
328
+ function cliWorker(options) {
329
+ const config = { kind: options.kind ?? "cli" };
330
+ if (options.timeoutMs !== void 0) config.timeoutMs = options.timeoutMs;
331
+ const tags = [step(config), ...options.tags ?? []];
332
+ const factory = async (ctx) => {
333
+ const input = ctx.input;
334
+ const result = await runCli({
335
+ command: resolveRequiredValue(options.command, input, ctx),
336
+ args: resolveValue(options.args ?? [], input, ctx),
337
+ stdin: resolveValue(options.stdin, input, ctx),
338
+ cwd: resolveValue(options.cwd, input, ctx),
339
+ env: resolveValue(options.env, input, ctx),
340
+ isolate: resolveValue(options.isolate, input, ctx),
341
+ timeoutMs: options.timeoutMs,
342
+ signal: ctx.data.seekTag(abortSignal)
343
+ });
344
+ return options.parseOutput ? options.parseOutput(result, input) : result.stdout.trim();
345
+ };
346
+ const flowOptions = {
347
+ name: options.name,
348
+ tags,
349
+ factory
350
+ };
351
+ return typeof options.parse === "function" ? flow({
352
+ ...flowOptions,
353
+ parse: options.parse
354
+ }) : flow({
355
+ ...flowOptions,
356
+ parse: options.parse ?? typed()
357
+ });
358
+ }
359
+ async function runCli(options) {
360
+ const { execFile } = await import("node:child_process");
361
+ const prepared = await prepareCli(options);
362
+ return new Promise((resolve, reject) => {
363
+ execFile(prepared.command, [...prepared.args], {
364
+ cwd: prepared.cwd,
365
+ env: prepared.env,
366
+ timeout: options.timeoutMs,
367
+ signal: options.signal
368
+ }, async (error, stdout, stderr) => {
369
+ await prepared.cleanup();
370
+ const execError = error;
371
+ const exitCode = typeof execError?.code === "number" ? execError.code : error ? null : 0;
372
+ const signal = execError?.signal ?? null;
373
+ const result = {
374
+ stdout: String(stdout),
375
+ stderr: String(stderr),
376
+ exitCode,
377
+ signal
378
+ };
379
+ if (execError?.killed && options.timeoutMs !== void 0) {
380
+ reject(new CliWorkerError(`CLI command timed out after ${options.timeoutMs}ms`, result));
381
+ return;
382
+ }
383
+ if (execError?.name === "AbortError") {
384
+ reject(new CliWorkerError("CLI command aborted", result));
385
+ return;
386
+ }
387
+ if (error) {
388
+ reject(new CliWorkerError(exitCode === null ? error.message : `CLI command failed with exit code ${exitCode}`, result));
389
+ return;
390
+ }
391
+ resolve(result);
392
+ }).stdin?.end(options.stdin);
393
+ });
394
+ }
395
+ async function prepareCli(options) {
396
+ if (!options.isolate) return {
397
+ command: options.command,
398
+ args: options.args ?? [],
399
+ cwd: options.cwd,
400
+ env: {
401
+ ...process.env,
402
+ ...options.env
403
+ },
404
+ cleanup: async () => void 0
405
+ };
406
+ return prepareIsolatedCli(options, typeof options.isolate === "boolean" ? {} : options.isolate);
407
+ }
408
+ async function prepareIsolatedCli(options, isolate) {
409
+ const { mkdtemp, rm, realpath } = await import("node:fs/promises");
410
+ const { existsSync } = await import("node:fs");
411
+ const { dirname, join, resolve } = await import("node:path");
412
+ const { tmpdir } = await import("node:os");
413
+ const hostCwd = resolve(options.cwd ?? process.cwd());
414
+ const workdir = isolate.workdir ?? "/workspace";
415
+ const tempDirs = [];
416
+ const home = isolate.home ?? await mkdtemp(join(tmpdir(), "pumped-fn-home-"));
417
+ if (!isolate.home) tempDirs.push(home);
418
+ const binds = /* @__PURE__ */ new Map();
419
+ addBind(binds, hostCwd, workdir, isolate.writable === true ? "rw" : "ro");
420
+ addBind(binds, home, "/home/agent", "rw");
421
+ if (isolate.codexHome) addBind(binds, isolate.codexHome, "/codex-home", "rw");
422
+ const commandPath = await commandPathOf(options.command, process.env["PATH"] ?? "", existsSync, realpath);
423
+ const nodePath = await realpath(process.execPath);
424
+ for (const dir of defaultCliDirs(existsSync)) addBind(binds, dir, dir, "ro");
425
+ for (const dir of defaultCliCertDirs(existsSync)) addBind(binds, dir, dir, "ro");
426
+ for (const file of defaultCliFiles(existsSync)) addBind(binds, file, file, "ro");
427
+ if (commandPath) {
428
+ addBind(binds, dirname(commandPath), dirname(commandPath), "ro");
429
+ addBind(binds, dirname(dirname(commandPath)), dirname(dirname(commandPath)), "ro");
430
+ }
431
+ addBind(binds, dirname(nodePath), dirname(nodePath), "ro");
432
+ addBind(binds, dirname(dirname(nodePath)), dirname(dirname(nodePath)), "ro");
433
+ for (const bind of isolate.bind ?? []) addBind(binds, bind.source, bind.target ?? bind.source, bind.mode ?? "ro");
434
+ const env = {
435
+ PATH: isolatedPathEnv(commandPath, nodePath, dirname),
436
+ HOME: "/home/agent",
437
+ TMPDIR: "/tmp",
438
+ ...isolate.codexHome ? { CODEX_HOME: "/codex-home" } : {},
439
+ ...options.env,
440
+ ...isolate.env
441
+ };
442
+ return {
443
+ command: isolate.bwrap ?? "bwrap",
444
+ args: [
445
+ "--die-with-parent",
446
+ "--unshare-all",
447
+ ...isolate.network === true ? ["--share-net"] : [],
448
+ "--proc",
449
+ "/proc",
450
+ "--dev",
451
+ "/dev",
452
+ "--tmpfs",
453
+ "/tmp",
454
+ "--dir",
455
+ "/etc",
456
+ "--dir",
457
+ "/home",
458
+ ...Object.entries(env).flatMap(([key, value]) => value === void 0 ? [] : [
459
+ "--setenv",
460
+ key,
461
+ value
462
+ ]),
463
+ ...[...binds.values()].flatMap((bind) => [
464
+ bind.mode === "rw" ? "--bind" : "--ro-bind",
465
+ bind.source,
466
+ bind.target
467
+ ]),
468
+ "--chdir",
469
+ workdir,
470
+ "--",
471
+ commandPath ?? options.command,
472
+ ...options.args ?? []
473
+ ],
474
+ env: { PATH: process.env["PATH"] },
475
+ cleanup: async () => {
476
+ await Promise.all(tempDirs.map((dir) => rm(dir, {
477
+ recursive: true,
478
+ force: true
479
+ })));
480
+ }
481
+ };
482
+ }
483
+ function addBind(binds, source, target, mode) {
484
+ binds.set(`${source}\u0000${target}`, {
485
+ source,
486
+ target,
487
+ mode
488
+ });
489
+ }
490
+ function defaultCliDirs(exists) {
491
+ return [
492
+ "/usr/bin",
493
+ "/bin",
494
+ "/usr/lib",
495
+ "/usr/lib64",
496
+ "/lib",
497
+ "/lib64"
498
+ ].filter((path, index, items) => items.indexOf(path) === index && exists(path));
499
+ }
500
+ function defaultCliCertDirs(exists) {
501
+ return [
502
+ "/etc/ssl",
503
+ "/etc/pki",
504
+ "/etc/ca-certificates",
505
+ "/usr/share/ca-certificates",
506
+ "/usr/local/share/ca-certificates"
507
+ ].filter((path, index, items) => items.indexOf(path) === index && exists(path));
508
+ }
509
+ function defaultCliFiles(exists) {
510
+ return ["/etc/hosts", "/etc/resolv.conf"].filter((path, index, items) => items.indexOf(path) === index && exists(path));
511
+ }
512
+ function isolatedPathEnv(commandPath, nodePath, dirname) {
513
+ return [
514
+ commandPath ? dirname(commandPath) : void 0,
515
+ dirname(nodePath),
516
+ "/usr/bin",
517
+ "/bin"
518
+ ].filter((path, index, items) => path !== void 0 && items.indexOf(path) === index).join(":");
519
+ }
520
+ async function commandPathOf(command, pathEnv, exists, realpath) {
521
+ if (command.includes("/")) return realpath(command);
522
+ const found = pathEnv.split(":").filter(Boolean).map((dir) => `${dir}/${command}`).find((path) => exists(path));
523
+ return found ? realpath(found) : void 0;
524
+ }
525
+ function resolveValue(value, input, ctx) {
526
+ if (typeof value === "function") return value(input, ctx);
527
+ return value;
528
+ }
529
+ function resolveRequiredValue(value, input, ctx) {
530
+ if (typeof value === "function") return value(input, ctx);
531
+ return value;
532
+ }
533
+ function guard(name, text = "") {
534
+ return material(name, {
535
+ kind: "json",
536
+ initialState: { text }
537
+ });
538
+ }
539
+ function claudeCliWorker(options = {}) {
540
+ assertNoClaudeBare(options.extraArgs ?? []);
541
+ return cliWorker({
542
+ name: options.name ?? "claude",
543
+ command: options.command ?? "claude",
544
+ args: (input) => cliPromptArgs(["-p", ...options.extraArgs ?? []], input.prompt),
545
+ isolate: options.isolate,
546
+ timeoutMs: options.timeoutMs,
547
+ kind: "llm",
548
+ tags: options.tags
549
+ });
550
+ }
551
+ function codexCliWorker(options = {}) {
552
+ return cliWorker({
553
+ name: options.name ?? "codex",
554
+ command: options.command ?? "codex",
555
+ args: (input) => cliPromptArgs([
556
+ "exec",
557
+ "-s",
558
+ options.sandbox ?? "read-only",
559
+ ...options.extraArgs ?? []
560
+ ], input.prompt),
561
+ isolate: options.isolate,
562
+ timeoutMs: options.timeoutMs,
563
+ kind: "llm",
564
+ tags: options.tags
565
+ });
566
+ }
567
+ function claudeHarness(options = {}) {
568
+ return cliHarnessModel(claudeCliWorker({
569
+ name: options.name ?? "claude-harness",
570
+ command: options.command,
571
+ extraArgs: ["--no-session-persistence", ...options.extraArgs ?? []],
572
+ isolate: options.isolate ?? { network: true },
573
+ timeoutMs: options.timeoutMs,
574
+ tags: options.tags
575
+ }), {
576
+ guard: options.guard === void 0 ? guard(`${options.name ?? "claude-harness"}-guard`) : options.guard,
577
+ prompt: options.prompt,
578
+ parse: options.parse
579
+ });
580
+ }
581
+ function codexHarness(options = {}) {
582
+ return cliHarnessModel(codexCliWorker({
583
+ name: options.name ?? "codex-harness",
584
+ command: options.command,
585
+ sandbox: options.sandbox,
586
+ extraArgs: [
587
+ "--ephemeral",
588
+ "--ignore-user-config",
589
+ ...options.extraArgs ?? []
590
+ ],
591
+ isolate: options.isolate ?? { network: true },
592
+ timeoutMs: options.timeoutMs,
593
+ tags: options.tags
594
+ }), {
595
+ guard: options.guard === void 0 ? guard(`${options.name ?? "codex-harness"}-guard`) : options.guard,
596
+ prompt: options.prompt,
597
+ parse: options.parse
598
+ });
599
+ }
600
+ function cliHarnessModel(worker, config) {
601
+ return { complete: async (ctx, request) => {
602
+ const current = config.guard ? await ctx.resolve(config.guard) : void 0;
603
+ const state = current?.state ?? { text: "" };
604
+ const output = await ctx.exec({
605
+ flow: worker,
606
+ input: { prompt: config.prompt ? config.prompt(request, state) : modelPrompt(request, state) }
607
+ });
608
+ const response = config.parse ? config.parse(output) : parseModelOutput(output);
609
+ if (config.guard && current) await collectGuard(ctx, config.guard, current, response);
610
+ return response;
611
+ } };
612
+ }
613
+ async function collectGuard(ctx, store, current, response) {
614
+ const text = guardTextOf(response.guard);
615
+ if (!text || current.state.text) return;
616
+ await patchMaterial(ctx, store, [{
617
+ op: "replace",
618
+ path: "/text",
619
+ value: text
620
+ }], { expectedRevision: current.revision });
621
+ }
622
+ function modelPrompt(request, guard) {
623
+ return [
624
+ "Return JSON only.",
625
+ "Schema: {\"content\":string,\"stop\"?:boolean,\"guard\"?:string,\"skillCalls\"?:array,\"toolCalls\"?:array,\"subagentCalls\"?:array}.",
626
+ guard.text ? `Guard:\n${guard.text}` : "First run only: set guard to the anti-goal that should prevent this agent from drifting.",
627
+ `Agent: ${request.agentName}`,
628
+ request.instructions ? `Instructions:\n${request.instructions}` : void 0,
629
+ request.skills.length ? `Available skills:\n${request.skills.map(formatCapability).join("\n")}` : void 0,
630
+ request.loadedSkills.length ? `Loaded skills:\n${request.loadedSkills.map(formatLoadedSkill).join("\n\n")}` : void 0,
631
+ request.tools.length ? `Available tools:\n${request.tools.map(formatCapability).join("\n")}` : void 0,
632
+ request.subagents.length ? `Available subagents:\n${request.subagents.map(formatCapability).join("\n")}` : void 0,
633
+ `Round: ${request.round}`,
634
+ `Messages:\n${request.messages.map(formatMessage).join("\n")}`
635
+ ].filter((item) => item !== void 0).join("\n\n");
636
+ }
637
+ function parseModelOutput(output) {
638
+ const value = readJson(output);
639
+ if (!isRecord(value)) return {
640
+ content: output,
641
+ stop: true
642
+ };
643
+ const response = {
644
+ content: typeof value["content"] === "string" ? value["content"] : output,
645
+ stop: typeof value["stop"] === "boolean" ? value["stop"] : true
646
+ };
647
+ const guard = guardTextOf(value["guard"] ?? value["antiGoal"]);
648
+ const skillCalls = skillCallsOf(value["skillCalls"]);
649
+ const toolCalls = toolCallsOf(value["toolCalls"]);
650
+ const subagentCalls = subagentCallsOf(value["subagentCalls"]);
651
+ if (guard) response.guard = guard;
652
+ if (skillCalls) response.skillCalls = skillCalls;
653
+ if (toolCalls) response.toolCalls = toolCalls;
654
+ if (subagentCalls) response.subagentCalls = subagentCalls;
655
+ return response;
656
+ }
657
+ function readJson(output) {
658
+ const trimmed = output.trim();
659
+ if (!trimmed) return void 0;
660
+ try {
661
+ return JSON.parse(trimmed);
662
+ } catch {
663
+ const start = trimmed.indexOf("{");
664
+ const end = trimmed.lastIndexOf("}");
665
+ if (start === -1 || end <= start) return void 0;
666
+ try {
667
+ return JSON.parse(trimmed.slice(start, end + 1));
668
+ } catch {
669
+ return;
670
+ }
671
+ }
672
+ }
673
+ function skillCallsOf(value) {
674
+ if (!Array.isArray(value)) return void 0;
675
+ const calls = value.flatMap((item) => {
676
+ if (!isRecord(item) || typeof item["name"] !== "string") return [];
677
+ return [{
678
+ name: item["name"],
679
+ ...typeof item["id"] === "string" ? { id: item["id"] } : {}
680
+ }];
681
+ });
682
+ return calls.length ? calls : void 0;
683
+ }
684
+ function toolCallsOf(value) {
685
+ if (!Array.isArray(value)) return void 0;
686
+ const calls = value.flatMap((item) => {
687
+ if (!isRecord(item) || typeof item["name"] !== "string") return [];
688
+ return [{
689
+ name: item["name"],
690
+ input: item["input"],
691
+ ...typeof item["id"] === "string" ? { id: item["id"] } : {}
692
+ }];
693
+ });
694
+ return calls.length ? calls : void 0;
695
+ }
696
+ function subagentCallsOf(value) {
697
+ if (!Array.isArray(value)) return void 0;
698
+ const calls = value.flatMap((item) => {
699
+ if (!isRecord(item) || typeof item["name"] !== "string") return [];
700
+ return [{
701
+ name: item["name"],
702
+ input: turnInputOf(item["input"]),
703
+ ...typeof item["id"] === "string" ? { id: item["id"] } : {}
704
+ }];
705
+ });
706
+ return calls.length ? calls : void 0;
707
+ }
708
+ function turnInputOf(value) {
709
+ if (isRecord(value)) return value;
710
+ return { prompt: stringifyAgentValue(value) };
711
+ }
712
+ function guardTextOf(value) {
713
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
714
+ }
715
+ function formatCapability(capability) {
716
+ return `- ${capability.name}: ${capability.description}`;
717
+ }
718
+ function formatLoadedSkill(skill) {
719
+ return `## ${skill.name}\n${skill.content}`;
720
+ }
721
+ function formatMessage(message) {
722
+ return message.name ? `${message.role}(${message.name}): ${message.content}` : `${message.role}: ${message.content}`;
723
+ }
724
+ function assertNoClaudeBare(args) {
725
+ if (args.some((arg) => arg === "--bare" || arg.startsWith("--bare="))) throw new Error("Claude harness must not use --bare");
726
+ }
727
+ function cliPromptArgs(args, prompt) {
728
+ if (args.includes("--")) throw new Error("CLI helper extraArgs cannot include --");
729
+ return [
730
+ ...args,
731
+ "--",
732
+ prompt
733
+ ];
734
+ }
735
+ const events = resource({
736
+ name: "agent.events",
737
+ ownership: "boundary",
738
+ factory: () => {
739
+ let next = 0;
740
+ const events = [];
741
+ return {
742
+ get events() {
743
+ return events;
744
+ },
745
+ record(event) {
746
+ const stored = {
747
+ ...event,
748
+ index: next++
749
+ };
750
+ events.push(stored);
751
+ return stored;
752
+ }
753
+ };
754
+ }
755
+ });
756
+ const model = tag({ label: "agent.model" });
757
+ const sandbox = tag({ label: "agent.sandbox" });
758
+ function session(name, options = {}) {
759
+ return material(name, {
760
+ kind: "json",
761
+ initialState: { messages: options.messages ?? [] },
762
+ tags: options.tags,
763
+ keepAlive: options.keepAlive
764
+ });
765
+ }
766
+ function tool(options) {
767
+ const name = options.name ?? options.flow.name;
768
+ if (!name) throw new Error("Agent tool requires a name");
769
+ return {
770
+ name,
771
+ description: options.description,
772
+ flow: options.flow
773
+ };
774
+ }
775
+ function skill(options) {
776
+ if (options.load) return {
777
+ name: options.name,
778
+ description: options.description,
779
+ load: options.load
780
+ };
781
+ const content = options.content ?? "";
782
+ return {
783
+ name: options.name,
784
+ description: options.description,
785
+ load: () => content
786
+ };
787
+ }
788
+ function sub(options) {
789
+ return {
790
+ name: options.name ?? options.agent.name,
791
+ description: options.description,
792
+ agent: options.agent
793
+ };
794
+ }
795
+ function agent(options) {
796
+ const tools = options.tools ?? [];
797
+ const skills = options.skills ?? [];
798
+ const subagents = options.subagents ?? [];
799
+ const maxRounds = options.maxRounds ?? 4;
800
+ let agent;
801
+ const turn = flow({
802
+ name: options.name,
803
+ parse: typed(),
804
+ deps: { model: tags.required(model) },
805
+ tags: agentStepTags({
806
+ workflow: true,
807
+ kind: "agent"
808
+ }, options.tags),
809
+ factory: (ctx, deps) => executeAgentTurn(ctx, agent, deps.model)
810
+ });
811
+ agent = {
812
+ name: options.name,
813
+ description: options.description,
814
+ instructions: options.instructions ?? "",
815
+ tools,
816
+ skills,
817
+ subagents,
818
+ turn,
819
+ maxRounds
820
+ };
821
+ return agent;
822
+ }
823
+ function execTurn(ctx, agent, input, tags = []) {
824
+ return ctx.exec({
825
+ flow: agent.turn,
826
+ input,
827
+ name: agent.name,
828
+ tags: [...tags]
829
+ });
830
+ }
831
+ async function send(ctx, session, agent, input) {
832
+ const current = await ctx.resolve(session);
833
+ const result = await execTurn(ctx, agent, {
834
+ ...input,
835
+ messages: [...current.state.messages, ...input.messages ?? []]
836
+ });
837
+ await patchMaterial(ctx, session, [{
838
+ op: "replace",
839
+ path: "/messages",
840
+ value: serializeMessages(result.messages)
841
+ }], { expectedRevision: current.revision });
842
+ return result;
843
+ }
844
+ function channel(options) {
845
+ const flowOptions = {
846
+ name: options.name,
847
+ tags: agentStepTags({
848
+ workflow: true,
849
+ kind: "channel"
850
+ }, options.tags),
851
+ factory: async (ctx) => execTurn(ctx, options.agent, await options.input(ctx))
852
+ };
853
+ return typeof options.parse === "function" ? flow({
854
+ ...flowOptions,
855
+ parse: options.parse
856
+ }) : flow({
857
+ ...flowOptions,
858
+ parse: options.parse
859
+ });
860
+ }
861
+ function schedule(options) {
862
+ return flow({
863
+ name: options.name,
864
+ tags: agentStepTags({
865
+ workflow: true,
866
+ kind: "schedule"
867
+ }, options.tags),
868
+ factory: async (ctx) => execTurn(ctx, options.agent, await options.input(ctx))
869
+ });
870
+ }
871
+ function judge(options) {
872
+ return options;
873
+ }
874
+ function suite(options) {
875
+ const judges = options.judges ?? [];
876
+ assertJudgeQuorum(judges);
877
+ return {
878
+ name: options.name,
879
+ agent: options.agent,
880
+ cases: options.cases,
881
+ judges
882
+ };
883
+ }
884
+ function includes(text) {
885
+ return (result) => ({
886
+ name: `output includes "${text}"`,
887
+ passed: result.content.includes(text)
888
+ });
889
+ }
890
+ function used(name) {
891
+ return (result) => ({
892
+ name: `tool used "${name}"`,
893
+ passed: result.toolResults.some((call) => call.name === name)
894
+ });
895
+ }
896
+ function loaded(name) {
897
+ return (result) => ({
898
+ name: `skill loaded "${name}"`,
899
+ passed: result.skillResults.some((call) => call.name === name)
900
+ });
901
+ }
902
+ function delegated(name) {
903
+ return (result) => ({
904
+ name: `subagent used "${name}"`,
905
+ passed: result.subagentResults.some((call) => call.name === name)
906
+ });
907
+ }
908
+ async function runEval(ctx, target) {
909
+ assertJudgeQuorum(target.judges);
910
+ const cases = [];
911
+ for (const item of target.cases) {
912
+ const result = await execTurn(ctx, target.agent, item.input);
913
+ const checks = await runEvalChecks(result, item.checks ?? []);
914
+ const judges = await runEvalJudges(ctx, result, target.judges);
915
+ cases.push({
916
+ name: item.name,
917
+ result,
918
+ checks,
919
+ judges,
920
+ passed: checks.every((check) => check.passed) && judges.every((judge) => judge.passed)
921
+ });
922
+ }
923
+ return {
924
+ name: target.name,
925
+ cases,
926
+ passed: cases.every((item) => item.passed)
927
+ };
928
+ }
929
+ async function inspect(log, query) {
930
+ const entries = (await log.entries(query)).filter((entry) => entry.key.taskId === query.taskId && entry.key.runId === query.runId);
931
+ if (!entries[0]) throw new Error("Run not found");
932
+ const steps = entries.map(runStep);
933
+ return {
934
+ taskId: query.taskId,
935
+ runId: query.runId,
936
+ status: steps.some((item) => item.status === "pending") ? "pending" : "completed",
937
+ steps
938
+ };
939
+ }
940
+ function summary(report) {
941
+ return jsonValue({
942
+ name: report.name,
943
+ passed: report.passed,
944
+ cases: report.cases.map((item) => ({
945
+ name: item.name,
946
+ passed: item.passed,
947
+ output: item.result.content,
948
+ checks: item.checks,
949
+ judges: item.judges,
950
+ tools: item.result.toolResults.map((call) => ({
951
+ name: call.name,
952
+ output: call.output
953
+ })),
954
+ skills: item.result.skillResults.map((call) => ({ name: call.name })),
955
+ subagents: item.result.subagentResults.map((call) => ({
956
+ name: call.name,
957
+ output: call.output.content
958
+ })),
959
+ events: item.result.events.map((event) => ({
960
+ type: event.type,
961
+ agentName: event.agentName,
962
+ targetName: event.targetName,
963
+ round: event.round
964
+ }))
965
+ }))
966
+ });
967
+ }
968
+ function http(options) {
969
+ return flow({
970
+ name: options.name ?? `${options.agent.name}-http`,
971
+ parse: typed(),
972
+ tags: agentStepTags({
973
+ workflow: true,
974
+ kind: "channel"
975
+ }),
976
+ factory: async (ctx) => {
977
+ const request = ctx.input;
978
+ const input = options.input ? await options.input(request) : await request.json();
979
+ const tags = options.tags ? await options.tags(request) : [];
980
+ return Response.json(jsonValue(await execTurn(ctx, options.agent, input, tags)));
981
+ }
982
+ });
983
+ }
984
+ async function executeAgentTurn(ctx, agent, model) {
985
+ const messages = initialMessages(ctx.input);
986
+ const loadedSkills = [];
987
+ const skillResults = [];
988
+ const toolResults = [];
989
+ const subagentResults = [];
990
+ const maxRounds = ctx.input.maxRounds ?? agent.maxRounds;
991
+ let content = "";
992
+ let rounds = 0;
993
+ const startIndex = (await ctx.resolve(events)).events.length;
994
+ await recordAgentEvent(ctx, {
995
+ type: "agent_start",
996
+ agentName: agent.name,
997
+ input: ctx.input
998
+ });
999
+ for (let round = 0; round < maxRounds; round++) {
1000
+ rounds = round + 1;
1001
+ await recordAgentEvent(ctx, {
1002
+ type: "agent_model_start",
1003
+ agentName: agent.name,
1004
+ round,
1005
+ input: messages
1006
+ });
1007
+ const response = await model.complete(ctx, {
1008
+ agentName: agent.name,
1009
+ instructions: agent.instructions,
1010
+ messages,
1011
+ tools: agent.tools.map(agentToolCapability),
1012
+ skills: agent.skills.map(agentSkillCapability),
1013
+ loadedSkills,
1014
+ subagents: agent.subagents.map(agentSubagentCapability),
1015
+ round
1016
+ });
1017
+ content = response.content;
1018
+ await recordAgentEvent(ctx, {
1019
+ type: "agent_model_end",
1020
+ agentName: agent.name,
1021
+ round,
1022
+ output: response
1023
+ });
1024
+ const skillCalls = response.skillCalls ?? [];
1025
+ const toolCalls = response.toolCalls ?? [];
1026
+ const subagentCalls = response.subagentCalls ?? [];
1027
+ if (response.content) messages.push({
1028
+ role: "assistant",
1029
+ content: response.content
1030
+ });
1031
+ if (response.stop === true || skillCalls.length === 0 && toolCalls.length === 0 && subagentCalls.length === 0) break;
1032
+ for (const call of skillCalls) {
1033
+ const result = await executeAgentSkill(ctx, agent, call);
1034
+ loadedSkills.push({
1035
+ name: result.name,
1036
+ content: result.content,
1037
+ description: findByName(agent.skills, result.name, "skill").description
1038
+ });
1039
+ skillResults.push(result);
1040
+ messages.push({
1041
+ role: "skill",
1042
+ name: result.name,
1043
+ content: result.content
1044
+ });
1045
+ }
1046
+ for (const call of toolCalls) {
1047
+ const result = await executeAgentTool(ctx, agent, call);
1048
+ toolResults.push(result);
1049
+ messages.push({
1050
+ role: "tool",
1051
+ name: result.name,
1052
+ content: stringifyAgentValue(result.output)
1053
+ });
1054
+ }
1055
+ for (const call of subagentCalls) {
1056
+ const result = await executeAgentSubagent(ctx, agent, call);
1057
+ subagentResults.push(result);
1058
+ messages.push({
1059
+ role: "subagent",
1060
+ name: result.name,
1061
+ content: result.output.content
1062
+ });
1063
+ }
1064
+ }
1065
+ await recordAgentEvent(ctx, {
1066
+ type: "agent_end",
1067
+ agentName: agent.name,
1068
+ output: content
1069
+ });
1070
+ const buffer = await ctx.resolve(events);
1071
+ return {
1072
+ agentName: agent.name,
1073
+ content,
1074
+ messages,
1075
+ skillResults,
1076
+ toolResults,
1077
+ subagentResults,
1078
+ rounds,
1079
+ events: buffer.events.slice(startIndex)
1080
+ };
1081
+ }
1082
+ async function executeAgentSkill(ctx, agent, call) {
1083
+ const target = findByName(agent.skills, call.name, "skill");
1084
+ await recordAgentEvent(ctx, {
1085
+ type: "agent_skill_start",
1086
+ agentName: agent.name,
1087
+ targetName: target.name
1088
+ });
1089
+ const content = await ctx.exec({
1090
+ fn: (skillCtx) => target.load(skillCtx),
1091
+ params: [],
1092
+ name: target.name,
1093
+ tags: [agentStepTag({
1094
+ workflow: true,
1095
+ kind: "skill"
1096
+ })]
1097
+ });
1098
+ await recordAgentEvent(ctx, {
1099
+ type: "agent_skill_end",
1100
+ agentName: agent.name,
1101
+ targetName: target.name,
1102
+ output: content
1103
+ });
1104
+ return {
1105
+ name: target.name,
1106
+ id: call.id,
1107
+ content
1108
+ };
1109
+ }
1110
+ async function executeAgentTool(ctx, agent, call) {
1111
+ const target = findByName(agent.tools, call.name, "tool");
1112
+ await recordAgentEvent(ctx, {
1113
+ type: "agent_tool_start",
1114
+ agentName: agent.name,
1115
+ targetName: target.name,
1116
+ input: call.input
1117
+ });
1118
+ const output = await ctx.exec({
1119
+ flow: target.flow,
1120
+ rawInput: call.input,
1121
+ name: target.name,
1122
+ tags: [agentStepTag({
1123
+ workflow: true,
1124
+ kind: "tool"
1125
+ }, target.flow.tags)]
1126
+ });
1127
+ await recordAgentEvent(ctx, {
1128
+ type: "agent_tool_end",
1129
+ agentName: agent.name,
1130
+ targetName: target.name,
1131
+ output
1132
+ });
1133
+ return {
1134
+ name: target.name,
1135
+ id: call.id,
1136
+ input: call.input,
1137
+ output
1138
+ };
1139
+ }
1140
+ async function executeAgentSubagent(ctx, agent, call) {
1141
+ const target = findByName(agent.subagents, call.name, "subagent");
1142
+ await recordAgentEvent(ctx, {
1143
+ type: "agent_subagent_start",
1144
+ agentName: agent.name,
1145
+ targetName: target.name,
1146
+ input: call.input
1147
+ });
1148
+ const output = await ctx.exec({
1149
+ flow: target.agent.turn,
1150
+ input: call.input,
1151
+ name: target.name,
1152
+ tags: [agentStepTag({
1153
+ workflow: true,
1154
+ kind: "subagent"
1155
+ }, target.agent.turn.tags)]
1156
+ });
1157
+ await recordAgentEvent(ctx, {
1158
+ type: "agent_subagent_end",
1159
+ agentName: agent.name,
1160
+ targetName: target.name,
1161
+ output
1162
+ });
1163
+ return {
1164
+ name: target.name,
1165
+ id: call.id,
1166
+ input: call.input,
1167
+ output
1168
+ };
1169
+ }
1170
+ async function recordAgentEvent(ctx, event) {
1171
+ return (await ctx.resolve(events)).record(event);
1172
+ }
1173
+ function initialMessages(input) {
1174
+ return [...input.messages ?? [], ...input.prompt ? [{
1175
+ role: "user",
1176
+ content: input.prompt
1177
+ }] : []];
1178
+ }
1179
+ function agentStepTags(defaults, source = []) {
1180
+ return [agentStepTag(defaults, source), ...source.filter((tagged) => tagged.key !== step.key)];
1181
+ }
1182
+ function agentStepTag(defaults, source = []) {
1183
+ return step(Object.assign({}, defaults, ...step.collect(source)));
1184
+ }
1185
+ function agentToolCapability(tool) {
1186
+ return {
1187
+ name: tool.name,
1188
+ description: tool.description
1189
+ };
1190
+ }
1191
+ function agentSkillCapability(skill) {
1192
+ return {
1193
+ name: skill.name,
1194
+ description: skill.description ?? ""
1195
+ };
1196
+ }
1197
+ function agentSubagentCapability(subagent) {
1198
+ return {
1199
+ name: subagent.name,
1200
+ description: subagent.description
1201
+ };
1202
+ }
1203
+ function findByName(items, name, kind) {
1204
+ const found = items.find((item) => item.name === name);
1205
+ if (!found) throw new Error(`Agent ${kind} "${name}" not found`);
1206
+ return found;
1207
+ }
1208
+ function runStep(entry) {
1209
+ if (entry.status === "pending") return {
1210
+ key: entry.key,
1211
+ status: entry.status,
1212
+ targetName: entry.targetName,
1213
+ input: entry.input,
1214
+ kind: entry.kind
1215
+ };
1216
+ if (entry.status === "resolved") return {
1217
+ key: entry.key,
1218
+ status: entry.status,
1219
+ targetName: entry.targetName,
1220
+ output: entry.value
1221
+ };
1222
+ return {
1223
+ key: entry.key,
1224
+ status: entry.status,
1225
+ targetName: entry.targetName,
1226
+ output: entry.result
1227
+ };
1228
+ }
1229
+ function stringifyAgentValue(value) {
1230
+ if (typeof value === "string") return value;
1231
+ if (value === void 0) return String(value);
1232
+ if (typeof value === "bigint" || typeof value === "symbol" || typeof value === "function") return String(value);
1233
+ const seen = /* @__PURE__ */ new WeakSet();
1234
+ return JSON.stringify(value, (_key, item) => {
1235
+ if (typeof item === "bigint" || typeof item === "symbol" || typeof item === "function") return String(item);
1236
+ if (typeof item === "object" && item !== null) {
1237
+ if (seen.has(item)) return "[Circular]";
1238
+ seen.add(item);
1239
+ }
1240
+ return item;
1241
+ }) ?? String(value);
1242
+ }
1243
+ function jsonValue(value, seen = /* @__PURE__ */ new WeakSet()) {
1244
+ if (value === null) return null;
1245
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
1246
+ if (value === void 0 || typeof value === "bigint" || typeof value === "symbol" || typeof value === "function") return String(value);
1247
+ if (Array.isArray(value)) return value.map((item) => jsonValue(item, seen));
1248
+ if (typeof value === "object") {
1249
+ if (seen.has(value)) return "[Circular]";
1250
+ seen.add(value);
1251
+ return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, jsonValue(item, seen)]));
1252
+ }
1253
+ return String(value);
1254
+ }
1255
+ function serializeMessages(messages) {
1256
+ return messages.map((message) => {
1257
+ const serialized = {
1258
+ role: message.role,
1259
+ content: message.content
1260
+ };
1261
+ if (message.name !== void 0) serialized["name"] = message.name;
1262
+ return serialized;
1263
+ });
1264
+ }
1265
+ async function runEvalChecks(result, checks) {
1266
+ const results = [];
1267
+ for (const check of checks) results.push(await check(result));
1268
+ return results;
1269
+ }
1270
+ function assertJudgeQuorum(judges) {
1271
+ if (judges.length === 1) throw new Error("Agent evals require zero judges or at least two judges");
1272
+ }
1273
+ async function runEvalJudges(ctx, result, judges) {
1274
+ const results = [];
1275
+ for (const judge of judges) results.push(await judge.evaluate(ctx, result));
1276
+ return results;
1277
+ }
1278
+ //#endregion
1279
+ export { CliWorkerError, MaterialConflictError, SuspendSignal, SuspenseSignal, WorkerRegistry, abortSignal, agent, channel, claudeCliWorker, claudeHarness, cliWorker, codexCliWorker, codexHarness, delegated, derivedMaterial, events, extension, formatStepKey, guard, http, includes, inspect, judge, loaded, material, materialKind, model, patchMaterial, runCli, runEval, runtime, sandbox, schedule, send, session, skill, step, sub, suite, summary, tool, used, workerRegistry, workers, workflow, workflowExtension, workflowRun };
1280
+
1281
+ //# sourceMappingURL=index.mjs.map