@tangle-network/agent-runtime 0.102.0 → 0.102.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.
Files changed (77) hide show
  1. package/dist/agent.d.ts +1 -1
  2. package/dist/agent.js +5 -3
  3. package/dist/agent.js.map +1 -1
  4. package/dist/analyst-loop.d.ts +1 -1
  5. package/dist/candidate-execution/index.js +5 -4
  6. package/dist/{chunk-SPCD4IQQ.js → chunk-377GOJHJ.js} +2 -2
  7. package/dist/{chunk-LKKIM5QD.js → chunk-3DW5DEKQ.js} +3 -3
  8. package/dist/{chunk-KVJQV342.js → chunk-6MR4IJRW.js} +25 -1777
  9. package/dist/chunk-6MR4IJRW.js.map +1 -0
  10. package/dist/{chunk-4AMAFNUD.js → chunk-7FJJUC73.js} +311 -40
  11. package/dist/chunk-7FJJUC73.js.map +1 -0
  12. package/dist/{chunk-23Z7N5IG.js → chunk-CI7WS6S2.js} +5 -5
  13. package/dist/{chunk-DA7YL6I4.js → chunk-CK76OZPM.js} +3 -3
  14. package/dist/{chunk-KSBUSEUA.js → chunk-KJ2Q4T7F.js} +2 -2
  15. package/dist/{chunk-MAONWP4R.js → chunk-KPHTCHQ4.js} +611 -1419
  16. package/dist/chunk-KPHTCHQ4.js.map +1 -0
  17. package/dist/{chunk-AIBIRAJ6.js → chunk-KSM6GFHP.js} +2 -2
  18. package/dist/chunk-L5DST3QC.js +351 -0
  19. package/dist/chunk-L5DST3QC.js.map +1 -0
  20. package/dist/{chunk-TGDHHHH4.js → chunk-LJLG734E.js} +12 -253
  21. package/dist/chunk-LJLG734E.js.map +1 -0
  22. package/dist/chunk-ROILMKDL.js +1338 -0
  23. package/dist/chunk-ROILMKDL.js.map +1 -0
  24. package/dist/{chunk-N2CEE5Q3.js → chunk-RTB3TC73.js} +3 -3
  25. package/dist/chunk-SQ3ZJH3Y.js +3082 -0
  26. package/dist/chunk-SQ3ZJH3Y.js.map +1 -0
  27. package/dist/chunk-UPWGXKXB.js +254 -0
  28. package/dist/chunk-UPWGXKXB.js.map +1 -0
  29. package/dist/{completion-gate-C80jiRfN.d.ts → completion-gate-C6dhVN-N.d.ts} +2 -2
  30. package/dist/{coordination-BFE3Den7.d.ts → coordination-D9l_YmwW.d.ts} +6 -6
  31. package/dist/environment-provider.d.ts +2 -2
  32. package/dist/{improve-CIml6hT3.d.ts → improve-B40dRu0X.d.ts} +40 -19
  33. package/dist/index.d.ts +329 -21
  34. package/dist/index.js +541 -137
  35. package/dist/index.js.map +1 -1
  36. package/dist/intelligence.d.ts +5 -5
  37. package/dist/intelligence.js +7 -5
  38. package/dist/intelligence.js.map +1 -1
  39. package/dist/knowledge.d.ts +8 -8
  40. package/dist/knowledge.js +9 -7
  41. package/dist/{local-harness-ZqCx51u7.d.ts → local-harness-CtK9dSny.d.ts} +14 -2
  42. package/dist/{loop-runner-bin-Cn1N2rRo.d.ts → loop-runner-bin-PnWslIw4.d.ts} +2 -2
  43. package/dist/loop-runner-bin.d.ts +6 -6
  44. package/dist/loop-runner-bin.js +6 -4
  45. package/dist/loops.d.ts +231 -460
  46. package/dist/loops.js +58 -37
  47. package/dist/mcp/bin.js +2 -2
  48. package/dist/mcp/index.d.ts +184 -12
  49. package/dist/mcp/index.js +31 -9
  50. package/dist/mcp/index.js.map +1 -1
  51. package/dist/mcp/memory-bin.d.ts +1 -0
  52. package/dist/mcp/memory-bin.js +22 -0
  53. package/dist/mcp/memory-bin.js.map +1 -0
  54. package/dist/profiles.d.ts +3 -3
  55. package/dist/structural-rollout-D7xik9XR.d.ts +446 -0
  56. package/dist/{substrate-DO2GHNg2.d.ts → substrate-Dyiqmd3o.d.ts} +1 -1
  57. package/dist/{supervise-BLPI50-w.d.ts → supervise-BQdNAXtK.d.ts} +4 -4
  58. package/dist/testing.js +10 -8
  59. package/dist/testing.js.map +1 -1
  60. package/dist/{types-B3vAW0Oq.d.ts → types-CLat4bT9.d.ts} +1 -1
  61. package/dist/{types-CmnA2iL3.d.ts → types-D870JlH0.d.ts} +2 -2
  62. package/dist/{worktree-fanout-DCA3G4bO.d.ts → worktree-fanout-DsIR4d6w.d.ts} +234 -234
  63. package/package.json +4 -3
  64. package/dist/chunk-4AMAFNUD.js.map +0 -1
  65. package/dist/chunk-IKGCKPDX.js +0 -1115
  66. package/dist/chunk-IKGCKPDX.js.map +0 -1
  67. package/dist/chunk-KVJQV342.js.map +0 -1
  68. package/dist/chunk-MAONWP4R.js.map +0 -1
  69. package/dist/chunk-TGDHHHH4.js.map +0 -1
  70. package/dist/{chunk-SPCD4IQQ.js.map → chunk-377GOJHJ.js.map} +0 -0
  71. package/dist/{chunk-LKKIM5QD.js.map → chunk-3DW5DEKQ.js.map} +0 -0
  72. package/dist/{chunk-23Z7N5IG.js.map → chunk-CI7WS6S2.js.map} +0 -0
  73. package/dist/{chunk-DA7YL6I4.js.map → chunk-CK76OZPM.js.map} +0 -0
  74. package/dist/{chunk-KSBUSEUA.js.map → chunk-KJ2Q4T7F.js.map} +0 -0
  75. package/dist/{chunk-AIBIRAJ6.js.map → chunk-KSM6GFHP.js.map} +0 -0
  76. package/dist/{chunk-N2CEE5Q3.js.map → chunk-RTB3TC73.js.map} +0 -0
  77. package/dist/{sanitize-BTSsdBXw.d.ts → sanitize-DEbPNtyI.d.ts} +58 -58
@@ -6,9 +6,18 @@ import {
6
6
  } from "./chunk-2VZYRB55.js";
7
7
  import {
8
8
  assertModelAllowed,
9
- harnessInvocation,
10
- runLocalHarness
11
- } from "./chunk-IKGCKPDX.js";
9
+ captureWorktreeDiff,
10
+ createSupervisor,
11
+ createWorktree,
12
+ notifyRuntimeHookEvent,
13
+ removeWorktree,
14
+ routerBrain,
15
+ routerChatWithUsage,
16
+ runBrainLoop,
17
+ runWorktreeChecks,
18
+ runWorktreeHarness,
19
+ withDriverExecutor
20
+ } from "./chunk-SQ3ZJH3Y.js";
12
21
  import {
13
22
  InMemoryResultBlobStore,
14
23
  InMemorySpawnJournal,
@@ -38,7 +47,6 @@ import {
38
47
  AgentEvalError,
39
48
  ConfigError,
40
49
  NotFoundError,
41
- RuntimeRunStateError,
42
50
  ValidationError
43
51
  } from "./chunk-YEJR7IXO.js";
44
52
 
@@ -84,919 +92,6 @@ function isAsyncIterable(v) {
84
92
  return v != null && typeof v[Symbol.asyncIterator] === "function";
85
93
  }
86
94
 
87
- // src/runtime-hooks.ts
88
- function defineRuntimeHooks(hooks) {
89
- return hooks;
90
- }
91
- function composeRuntimeHooks(...entries) {
92
- const hooks = entries.filter((entry) => !!entry);
93
- return {
94
- onEvent: hooks.some((hook) => hook.onEvent) ? (event, context) => {
95
- const pending = [];
96
- for (const hook of hooks) {
97
- const result = hook.onEvent?.(event, context);
98
- if (isThenable(result)) pending.push(Promise.resolve(result));
99
- }
100
- if (pending.length > 0) return Promise.all(pending).then(() => void 0);
101
- return void 0;
102
- } : void 0,
103
- onDecisionPoint: hooks.some((hook) => hook.onDecisionPoint) ? (point, context) => {
104
- const pending = [];
105
- for (const hook of hooks) {
106
- const result = hook.onDecisionPoint?.(point, context);
107
- if (isThenable(result)) pending.push(Promise.resolve(result));
108
- }
109
- if (pending.length > 0) return Promise.all(pending).then(() => void 0);
110
- return void 0;
111
- } : void 0,
112
- onHookError: hooks.some((hook) => hook.onHookError) ? (error, context) => {
113
- const pending = [];
114
- for (const hook of hooks) {
115
- const result = hook.onHookError?.(error, context);
116
- if (isThenable(result)) pending.push(Promise.resolve(result));
117
- }
118
- if (pending.length > 0) return Promise.all(pending).then(() => void 0);
119
- return void 0;
120
- } : void 0
121
- };
122
- }
123
- function notifyRuntimeHookEvent(hooks, event, context = {}) {
124
- const onEvent = hooks?.onEvent;
125
- if (!onEvent) return;
126
- try {
127
- const result = onEvent(event, context);
128
- if (isThenable(result)) {
129
- void result.catch((error) => {
130
- notifyRuntimeHookError(hooks, toError(error), {
131
- hook: "onEvent",
132
- eventId: event.id,
133
- target: event.target,
134
- phase: event.phase
135
- });
136
- });
137
- }
138
- } catch (error) {
139
- notifyRuntimeHookError(hooks, toError(error), {
140
- hook: "onEvent",
141
- eventId: event.id,
142
- target: event.target,
143
- phase: event.phase
144
- });
145
- }
146
- }
147
- function notifyRuntimeDecisionPoint(hooks, point, context = {}) {
148
- const onDecisionPoint = hooks?.onDecisionPoint;
149
- if (!onDecisionPoint) return;
150
- try {
151
- const result = onDecisionPoint(point, context);
152
- if (isThenable(result)) {
153
- void result.catch((error) => {
154
- notifyRuntimeHookError(hooks, toError(error), {
155
- hook: "onDecisionPoint",
156
- decisionId: point.id,
157
- decisionKind: point.kind
158
- });
159
- });
160
- }
161
- } catch (error) {
162
- notifyRuntimeHookError(hooks, toError(error), {
163
- hook: "onDecisionPoint",
164
- decisionId: point.id,
165
- decisionKind: point.kind
166
- });
167
- }
168
- }
169
- function notifyRuntimeHookError(hooks, error, context) {
170
- try {
171
- const result = hooks?.onHookError?.(error, context);
172
- if (isThenable(result)) void result.catch(() => void 0);
173
- } catch {
174
- }
175
- }
176
- function isThenable(value) {
177
- return typeof value === "object" && value !== null && "then" in value && typeof value.then === "function";
178
- }
179
- function toError(error) {
180
- return error instanceof Error ? error : new Error(String(error));
181
- }
182
-
183
- // src/runtime/supervise/scope.ts
184
- var nestedScopeSeamKey = "nested-scope";
185
- function makeNestedScopeSeam(args, childNodeId) {
186
- return {
187
- depth: args.depth,
188
- ...args.maxDepth !== void 0 ? { maxDepth: args.maxDepth } : {},
189
- journalRoot: args.root,
190
- mount(nestedRoot, signal) {
191
- return createScope({
192
- parentId: childNodeId,
193
- root: nestedRoot,
194
- pool: args.pool,
195
- journal: args.journal,
196
- blobs: args.blobs,
197
- executors: args.executors,
198
- // Re-seed the parent's NON-recursion seams (sandbox/router for leaf grandchildren);
199
- // the nested scope adds its OWN nested-scope seam per child in `spawn`.
200
- seams: args.seams,
201
- depth: args.depth + 1,
202
- ...args.maxDepth !== void 0 ? { maxDepth: args.maxDepth } : {},
203
- signal,
204
- ...args.now ? { now: args.now } : {},
205
- ...args.hooks ? { hooks: args.hooks } : {}
206
- });
207
- }
208
- };
209
- }
210
- function createScope(args) {
211
- const children = /* @__PURE__ */ new Map();
212
- let spawnOrdinal = 0;
213
- let cursorSeq = 0;
214
- let meterSeq = 0;
215
- const now = args.now ?? Date.now;
216
- function spawn4(agent, task, opts) {
217
- if (args.maxDepth !== void 0 && args.depth >= args.maxDepth) {
218
- return { ok: false, reason: "depth-exceeded" };
219
- }
220
- const spec = agent.executorSpec;
221
- if (!isAgentSpec(spec)) {
222
- throw new ValidationError(
223
- `scope.spawn: agent "${agent.name}" exposes no \`executorSpec\` (AgentSpec) to resolve a Executor`
224
- );
225
- }
226
- const resolved = args.executors.resolve(spec);
227
- if (!resolved.succeeded) throw new ValidationError(`scope.spawn: ${resolved.error}`);
228
- const reservation = args.pool.reserve(opts.budget);
229
- if (!reservation.ok) return { ok: false, reason: reservation.reason };
230
- try {
231
- const ordinal = spawnOrdinal++;
232
- const id = `${args.parentId}:s${ordinal}`;
233
- const childAbort = new AbortController();
234
- const cascadeAbort = () => childAbort.abort();
235
- if (args.signal.aborted) childAbort.abort();
236
- else args.signal.addEventListener("abort", cascadeAbort, { once: true });
237
- const ctx = {
238
- signal: childAbort.signal,
239
- seams: { ...args.seams, [nestedScopeSeamKey]: makeNestedScopeSeam(args, id) }
240
- };
241
- const executor = resolved.value(spec, ctx);
242
- const handle = {
243
- id,
244
- label: opts.label,
245
- get status() {
246
- return children.get(id)?.status ?? "cancelled";
247
- },
248
- abort(reason) {
249
- childAbort.abort(reason);
250
- }
251
- };
252
- const live = {
253
- id,
254
- status: "acquiring",
255
- runtime: executor.runtime,
256
- budget: opts.budget,
257
- label: opts.label,
258
- spent: zeroSpend(),
259
- settled: void 0,
260
- delivered: false,
261
- executorDone: false,
262
- ...executor.deliver ? { deliver: executor.deliver.bind(executor) } : {}
263
- };
264
- children.set(id, live);
265
- void args.journal.appendEvent(args.root, {
266
- kind: "spawned",
267
- id,
268
- parent: args.parentId,
269
- label: opts.label,
270
- budget: opts.budget,
271
- runtime: executor.runtime,
272
- seq: ordinal,
273
- at: new Date(now()).toISOString()
274
- });
275
- notifyRuntimeHookEvent(
276
- args.hooks,
277
- {
278
- id: `${id}:spawn`,
279
- runId: args.root,
280
- target: "agent.spawn",
281
- phase: "after",
282
- timestamp: now(),
283
- stepIndex: ordinal,
284
- parentId: args.parentId,
285
- payload: {
286
- childId: id,
287
- label: opts.label,
288
- runtime: executor.runtime,
289
- budget: opts.budget,
290
- depth: args.depth
291
- }
292
- },
293
- { signal: args.signal }
294
- );
295
- const settled = runChild(
296
- live,
297
- executor,
298
- childAbort,
299
- task,
300
- opts,
301
- args.pool,
302
- reservation.ticket,
303
- args.blobs
304
- ).then((s) => {
305
- live.resolved = s;
306
- return s;
307
- }).finally(() => {
308
- args.signal.removeEventListener("abort", cascadeAbort);
309
- });
310
- live.settled = settled;
311
- return { ok: true, handle };
312
- } catch (err) {
313
- args.pool.reconcile(reservation.ticket, zeroSpend());
314
- throw err;
315
- }
316
- }
317
- async function next() {
318
- const undelivered = () => [...children.values()].filter((c) => !c.delivered);
319
- if (undelivered().length === 0) return null;
320
- for (; ; ) {
321
- const pending = undelivered();
322
- if (pending.length === 0) return null;
323
- const ready = pending.find((c) => c.resolved !== void 0);
324
- const chosen = ready ?? await raceFirstSettled(pending);
325
- if (chosen.delivered) continue;
326
- chosen.delivered = true;
327
- const seq = cursorSeq++;
328
- const settlement = chosen.resolved;
329
- if (!settlement) {
330
- throw new ValidationError(
331
- `scope.next: child '${chosen.id}' won the settle race without a resolved value`
332
- );
333
- }
334
- return finalizeSettlement(chosen, settlement, seq, args, now);
335
- }
336
- }
337
- async function nextResolved() {
338
- for (; ; ) {
339
- const candidates = [...children.values()].filter((c) => !c.delivered);
340
- const pick = candidates.find((c) => c.resolved !== void 0) ?? candidates.find((c) => c.executorDone);
341
- if (!pick) return null;
342
- const settlement = await pick.settled;
343
- if (pick.delivered) continue;
344
- pick.delivered = true;
345
- const seq = cursorSeq++;
346
- return finalizeSettlement(pick, settlement, seq, args, now);
347
- }
348
- }
349
- function send(nodeId, msg) {
350
- const child = children.get(nodeId);
351
- if (!child || child.delivered || !child.deliver) return false;
352
- child.deliver(msg);
353
- return true;
354
- }
355
- async function meter(spend, detail) {
356
- const seq = meterSeq++;
357
- args.pool.observe(spend);
358
- await args.journal.appendEvent(args.root, {
359
- kind: "metered",
360
- id: args.parentId,
361
- spend,
362
- seq,
363
- at: new Date(now()).toISOString()
364
- });
365
- notifyRuntimeHookEvent(
366
- args.hooks,
367
- {
368
- id: `${args.parentId}:meter:${seq}`,
369
- runId: args.root,
370
- target: "agent.turn",
371
- phase: "after",
372
- timestamp: now(),
373
- parentId: args.parentId,
374
- payload: { spend, ...detail ?? {} }
375
- },
376
- { signal: args.signal }
377
- );
378
- }
379
- return {
380
- spawn: spawn4,
381
- next,
382
- nextResolved,
383
- send,
384
- signal: args.signal,
385
- meter,
386
- get view() {
387
- return makeTreeView(args.parentId, children);
388
- },
389
- get budget() {
390
- return args.pool.readout();
391
- }
392
- };
393
- }
394
- async function raceFirstSettled(pending) {
395
- return Promise.race(pending.map((c) => c.settled.then(() => c)));
396
- }
397
- async function finalizeSettlement(child, settlement, seq, args, now) {
398
- const handle = frozenHandle(child);
399
- if (settlement.kind === "down") {
400
- child.status = "failed";
401
- await args.journal.appendEvent(args.root, {
402
- kind: "settled",
403
- id: child.id,
404
- status: "down",
405
- spent: child.spent,
406
- infra: settlement.infra,
407
- seq,
408
- at: new Date(now()).toISOString()
409
- });
410
- if (settlement.metered) {
411
- await args.journal.appendEvent(args.root, {
412
- kind: "metered",
413
- id: child.id,
414
- spend: settlement.metered,
415
- seq,
416
- at: new Date(now()).toISOString()
417
- });
418
- }
419
- notifyRuntimeHookEvent(
420
- args.hooks,
421
- {
422
- id: `${child.id}:settled`,
423
- runId: args.root,
424
- target: "agent.child",
425
- phase: "after",
426
- timestamp: now(),
427
- stepIndex: seq,
428
- parentId: args.parentId,
429
- payload: {
430
- childId: child.id,
431
- status: "down",
432
- reason: settlement.reason,
433
- infra: settlement.infra,
434
- spent: child.spent
435
- }
436
- },
437
- { signal: args.signal }
438
- );
439
- return {
440
- kind: "down",
441
- handle,
442
- reason: settlement.reason,
443
- infra: settlement.infra,
444
- restartCount: settlement.restartCount,
445
- seq
446
- };
447
- }
448
- child.status = "done";
449
- child.outRef = settlement.outRef;
450
- child.spent = settlement.spent;
451
- await args.journal.appendEvent(args.root, {
452
- kind: "settled",
453
- id: child.id,
454
- status: "done",
455
- outRef: settlement.outRef,
456
- ...settlement.verdict ? { verdict: settlement.verdict } : {},
457
- spent: settlement.spent,
458
- seq,
459
- at: new Date(now()).toISOString()
460
- });
461
- if (settlement.metered) {
462
- await args.journal.appendEvent(args.root, {
463
- kind: "metered",
464
- id: child.id,
465
- spend: settlement.metered,
466
- seq,
467
- at: new Date(now()).toISOString()
468
- });
469
- }
470
- notifyRuntimeHookEvent(
471
- args.hooks,
472
- {
473
- id: `${child.id}:settled`,
474
- runId: args.root,
475
- target: "agent.child",
476
- phase: "after",
477
- timestamp: now(),
478
- stepIndex: seq,
479
- parentId: args.parentId,
480
- payload: {
481
- childId: child.id,
482
- status: "done",
483
- outRef: settlement.outRef,
484
- score: settlement.verdict?.score,
485
- valid: settlement.verdict?.valid,
486
- spent: settlement.spent
487
- }
488
- },
489
- { signal: args.signal }
490
- );
491
- return {
492
- kind: "done",
493
- handle,
494
- out: settlement.out,
495
- outRef: settlement.outRef,
496
- ...settlement.verdict ? { verdict: settlement.verdict } : {},
497
- spent: settlement.spent,
498
- seq
499
- };
500
- }
501
- async function runChild(live, executor, childAbort, task, opts, pool, ticket, blobs) {
502
- let reconciled = false;
503
- const reconcileOnce = (spend) => {
504
- if (reconciled) return;
505
- reconciled = true;
506
- pool.reconcile(ticket, clampSpend(spend, opts.budget));
507
- };
508
- try {
509
- live.status = "running";
510
- const ran = executor.execute(task, childAbort.signal);
511
- let artifact;
512
- if (isAsyncIterable2(ran)) {
513
- const spend = await foldStream(ran);
514
- live.spent = spend;
515
- artifact = executor.resultArtifact();
516
- reconcileOnce(spend);
517
- } else {
518
- const terminal = await ran;
519
- live.spent = terminal.spent;
520
- artifact = terminal;
521
- reconcileOnce(terminal.spent);
522
- }
523
- live.executorDone = true;
524
- const ownMetered = executor.metered?.();
525
- if (childAbort.signal.aborted) {
526
- await teardownSafe(executor, opts.shutdown ?? "brutalKill");
527
- return downRecord("aborted before settle", true, ownMetered);
528
- }
529
- const outRef = contentAddress(artifact.out);
530
- await blobs.put(outRef, artifact.out);
531
- await teardownSafe(executor, opts.shutdown ?? "infinity");
532
- return {
533
- kind: "done",
534
- out: artifact.out,
535
- outRef,
536
- ...artifact.verdict ? { verdict: artifact.verdict } : {},
537
- spent: live.spent,
538
- ...ownMetered ? { metered: ownMetered } : {}
539
- };
540
- } catch (err) {
541
- live.executorDone = true;
542
- reconcileOnce(live.spent);
543
- await teardownSafe(executor, "brutalKill");
544
- const aborted = childAbort.signal.aborted || isAbortError(err);
545
- return downRecord(errMessage(err), aborted || isInfraError(err), executor.metered?.());
546
- }
547
- }
548
- function settledToIteration(settled) {
549
- if (settled.kind === "down") {
550
- throw new ValidationError(
551
- `settledToIteration: cannot adapt a 'down' settlement (node '${settled.handle.id}', seq ${settled.seq}) to an Iteration`
552
- );
553
- }
554
- return {
555
- index: settled.seq,
556
- task: void 0,
557
- agentRunName: settled.handle.label,
558
- output: settled.out,
559
- ...settled.verdict ? { verdict: settled.verdict } : {},
560
- events: [],
561
- startedAt: 0,
562
- endedAt: settled.spent.ms,
563
- costUsd: settled.spent.usd,
564
- tokenUsage: { input: settled.spent.tokens.input, output: settled.spent.tokens.output }
565
- };
566
- }
567
- function makeTreeView(root, children) {
568
- const nodes = [...children.values()].map((c) => ({
569
- id: c.id,
570
- parent: root,
571
- label: c.label,
572
- status: c.status,
573
- runtime: c.runtime,
574
- budget: c.budget,
575
- spent: c.spent,
576
- ...c.outRef ? { outRef: c.outRef } : {}
577
- }));
578
- return {
579
- root,
580
- nodes,
581
- inFlight: nodes.filter((n) => n.status === "running" || n.status === "acquiring").length
582
- };
583
- }
584
- function frozenHandle(child) {
585
- return {
586
- id: child.id,
587
- label: child.label,
588
- status: child.status,
589
- abort() {
590
- }
591
- };
592
- }
593
- async function foldStream(stream) {
594
- const tokens = { input: 0, output: 0 };
595
- let usd = 0;
596
- let iterations = 0;
597
- for await (const ev of stream) {
598
- if (ev.kind === "tokens") {
599
- tokens.input += ev.input;
600
- tokens.output += ev.output;
601
- } else if (ev.kind === "cost") {
602
- usd += ev.usd;
603
- } else {
604
- iterations += 1;
605
- }
606
- }
607
- return { iterations, tokens, usd, ms: 0 };
608
- }
609
- function clampSpend(spend, budget) {
610
- const totalTokens2 = spend.tokens.input + spend.tokens.output;
611
- const tokensOk = totalTokens2 <= budget.maxTokens;
612
- const itersOk = spend.iterations <= budget.maxIterations;
613
- const usdOk = budget.maxUsd === void 0 || spend.usd <= budget.maxUsd;
614
- if (tokensOk && itersOk && usdOk) return spend;
615
- const ratio = !tokensOk && totalTokens2 > 0 ? budget.maxTokens / totalTokens2 : 1;
616
- return {
617
- iterations: Math.min(spend.iterations, budget.maxIterations),
618
- tokens: ratio < 1 ? {
619
- input: Math.floor(spend.tokens.input * ratio),
620
- output: Math.floor(spend.tokens.output * ratio)
621
- } : spend.tokens,
622
- usd: budget.maxUsd === void 0 ? spend.usd : Math.min(spend.usd, budget.maxUsd),
623
- ...spend.usdKnown === false ? { usdKnown: false } : {},
624
- ms: spend.ms
625
- };
626
- }
627
- async function teardownSafe(executor, grace) {
628
- try {
629
- await executor.teardown(grace);
630
- } catch {
631
- }
632
- }
633
- function downRecord(reason, infra, metered) {
634
- return { kind: "down", reason, infra, restartCount: 0, ...metered ? { metered } : {} };
635
- }
636
- function zeroSpend() {
637
- return { iterations: 0, tokens: { input: 0, output: 0 }, usd: 0, ms: 0 };
638
- }
639
- function isAsyncIterable2(value) {
640
- return typeof value === "object" && value !== null && typeof value[Symbol.asyncIterator] === "function";
641
- }
642
- function isAgentSpec(value) {
643
- if (typeof value !== "object" || value === null) return false;
644
- const v = value;
645
- return "profile" in v && "harness" in v;
646
- }
647
- function isAbortError(err) {
648
- return typeof err === "object" && err !== null && "name" in err && err.name === "AbortError";
649
- }
650
- function isInfraError(err) {
651
- return err instanceof ValidationError;
652
- }
653
- function errMessage(err) {
654
- if (err instanceof Error) return err.message;
655
- return String(err);
656
- }
657
-
658
- // src/mcp/worktree.ts
659
- import { spawn } from "child_process";
660
- import { isAbsolute, win32 } from "path";
661
- async function runGitAsync(args, cwd, runner) {
662
- if (runner) return runner(args, { cwd });
663
- return new Promise((resolve, reject) => {
664
- const proc = spawn("git", args, { cwd, stdio: "pipe" });
665
- let stdout = "";
666
- let stderr = "";
667
- proc.stdout?.on("data", (c) => {
668
- stdout += String(c);
669
- });
670
- proc.stderr?.on("data", (c) => {
671
- stderr += String(c);
672
- });
673
- proc.on("error", reject);
674
- proc.on("close", (code) => resolve({ stdout, stderr, exitCode: code ?? -1 }));
675
- });
676
- }
677
- function ensureGitOk(step, result) {
678
- if (result.exitCode !== 0) {
679
- throw gitFailure(step, result);
680
- }
681
- }
682
- function gitFailure(step, result) {
683
- return new Error(
684
- `worktree: git ${step} failed (exit ${result.exitCode}): ${result.stderr.slice(0, 400)}`
685
- );
686
- }
687
- async function createWorktree(options) {
688
- const variants = options.variantsDir ?? ".agent-worktrees";
689
- const baseRef = options.baseRef ?? "HEAD";
690
- const branch = `delegate/${options.runId}`;
691
- const path2 = `${options.repoRoot.replace(/\/+$/, "")}/${variants}/${options.runId}`;
692
- const headSha = await runGitAsync(["rev-parse", baseRef], options.repoRoot, options.runGit);
693
- ensureGitOk(`rev-parse ${baseRef}`, headSha);
694
- const add = await runGitAsync(
695
- ["worktree", "add", "-b", branch, path2, baseRef],
696
- options.repoRoot,
697
- options.runGit
698
- );
699
- ensureGitOk(`worktree add ${path2}`, add);
700
- return { path: path2, baseSha: headSha.stdout.trim(), branch };
701
- }
702
- async function captureWorktreeDiff(options) {
703
- const baseRef = options.baseRef ?? options.worktree.baseSha;
704
- const pathspecs = worktreeDiffPathspecs(options.excludePaths ?? []);
705
- const staged = await runGitAsync(
706
- ["add", "-A", ...pathspecs.length > 0 ? ["--", ".", ...pathspecs] : []],
707
- options.worktree.path,
708
- options.runGit
709
- );
710
- ensureGitOk("add -A", staged);
711
- const patch = await runGitAsync(
712
- ["diff", "--cached", baseRef, ...pathspecs.length > 0 ? ["--", ".", ...pathspecs] : []],
713
- options.worktree.path,
714
- options.runGit
715
- );
716
- ensureGitOk(`diff --cached ${baseRef}`, patch);
717
- const shortstat = await runGitAsync(
718
- [
719
- "diff",
720
- "--cached",
721
- "--shortstat",
722
- baseRef,
723
- ...pathspecs.length > 0 ? ["--", ".", ...pathspecs] : []
724
- ],
725
- options.worktree.path,
726
- options.runGit
727
- );
728
- ensureGitOk(`diff --cached --shortstat ${baseRef}`, shortstat);
729
- const stats = parseShortstat(shortstat.stdout);
730
- return { patch: patch.stdout, stats };
731
- }
732
- function worktreeDiffPathspecs(paths) {
733
- const normalized = /* @__PURE__ */ new Set();
734
- for (const path2 of paths) {
735
- if (typeof path2 !== "string" || path2.length === 0 || path2.includes("\\") || hasControlCharacter(path2) || isAbsolute(path2) || win32.isAbsolute(path2)) {
736
- throw new Error(
737
- `worktree: excluded path must be a canonical repository-relative path: ${path2}`
738
- );
739
- }
740
- const segments = path2.split("/");
741
- if (segments.some((segment) => segment.length === 0 || segment === "." || segment === "..")) {
742
- throw new Error(
743
- `worktree: excluded path must be a canonical repository-relative path: ${path2}`
744
- );
745
- }
746
- normalized.add(path2);
747
- }
748
- return [...normalized].sort((left, right) => left.localeCompare(right)).map((path2) => `:(top,exclude,literal)${path2}`);
749
- }
750
- function hasControlCharacter(value) {
751
- for (let index = 0; index < value.length; index += 1) {
752
- const code = value.charCodeAt(index);
753
- if (code < 32 || code === 127) return true;
754
- }
755
- return false;
756
- }
757
- function parseShortstat(text) {
758
- const out = { filesChanged: 0, insertions: 0, deletions: 0 };
759
- const filesMatch = text.match(/(\d+)\s+files?\s+changed/);
760
- if (filesMatch?.[1]) out.filesChanged = Number(filesMatch[1]);
761
- const insertMatch = text.match(/(\d+)\s+insertions?/);
762
- if (insertMatch?.[1]) out.insertions = Number(insertMatch[1]);
763
- const deleteMatch = text.match(/(\d+)\s+deletions?/);
764
- if (deleteMatch?.[1]) out.deletions = Number(deleteMatch[1]);
765
- return out;
766
- }
767
- async function removeWorktree(options) {
768
- const force = options.force ?? true;
769
- const args = ["worktree", "remove"];
770
- if (force) args.push("--force");
771
- args.push(options.worktree.path);
772
- const removal = await runGitAsync(args, options.repoRoot, options.runGit);
773
- const removalError = removal.exitCode !== 0 && !/not a working tree/iu.test(removal.stderr) ? gitFailure(`worktree remove ${options.worktree.path}`, removal) : void 0;
774
- const branchRemoval = await runGitAsync(
775
- ["branch", "-D", options.worktree.branch],
776
- options.repoRoot,
777
- options.runGit
778
- );
779
- const branchError = branchRemoval.exitCode !== 0 && !/branch .+ not found/iu.test(branchRemoval.stderr) ? gitFailure(`branch -D ${options.worktree.branch}`, branchRemoval) : void 0;
780
- if (removalError && branchError) {
781
- throw new AggregateError(
782
- [removalError, branchError],
783
- "worktree: failed to remove worktree and branch"
784
- );
785
- }
786
- if (removalError) throw removalError;
787
- if (branchError) throw branchError;
788
- }
789
-
790
- // src/runtime/router-client.ts
791
- import { estimateCost, isModelPriced } from "@tangle-network/agent-eval";
792
-
793
- // src/runtime/tool-loop.ts
794
- function estimateConversationTokens(messages) {
795
- let chars = 0;
796
- for (const m of messages) {
797
- const content = m.content;
798
- chars += typeof content === "string" ? content.length : safeJsonLength(content);
799
- const calls = m.tool_calls;
800
- if (calls) for (const c of calls) chars += c.function?.arguments?.length ?? 0;
801
- }
802
- return Math.ceil(chars / 4);
803
- }
804
- function safeJsonLength(value) {
805
- if (value === void 0 || value === null) return 0;
806
- try {
807
- return JSON.stringify(value)?.length ?? 0;
808
- } catch {
809
- return String(value).length;
810
- }
811
- }
812
- async function maybeCompact(messages, c, turn) {
813
- const head = c.preserveHead !== void 0 && c.preserveHead > 0 ? c.preserveHead : 2;
814
- if (messages.length <= head + 1) return false;
815
- const estimate = c.estimateTokens ?? estimateConversationTokens;
816
- const before = estimate(messages);
817
- if (before <= c.thresholdTokens) return false;
818
- const digest = await c.distill([...messages]);
819
- messages.splice(head, messages.length - head, {
820
- role: "user",
821
- content: `[earlier work compacted to save context \u2014 progress so far]
822
- ${digest}`
823
- });
824
- c.onCompact?.({ turn, beforeTokens: before, afterTokens: estimate(messages) });
825
- return true;
826
- }
827
- async function runBrainLoop(opts) {
828
- const maxTurns = opts.maxTurns ?? 4;
829
- const messages = [...opts.initialMessages];
830
- let toolCalls = 0;
831
- let lastText = "";
832
- const usage = { input: 0, output: 0 };
833
- const toolTrace = [];
834
- for (let turn = 1; turn <= maxTurns; turn += 1) {
835
- if (opts.hooks?.stopBefore?.(turn)) break;
836
- await opts.hooks?.beforeTurn?.(turn, messages);
837
- if (opts.compaction) await maybeCompact(messages, opts.compaction, turn);
838
- const r = await opts.chat(messages, opts.tools);
839
- if (r.usage) {
840
- usage.input += r.usage.input;
841
- usage.output += r.usage.output;
842
- opts.hooks?.onUsage?.(r.usage);
843
- }
844
- if (r.content) lastText = r.content;
845
- if (r.toolCalls.length === 0) {
846
- if (r.content) messages.push({ role: "assistant", content: r.content });
847
- return { final: lastText, turns: turn, toolCalls, toolTrace, usage, messages };
848
- }
849
- messages.push({
850
- role: "assistant",
851
- content: r.content ?? "",
852
- tool_calls: r.toolCalls.map((tc) => ({
853
- id: tc.id,
854
- type: "function",
855
- function: { name: tc.name, arguments: tc.arguments }
856
- }))
857
- });
858
- for (const tc of r.toolCalls) {
859
- toolCalls += 1;
860
- let args = {};
861
- try {
862
- args = JSON.parse(tc.arguments);
863
- } catch {
864
- messages.push({
865
- role: "tool",
866
- tool_call_id: tc.id,
867
- content: `error: arguments were not valid JSON: ${tc.arguments.slice(0, 200)}`
868
- });
869
- continue;
870
- }
871
- const out = await opts.execute(tc.name, args);
872
- messages.push({ role: "tool", tool_call_id: tc.id, content: out });
873
- toolTrace.push({ name: tc.name, args: tc.arguments, result: out });
874
- }
875
- }
876
- return { final: lastText, turns: maxTurns, toolCalls, toolTrace, usage, messages };
877
- }
878
-
879
- // src/runtime/router-client.ts
880
- async function routerChatWithUsage(cfg, messages, opts) {
881
- const url = `${cfg.routerBaseUrl.replace(/\/$/, "")}/chat/completions`;
882
- const headers = { "content-type": "application/json", authorization: `Bearer ${cfg.routerKey}` };
883
- let temperature = opts?.temperature ?? 0.2;
884
- const body = () => ({
885
- model: cfg.model,
886
- messages,
887
- temperature,
888
- max_tokens: opts?.maxTokens ?? 8192,
889
- ...opts?.reasoningEffort ? { reasoning_effort: opts.reasoningEffort } : {}
890
- });
891
- if (cfg.complete) return parseChatResult(await cfg.complete(body()), cfg.model);
892
- let lastErr = "";
893
- for (let attempt = 0; attempt < 5; attempt += 1) {
894
- const res = await fetch(url, {
895
- method: "POST",
896
- headers,
897
- body: JSON.stringify(body()),
898
- ...opts?.signal ? { signal: opts.signal } : {}
899
- });
900
- if (res.ok) return parseChatResult(await res.json(), cfg.model);
901
- const status = res.status;
902
- const text = (await res.text()).slice(0, 200);
903
- lastErr = `router ${status}: ${text}`;
904
- if (status === 400 && /temperature/i.test(text) && temperature !== 1) {
905
- temperature = 1;
906
- continue;
907
- }
908
- if (![408, 425, 429, 500, 502, 503, 504, 520, 522, 524].includes(status))
909
- throw new Error(lastErr);
910
- if (attempt < 4) await new Promise((r) => setTimeout(r, 800 * 2 ** attempt));
911
- }
912
- throw new Error(`${lastErr} (exhausted retries)`);
913
- }
914
- function parseChatResult(json, model) {
915
- const data = json;
916
- const u = data.usage;
917
- const usage = u && typeof u.prompt_tokens === "number" && typeof u.completion_tokens === "number" ? { input: u.prompt_tokens, output: u.completion_tokens } : void 0;
918
- const costUsd = usage && isModelPriced(model) ? estimateCost(usage.input, usage.output, model) : void 0;
919
- const msg = data.choices?.[0]?.message;
920
- const { content, reasoning } = splitReasoning(
921
- msg?.content ?? "",
922
- msg?.reasoning ?? msg?.reasoning_content
923
- );
924
- return {
925
- content,
926
- ...reasoning ? { reasoning } : {},
927
- ...usage ? { usage } : {},
928
- ...costUsd !== void 0 ? { costUsd } : {}
929
- };
930
- }
931
- function splitReasoning(rawContent, fieldReasoning) {
932
- const open = rawContent.indexOf("<think>");
933
- if (open !== -1) {
934
- const close = rawContent.indexOf("</think>", open);
935
- const inline = close !== -1 ? rawContent.slice(open + 7, close) : rawContent.slice(open + 7);
936
- const rest = close !== -1 ? rawContent.slice(0, open) + rawContent.slice(close + 8) : rawContent.slice(0, open);
937
- const reasoning = [fieldReasoning, inline.trim()].filter(Boolean).join("\n");
938
- return { content: rest.trim(), ...reasoning ? { reasoning } : {} };
939
- }
940
- return { content: rawContent, ...fieldReasoning ? { reasoning: fieldReasoning } : {} };
941
- }
942
- async function routerChatWithTools(cfg, messages, tools, opts) {
943
- const body = {
944
- model: cfg.model,
945
- messages,
946
- tools,
947
- tool_choice: opts?.toolChoice ?? "auto",
948
- temperature: opts?.temperature ?? 0.3,
949
- ...opts?.maxTokens ? { max_tokens: opts.maxTokens } : {}
950
- };
951
- const raw = cfg.complete ? await cfg.complete(body) : await (async () => {
952
- const res = await fetch(`${cfg.routerBaseUrl.replace(/\/$/, "")}/chat/completions`, {
953
- method: "POST",
954
- headers: { "content-type": "application/json", authorization: `Bearer ${cfg.routerKey}` },
955
- body: JSON.stringify(body),
956
- ...opts?.signal ? { signal: opts.signal } : {}
957
- });
958
- if (!res.ok) throw new Error(`router ${res.status}: ${(await res.text()).slice(0, 200)}`);
959
- return res.json();
960
- })();
961
- const data = raw;
962
- const msg = data.choices?.[0]?.message;
963
- const toolCalls = (msg?.tool_calls ?? []).map((tc, i) => ({
964
- id: tc.id ?? `call_${i}`,
965
- name: tc.function?.name ?? "",
966
- arguments: tc.function?.arguments ?? "{}"
967
- }));
968
- const u = data.usage;
969
- const usage = u && typeof u.prompt_tokens === "number" && typeof u.completion_tokens === "number" ? { input: u.prompt_tokens, output: u.completion_tokens } : void 0;
970
- const costUsd = usage && isModelPriced(cfg.model) ? estimateCost(usage.input, usage.output, cfg.model) : void 0;
971
- return {
972
- content: msg?.content ?? null,
973
- toolCalls,
974
- ...usage ? { usage } : {},
975
- ...costUsd !== void 0 ? { costUsd } : {}
976
- };
977
- }
978
- async function routerToolLoop(cfg, system, user, tools, execute, opts) {
979
- const initialMessages = opts?.initialMessages ?? [
980
- { role: "system", content: system },
981
- { role: "user", content: user }
982
- ];
983
- return runBrainLoop({
984
- chat: (messages, toolSpecs) => routerChatWithTools(cfg, messages, toolSpecs, {
985
- ...opts?.temperature !== void 0 ? { temperature: opts.temperature } : {},
986
- ...opts?.maxTokens ? { maxTokens: opts.maxTokens } : {},
987
- ...opts?.signal ? { signal: opts.signal } : {}
988
- }),
989
- tools,
990
- execute,
991
- initialMessages,
992
- maxTurns: opts?.maxTurns ?? 4
993
- });
994
- }
995
- function routerBrain(cfg, opts = {}) {
996
- const temperature = opts.temperature ?? 0.4;
997
- return (messages, tools) => routerChatWithTools(cfg, messages, tools, { temperature, toolChoice: "auto" });
998
- }
999
-
1000
95
  // src/runtime/sandbox-acquire.ts
1001
96
  var RETRYABLE_HTTP = /* @__PURE__ */ new Set([502, 503, 504, 522, 524, 408, 425, 429]);
1002
97
  var TERMINAL_STATUS = /* @__PURE__ */ new Set(["failed", "expired", "stopped"]);
@@ -1687,13 +782,13 @@ async function executeIteration(args) {
1687
782
  await destroySandboxSafe(box, args.ctx.traceEmitter, args.runId, args.now);
1688
783
  }
1689
784
  }
1690
- if (isAbortError2(slot.error) || args.signal.aborted) {
785
+ if (isAbortError(slot.error) || args.signal.aborted) {
1691
786
  if (slot.error) throw slot.error;
1692
787
  throwAbort();
1693
788
  }
1694
789
  if (slot.error instanceof ValidationError) throw slot.error;
1695
790
  }
1696
- function isAbortError2(err) {
791
+ function isAbortError(err) {
1697
792
  return err instanceof Error && err.name === "AbortError";
1698
793
  }
1699
794
  var TEARDOWN_TIMEOUT_MS2 = 15e3;
@@ -2003,302 +1098,6 @@ ${lines.join("\n")}`;
2003
1098
 
2004
1099
  // src/runtime/supervise/worktree-cli-executor.ts
2005
1100
  import { randomUUID } from "crypto";
2006
-
2007
- // src/mcp/worktree-harness.ts
2008
- import { spawn as spawn2 } from "child_process";
2009
- import { createHash } from "crypto";
2010
- import {
2011
- applyWorkspacePlan,
2012
- materializeProfile
2013
- } from "@tangle-network/agent-profile-materialize";
2014
- var defaultCheckOutputCap = 16e3;
2015
- async function runWorktreeHarness(opts) {
2016
- const runHarness = opts.runHarness ?? runLocalHarness;
2017
- const runCommand = opts.runCommand ?? defaultRunCommand;
2018
- const checkTimeoutMs = opts.checkTimeoutMs ?? opts.harnessTimeoutMs ?? 5 * 60 * 1e3;
2019
- const cap = opts.checkOutputCap ?? defaultCheckOutputCap;
2020
- const worktree = await createWorktree({
2021
- repoRoot: opts.repoRoot,
2022
- runId: opts.runId,
2023
- ...opts.baseRef ? { baseRef: opts.baseRef } : {},
2024
- ...opts.runGit ? { runGit: opts.runGit } : {}
2025
- });
2026
- const cleanup = () => removeWorktree({
2027
- worktree,
2028
- repoRoot: opts.repoRoot,
2029
- ...opts.runGit ? { runGit: opts.runGit } : {}
2030
- });
2031
- try {
2032
- assertSupportedWorktreeProfile(opts.profile, opts.harness);
2033
- assertSafeProfileResourcePaths(opts.profile);
2034
- const resourceInstructions = resolveResourceInstructions(opts.profile);
2035
- const workspaceProfile = materializationOnlyProfile(opts.profile);
2036
- const plan = materializeProfile(workspaceProfile, opts.harness);
2037
- if (plan.unsupported.length > 0) {
2038
- throw new Error(
2039
- `runWorktreeHarness: profile cannot be materialized for ${opts.harness}: ${plan.unsupported.map(({ dimension, reason }) => `${dimension}: ${reason}`).join("; ")}`
2040
- );
2041
- }
2042
- assertSafeMaterializedPaths(plan);
2043
- const applied = applyWorkspacePlan(plan, worktree.path, { existingFiles: "reject" });
2044
- if (applied.unsupported.length > 0) {
2045
- throw new Error("runWorktreeHarness: applied profile unexpectedly retained unsupported rows");
2046
- }
2047
- const invocationProfile = profileWithResourceInstructions(opts.profile, resourceInstructions);
2048
- const { command, args } = harnessInvocation(opts.harness, invocationProfile, opts.taskPrompt, {
2049
- // This helper created the candidate worktree above; autonomous Claude
2050
- // edits are permitted only inside that isolated checkout.
2051
- dangerouslySkipPermissions: opts.harness === "claude",
2052
- ...opts.codexReproducible ? { codexReproducible: true } : {}
2053
- });
2054
- const harnessResult = await runHarness({
2055
- harness: opts.harness,
2056
- cwd: worktree.path,
2057
- taskPrompt: opts.taskPrompt,
2058
- invocation: { command, args: [...args, ...applied.flags] },
2059
- env: { ...process.env, ...applied.env },
2060
- ...opts.codexReproducible ? { codexReproducible: true } : {},
2061
- ...opts.codexReadDeniedPaths ? { codexReadDeniedPaths: opts.codexReadDeniedPaths } : {},
2062
- ...opts.harnessTimeoutMs !== void 0 ? { timeoutMs: opts.harnessTimeoutMs } : {},
2063
- ...opts.signal ? { signal: opts.signal } : {}
2064
- });
2065
- const diff = await captureWorktreeDiff({
2066
- worktree,
2067
- excludePaths: applied.written,
2068
- ...opts.runGit ? { runGit: opts.runGit } : {}
2069
- });
2070
- const checks = await runWorktreeChecks({
2071
- worktreePath: worktree.path,
2072
- ...opts.testCmd !== void 0 ? { testCmd: opts.testCmd } : {},
2073
- ...opts.typecheckCmd !== void 0 ? { typecheckCmd: opts.typecheckCmd } : {},
2074
- timeoutMs: checkTimeoutMs,
2075
- cap,
2076
- runCommand,
2077
- ...opts.signal ? { signal: opts.signal } : {}
2078
- });
2079
- const result = {
2080
- branch: worktree.branch,
2081
- patch: diff.patch,
2082
- stats: diff.stats,
2083
- profileMaterialization: profileMaterializationReceipt(applied, resourceInstructions),
2084
- harness: {
2085
- name: opts.harness,
2086
- exitCode: harnessResult.exitCode,
2087
- timedOut: harnessResult.timedOut,
2088
- killedBySignal: harnessResult.killedBySignal,
2089
- durationMs: harnessResult.durationMs,
2090
- stdout: harnessResult.stdout,
2091
- stderr: harnessResult.stderr,
2092
- ...harnessResult.usage ? { usage: harnessResult.usage } : {},
2093
- ...harnessResult.evidence ? {
2094
- cliVersion: harnessResult.evidence.cliVersion,
2095
- executableSha256: harnessResult.evidence.executableSha256,
2096
- requestedPromptSha256: harnessResult.evidence.requestedPromptSha256,
2097
- effectivePromptSha256: harnessResult.evidence.effectivePromptSha256,
2098
- nonPromptArgsSha256: harnessResult.evidence.nonPromptArgsSha256,
2099
- controlledConfigSha256: harnessResult.evidence.controlledConfigSha256,
2100
- readDeniedPaths: [...harnessResult.evidence.readDeniedPaths],
2101
- readDeniedPathsSha256: harnessResult.evidence.readDeniedPathsSha256,
2102
- readDeniedPathCount: harnessResult.evidence.readDeniedPathCount,
2103
- executionPolicy: harnessResult.evidence.policy
2104
- } : {}
2105
- },
2106
- ...checks ? { checks } : {}
2107
- };
2108
- return { worktree, result, cleanup };
2109
- } catch (err) {
2110
- try {
2111
- await cleanup();
2112
- } catch (cleanupError) {
2113
- throw new AggregateError(
2114
- [err, cleanupError],
2115
- "runWorktreeHarness: run failed and worktree cleanup also failed"
2116
- );
2117
- }
2118
- throw err;
2119
- }
2120
- }
2121
- function resolveResourceInstructions(profile) {
2122
- const instructions = profile.resources?.instructions;
2123
- if (instructions === void 0) return void 0;
2124
- if (typeof instructions === "string")
2125
- return instructions.trim().length > 0 ? instructions : void 0;
2126
- if (instructions.kind === "inline" && typeof instructions.content === "string") {
2127
- return instructions.content.trim().length > 0 ? instructions.content : void 0;
2128
- }
2129
- throw new Error(
2130
- "runWorktreeHarness: resources.instructions must be a string or inline resource; remote refs require pre-resolution"
2131
- );
2132
- }
2133
- function profileWithResourceInstructions(profile, resourceInstructions) {
2134
- let resources;
2135
- if (profile.resources) {
2136
- const { instructions: _instructions, ...structuralResources } = profile.resources;
2137
- resources = structuralResources;
2138
- }
2139
- return {
2140
- ...profile,
2141
- ...resources ? { resources } : {},
2142
- ...resourceInstructions === void 0 ? {} : {
2143
- prompt: {
2144
- ...profile.prompt,
2145
- instructions: [...profile.prompt?.instructions ?? [], resourceInstructions]
2146
- }
2147
- }
2148
- };
2149
- }
2150
- function materializationOnlyProfile(profile) {
2151
- const {
2152
- prompt: _prompt,
2153
- model: _model,
2154
- resources: profileResources,
2155
- ...structuralProfile
2156
- } = profile;
2157
- let resources;
2158
- if (profileResources) {
2159
- const { instructions: _instructions, ...fileBackedResources } = profileResources;
2160
- resources = fileBackedResources;
2161
- }
2162
- return {
2163
- ...structuralProfile,
2164
- ...resources ? { resources } : {}
2165
- };
2166
- }
2167
- function assertSupportedWorktreeProfile(profile, harness) {
2168
- const unsupportedAxes = [
2169
- hasEntries(profile.tools) ? "tools" : null,
2170
- hasEntries(profile.permissions) ? "permissions" : null,
2171
- profile.connections && profile.connections.length > 0 ? "connections" : null,
2172
- hasEntries(profile.confidential) ? "confidential" : null,
2173
- hasEntries(profile.modes) ? "modes" : null,
2174
- hasEntries(profile.extensions) ? "extensions" : null
2175
- ].filter((axis) => axis !== null);
2176
- if (profile.model?.reasoningEffort !== void 0 && harness !== "codex") {
2177
- unsupportedAxes.push("model.reasoningEffort");
2178
- }
2179
- for (const [name, server] of Object.entries(profile.mcp ?? {})) {
2180
- const path2 = `mcp[${JSON.stringify(name)}]`;
2181
- if (server.enabled === false && harness !== "opencode") {
2182
- unsupportedAxes.push(`${path2}.enabled`);
2183
- }
2184
- if (hasEntries(server.headers) && harness === "codex") {
2185
- unsupportedAxes.push(`${path2}.headers`);
2186
- }
2187
- if (server.cwd !== void 0 && harness === "opencode") {
2188
- unsupportedAxes.push(`${path2}.cwd`);
2189
- }
2190
- }
2191
- if (harness === "claude") {
2192
- for (const [event, commands] of Object.entries(profile.hooks ?? {})) {
2193
- for (const [index, command] of commands.entries()) {
2194
- const path2 = `hooks[${JSON.stringify(event)}][${index}]`;
2195
- if (hasEntries(command.env)) unsupportedAxes.push(`${path2}.env`);
2196
- if (command.blocking !== void 0) unsupportedAxes.push(`${path2}.blocking`);
2197
- }
2198
- }
2199
- }
2200
- for (const [name, subagent] of Object.entries(profile.subagents ?? {})) {
2201
- const path2 = `subagents[${JSON.stringify(name)}]`;
2202
- if (hasEntries(subagent.permissions)) unsupportedAxes.push(`${path2}.permissions`);
2203
- if (subagent.maxSteps !== void 0) unsupportedAxes.push(`${path2}.maxSteps`);
2204
- if (hasEntries(subagent.tools) && harness !== "claude") {
2205
- unsupportedAxes.push(`${path2}.tools`);
2206
- }
2207
- }
2208
- if (unsupportedAxes.length > 0) {
2209
- throw new Error(
2210
- `runWorktreeHarness: profile requests unsupported worktree behavior: ${unsupportedAxes.join(", ")}`
2211
- );
2212
- }
2213
- }
2214
- function hasEntries(value) {
2215
- return value !== void 0 && Object.keys(value).length > 0;
2216
- }
2217
- function assertSafeMaterializedPaths(plan) {
2218
- for (const file of plan.files) {
2219
- if (file.relPath.split("/").some(isGitMetadataSegment)) {
2220
- throw new Error(
2221
- `runWorktreeHarness: profile file cannot target reserved Git metadata: ${file.relPath}`
2222
- );
2223
- }
2224
- }
2225
- }
2226
- function assertSafeProfileResourcePaths(profile) {
2227
- for (const file of profile.resources?.files ?? []) {
2228
- if (file.path.split("/").some(isGitMetadataSegment)) {
2229
- throw new Error(
2230
- `runWorktreeHarness: profile file cannot target reserved Git metadata: ${file.path}`
2231
- );
2232
- }
2233
- }
2234
- }
2235
- function isGitMetadataSegment(segment) {
2236
- const windowsCanonical = segment.replace(/[ .]+$/u, "").toLowerCase();
2237
- return windowsCanonical === ".git" || windowsCanonical.startsWith(".git:");
2238
- }
2239
- function profileMaterializationReceipt(applied, resourceInstructions) {
2240
- const instructionBytes = resourceInstructions === void 0 ? null : Buffer.from(resourceInstructions, "utf8");
2241
- return {
2242
- workspacePlanDigest: applied.workspacePlanDigest,
2243
- writtenPaths: [...applied.written],
2244
- unsupported: [...applied.unsupported],
2245
- environmentNames: Object.keys(applied.env).sort(),
2246
- flags: [...applied.flags],
2247
- resourceInstructions: instructionBytes ? {
2248
- delivery: "invocation-prompt",
2249
- sha256: `sha256:${createHash("sha256").update(instructionBytes).digest("hex")}`,
2250
- byteLength: instructionBytes.byteLength
2251
- } : { delivery: "none", sha256: null, byteLength: 0 }
2252
- };
2253
- }
2254
- async function runWorktreeChecks(opts) {
2255
- if (opts.testCmd === void 0 && opts.typecheckCmd === void 0) return void 0;
2256
- const runCommand = opts.runCommand ?? defaultRunCommand;
2257
- const run = async (command) => {
2258
- const res = await runCommand({
2259
- command,
2260
- cwd: opts.worktreePath,
2261
- timeoutMs: opts.timeoutMs,
2262
- ...opts.signal ? { signal: opts.signal } : {}
2263
- });
2264
- return {
2265
- command,
2266
- passed: res.exitCode === 0,
2267
- exitCode: res.exitCode,
2268
- output: res.output.length > opts.cap ? res.output.slice(-opts.cap) : res.output
2269
- };
2270
- };
2271
- const checks = {};
2272
- if (opts.testCmd !== void 0) checks.tests = await run(opts.testCmd);
2273
- if (opts.typecheckCmd !== void 0) checks.typecheck = await run(opts.typecheckCmd);
2274
- return checks;
2275
- }
2276
- function defaultRunCommand(opts) {
2277
- return new Promise((resolve, reject) => {
2278
- const child = spawn2("/bin/sh", ["-c", opts.command], {
2279
- cwd: opts.cwd,
2280
- stdio: ["ignore", "pipe", "pipe"]
2281
- });
2282
- const chunks = [];
2283
- let settled = false;
2284
- const timer = setTimeout(() => child.kill("SIGTERM"), opts.timeoutMs);
2285
- const onAbort = () => child.kill("SIGTERM");
2286
- opts.signal?.addEventListener("abort", onAbort, { once: true });
2287
- child.stdout?.on("data", (d) => chunks.push(String(d)));
2288
- child.stderr?.on("data", (d) => chunks.push(String(d)));
2289
- const finish = (fn) => {
2290
- if (settled) return;
2291
- settled = true;
2292
- clearTimeout(timer);
2293
- opts.signal?.removeEventListener("abort", onAbort);
2294
- fn();
2295
- };
2296
- child.on("error", (err) => finish(() => reject(err)));
2297
- child.on("close", (code) => finish(() => resolve({ exitCode: code, output: chunks.join("") })));
2298
- });
2299
- }
2300
-
2301
- // src/runtime/supervise/worktree-cli-executor.ts
2302
1101
  function createWorktreeCliExecutor(options) {
2303
1102
  if (!options.repoRoot) {
2304
1103
  throw new ValidationError("createWorktreeCliExecutor: repoRoot required");
@@ -2404,12 +1203,12 @@ function linkSignals(a, b) {
2404
1203
  }
2405
1204
 
2406
1205
  // src/runtime/supervise/runtime.ts
2407
- import { spawn as spawn3 } from "child_process";
1206
+ import { spawn } from "child_process";
2408
1207
  import { randomUUID as randomUUID2 } from "crypto";
2409
1208
  import { request as httpRequest } from "http";
2410
1209
  import { request as httpsRequest } from "https";
2411
1210
  import { Readable } from "stream";
2412
- import { estimateCost as estimateCost2, isModelPriced as isModelPriced2 } from "@tangle-network/agent-eval";
1211
+ import { estimateCost, isModelPriced } from "@tangle-network/agent-eval";
2413
1212
  var routerSeamKey = "router";
2414
1213
  var sandboxSeamKey = "sandbox";
2415
1214
  var cliSeamKey = "cli";
@@ -2430,7 +1229,7 @@ function contentRef(prefix, value) {
2430
1229
  }
2431
1230
  return `${prefix}:${(h >>> 0).toString(16).padStart(8, "0")}`;
2432
1231
  }
2433
- function zeroSpend2() {
1232
+ function zeroSpend() {
2434
1233
  return { iterations: 0, tokens: zeroTokenUsage(), usd: 0, ms: 0 };
2435
1234
  }
2436
1235
  var routerInlineExecutor = (spec, ctx) => {
@@ -2624,7 +1423,7 @@ var routerToolsInlineExecutor = (spec, ctx) => {
2624
1423
  }
2625
1424
  }
2626
1425
  }
2627
- const usd = isModelPriced2(model) ? estimateCost2(tokens.input, tokens.output, model) : 0;
1426
+ const usd = isModelPriced(model) ? estimateCost(tokens.input, tokens.output, model) : 0;
2628
1427
  const spent = { iterations: turns, tokens, usd, ms: Date.now() - started };
2629
1428
  const out = { content: lastText };
2630
1429
  artifact = { outRef: contentRef("router-tools", { model, content: lastText }), out, spent };
@@ -2799,7 +1598,7 @@ var cliExecutor = (_spec, ctx) => {
2799
1598
  };
2800
1599
  async function* streamCliLeaf(args) {
2801
1600
  const prompt = taskToPrompt(args.task);
2802
- const proc = spawn3(args.seam.bin, args.seam.args ?? [], {
1601
+ const proc = spawn(args.seam.bin, args.seam.args ?? [], {
2803
1602
  ...args.seam.cwd ? { cwd: args.seam.cwd } : {},
2804
1603
  env: { ...process.env, ...args.seam.env ?? {} },
2805
1604
  stdio: ["pipe", "pipe", "pipe"]
@@ -2836,7 +1635,7 @@ async function* streamCliLeaf(args) {
2836
1635
  );
2837
1636
  }
2838
1637
  const out = { content: chunks.join("") };
2839
- args.onArtifact({ outRef: contentRef("cli", out), out, spent: zeroSpend2() });
1638
+ args.onArtifact({ outRef: contentRef("cli", out), out, spent: zeroSpend() });
2840
1639
  yield { kind: "iteration" };
2841
1640
  }
2842
1641
  function killWithGrace(proc, grace) {
@@ -3224,7 +2023,7 @@ function bridgeWorktreeExecutor(spec, ctx, seam) {
3224
2023
  inner = bridgeExecutor(spec, bridgeCtx);
3225
2024
  for (const msg of pending.splice(0)) inner.deliver?.(msg);
3226
2025
  const run = inner.execute(seam.taskPrompt, linked);
3227
- if (isAsyncIterable3(run)) {
2026
+ if (isAsyncIterable2(run)) {
3228
2027
  for await (const event of run) yield event;
3229
2028
  bridgeArtifact = inner.resultArtifact();
3230
2029
  } else {
@@ -3317,7 +2116,7 @@ function bridgeOutputText(out) {
3317
2116
  return String(out);
3318
2117
  }
3319
2118
  }
3320
- function isAsyncIterable3(value) {
2119
+ function isAsyncIterable2(value) {
3321
2120
  return value !== null && typeof value === "object" && typeof value[Symbol.asyncIterator] === "function";
3322
2121
  }
3323
2122
  var cliWorktreeExecutor = (spec, ctx) => {
@@ -3477,181 +2276,6 @@ function mergeAbortSignals(...signals) {
3477
2276
  return c.signal;
3478
2277
  }
3479
2278
 
3480
- // src/runtime/supervise/driver-executor.ts
3481
- var driverRuntime = "driver";
3482
- var driverRole = "driver";
3483
- function isDriverSpec(spec) {
3484
- const role = spec.profile.metadata?.role;
3485
- if (role !== driverRole) return false;
3486
- const driver = spec.driver;
3487
- if (!isAgent(driver)) {
3488
- throw new ValidationError(
3489
- "driverExecutor: a driver-role spec must carry a `driver` Agent to run inside its nested scope"
3490
- );
3491
- }
3492
- return true;
3493
- }
3494
- var driverExecutorFactory = (spec, ctx) => {
3495
- if (!isDriverSpec(spec)) {
3496
- throw new ValidationError(
3497
- 'driverExecutorFactory: spec is not a driver child (no role:"driver" marker)'
3498
- );
3499
- }
3500
- const driver = spec.driver;
3501
- const journal = spec.journal;
3502
- const seam = readNestedScopeSeam(ctx);
3503
- let artifact;
3504
- let meteredSpend;
3505
- return {
3506
- runtime: driverRuntime,
3507
- async execute(task, signal) {
3508
- const nestedRoot = nestedTreeKey(seam, journal);
3509
- await journal.beginTree(nestedRoot, (/* @__PURE__ */ new Date(0)).toISOString());
3510
- const nestedScope = seam.mount(nestedRoot, signal);
3511
- try {
3512
- const out = await driver.act(task, nestedScope);
3513
- const events = await loadTreeEvents(journal, nestedRoot);
3514
- const settled = events.filter(isSettled);
3515
- meteredSpend = nonZeroOrUndef(sumMetered(events));
3516
- const verdict = deriveDeliveryVerdict(settled);
3517
- artifact = {
3518
- outRef: `${driverRuntime}:${nestedRoot}`,
3519
- out,
3520
- spent: sumSpend(settled),
3521
- ...verdict ? { verdict } : {}
3522
- };
3523
- return artifact;
3524
- } catch (err) {
3525
- meteredSpend = await safeSumMetered(journal, nestedRoot);
3526
- throw err;
3527
- }
3528
- },
3529
- metered() {
3530
- return meteredSpend;
3531
- },
3532
- teardown() {
3533
- return Promise.resolve({ destroyed: true });
3534
- },
3535
- resultArtifact() {
3536
- if (!artifact) {
3537
- throw new ValidationError("driverExecutor: resultArtifact() read before execute()");
3538
- }
3539
- return artifact;
3540
- }
3541
- };
3542
- };
3543
- function withDriverExecutor(base) {
3544
- return {
3545
- register: base.register.bind(base),
3546
- resolve(spec) {
3547
- const role = spec.profile.metadata?.role;
3548
- if (role === driverRole && !spec.executor) {
3549
- return { succeeded: true, value: driverExecutorFactory };
3550
- }
3551
- return base.resolve(spec);
3552
- }
3553
- };
3554
- }
3555
- function nestedTreeKey(seam, journal) {
3556
- return `${seam.journalRoot}/d${nextNestOrdinal(journal)}`;
3557
- }
3558
- var nestCounters = /* @__PURE__ */ new WeakMap();
3559
- function nextNestOrdinal(journal) {
3560
- let c = nestCounters.get(journal);
3561
- if (!c) {
3562
- c = { n: 0 };
3563
- nestCounters.set(journal, c);
3564
- }
3565
- return c.n++;
3566
- }
3567
- async function loadTreeEvents(journal, nestedRoot) {
3568
- const events = await journal.loadTree(nestedRoot);
3569
- if (events === void 0) {
3570
- throw new ValidationError(
3571
- `driverExecutor: nested tree '${nestedRoot}' missing from the journal after run (corrupted log)`
3572
- );
3573
- }
3574
- return events;
3575
- }
3576
- function isSettled(ev) {
3577
- return ev.kind === "settled";
3578
- }
3579
- function sumSpend(settled) {
3580
- const total = { iterations: 0, tokens: { input: 0, output: 0 }, usd: 0, ms: 0 };
3581
- for (const ev of settled) {
3582
- total.iterations += ev.spent.iterations;
3583
- total.tokens.input += ev.spent.tokens.input;
3584
- total.tokens.output += ev.spent.tokens.output;
3585
- total.usd += ev.spent.usd;
3586
- if (ev.spent.usdKnown === false) total.usdKnown = false;
3587
- total.ms += ev.spent.ms;
3588
- }
3589
- return total;
3590
- }
3591
- function sumMetered(events) {
3592
- const total = { iterations: 0, tokens: { input: 0, output: 0 }, usd: 0, ms: 0 };
3593
- for (const ev of events) {
3594
- if (ev.kind !== "metered") continue;
3595
- total.iterations += ev.spend.iterations;
3596
- total.tokens.input += ev.spend.tokens.input;
3597
- total.tokens.output += ev.spend.tokens.output;
3598
- total.usd += ev.spend.usd;
3599
- if (ev.spend.usdKnown === false) total.usdKnown = false;
3600
- total.ms += ev.spend.ms;
3601
- }
3602
- return total;
3603
- }
3604
- function isNonZeroSpend(s) {
3605
- return s.iterations > 0 || s.tokens.input > 0 || s.tokens.output > 0 || s.usd > 0 || s.ms > 0;
3606
- }
3607
- function nonZeroOrUndef(s) {
3608
- return isNonZeroSpend(s) ? s : void 0;
3609
- }
3610
- async function safeSumMetered(journal, nestedRoot) {
3611
- try {
3612
- return nonZeroOrUndef(sumMetered(await loadTreeEvents(journal, nestedRoot)));
3613
- } catch {
3614
- return void 0;
3615
- }
3616
- }
3617
- function deriveDeliveryVerdict(settled) {
3618
- let sawChild = false;
3619
- let anyValid = false;
3620
- let bestValidScore;
3621
- let bestDoneScore;
3622
- for (const ev of settled) {
3623
- sawChild = true;
3624
- if (ev.status !== "done") continue;
3625
- const score = ev.verdict?.score;
3626
- if (score !== void 0 && (bestDoneScore === void 0 || score > bestDoneScore)) {
3627
- bestDoneScore = score;
3628
- }
3629
- if (ev.verdict?.valid === true) {
3630
- anyValid = true;
3631
- if (score !== void 0 && (bestValidScore === void 0 || score > bestValidScore)) {
3632
- bestValidScore = score;
3633
- }
3634
- }
3635
- }
3636
- if (!sawChild) return void 0;
3637
- return {
3638
- valid: anyValid,
3639
- score: anyValid ? bestValidScore ?? 1 : bestDoneScore ?? 0
3640
- };
3641
- }
3642
- function readNestedScopeSeam(ctx) {
3643
- const seam = ctx.seams[nestedScopeSeamKey];
3644
- if (!seam || typeof seam.mount !== "function") {
3645
- throw new ValidationError(
3646
- `driverExecutor: missing required seam "${nestedScopeSeamKey}" \u2014 a driver child must be spawned through a Scope that seeds it (the keystone scope does)`
3647
- );
3648
- }
3649
- return seam;
3650
- }
3651
- function isAgent(value) {
3652
- return typeof value === "object" && value !== null && typeof value.act === "function" && typeof value.name === "string";
3653
- }
3654
-
3655
2279
  // src/runtime/supervise/run-context.ts
3656
2280
  function createInMemoryRunContext(opts = {}) {
3657
2281
  const base = createExecutorRegistry();
@@ -3662,364 +2286,6 @@ function createInMemoryRunContext(opts = {}) {
3662
2286
  };
3663
2287
  }
3664
2288
 
3665
- // src/runtime/supervise/budget.ts
3666
- function spendFromUsageEvents(events) {
3667
- const tokens = zeroTokenUsage();
3668
- let usd = 0;
3669
- let iterations = 0;
3670
- for (const ev of events) {
3671
- if (ev.kind === "tokens") {
3672
- addTokenUsage(tokens, { input: ev.input, output: ev.output });
3673
- } else if (ev.kind === "cost") {
3674
- usd += ev.usd;
3675
- } else {
3676
- iterations += 1;
3677
- }
3678
- }
3679
- return { iterations, tokens, usd, ms: 0 };
3680
- }
3681
- async function foldUsage(events) {
3682
- if (Array.isArray(events)) return spendFromUsageEvents(events);
3683
- const tokens = zeroTokenUsage();
3684
- let usd = 0;
3685
- let iterations = 0;
3686
- for await (const ev of events) {
3687
- if (ev.kind === "tokens") {
3688
- addTokenUsage(tokens, { input: ev.input, output: ev.output });
3689
- } else if (ev.kind === "cost") {
3690
- usd += ev.usd;
3691
- } else {
3692
- iterations += 1;
3693
- }
3694
- }
3695
- return { iterations, tokens, usd, ms: 0 };
3696
- }
3697
- function totalTokens(usage) {
3698
- return usage.input + usage.output;
3699
- }
3700
- function createBudgetPool(root, now = Date.now) {
3701
- let freeTokens = root.maxTokens;
3702
- let reservedTokens = 0;
3703
- let committedTokens = 0;
3704
- const usdCapped = root.maxUsd !== void 0;
3705
- let freeUsd = root.maxUsd ?? 0;
3706
- let reservedUsd = 0;
3707
- let committedUsd = 0;
3708
- let freeIterations = root.maxIterations;
3709
- let reservedIterations = 0;
3710
- let committedIterations = 0;
3711
- const absoluteDeadlineMs = root.deadlineMs !== void 0 ? now() + root.deadlineMs : 0;
3712
- let nextTicketId = 0;
3713
- const open = /* @__PURE__ */ new Set();
3714
- function reserve(b) {
3715
- const wantTokens = b.maxTokens;
3716
- const wantUsd = b.maxUsd ?? 0;
3717
- const wantIterations = b.maxIterations;
3718
- if (wantTokens > freeTokens) return { ok: false, reason: "budget-exhausted" };
3719
- if (wantIterations > freeIterations) return { ok: false, reason: "budget-exhausted" };
3720
- if (wantUsd > 0 && (!usdCapped || wantUsd > freeUsd)) {
3721
- return { ok: false, reason: "budget-exhausted" };
3722
- }
3723
- freeTokens -= wantTokens;
3724
- reservedTokens += wantTokens;
3725
- freeIterations -= wantIterations;
3726
- reservedIterations += wantIterations;
3727
- if (wantUsd > 0) {
3728
- freeUsd -= wantUsd;
3729
- reservedUsd += wantUsd;
3730
- }
3731
- const id = nextTicketId++;
3732
- open.add(id);
3733
- return {
3734
- ok: true,
3735
- ticket: { id, reserved: { tokens: wantTokens, usd: wantUsd, iterations: wantIterations } }
3736
- };
3737
- }
3738
- function reconcile(ticket, spent) {
3739
- if (!open.has(ticket.id)) {
3740
- throw new Error(`budget pool: reconcile of unknown or already-settled ticket ${ticket.id}`);
3741
- }
3742
- open.delete(ticket.id);
3743
- const { tokens: rTokens, usd: rUsd, iterations: rIterations } = ticket.reserved;
3744
- if (usdCapped && spent.usdKnown === false) {
3745
- throw new Error(
3746
- `budget pool: ticket ${ticket.id} reported unknown dollar cost under a dollar-capped budget`
3747
- );
3748
- }
3749
- const spentTokens = totalTokens(spent.tokens);
3750
- if (spentTokens > rTokens) {
3751
- throw new Error(
3752
- `budget pool: ticket ${ticket.id} spent ${spentTokens} tokens > reserved ${rTokens}`
3753
- );
3754
- }
3755
- if (spent.iterations > rIterations) {
3756
- throw new Error(
3757
- `budget pool: ticket ${ticket.id} spent ${spent.iterations} iterations > reserved ${rIterations}`
3758
- );
3759
- }
3760
- if (usdCapped && spent.usd > rUsd) {
3761
- throw new Error(`budget pool: ticket ${ticket.id} spent $${spent.usd} > reserved $${rUsd}`);
3762
- }
3763
- reservedTokens -= rTokens;
3764
- committedTokens += spentTokens;
3765
- freeTokens += rTokens - spentTokens;
3766
- reservedIterations -= rIterations;
3767
- committedIterations += spent.iterations;
3768
- freeIterations += rIterations - spent.iterations;
3769
- if (usdCapped && rUsd > 0) {
3770
- reservedUsd -= rUsd;
3771
- committedUsd += spent.usd;
3772
- freeUsd += rUsd - spent.usd;
3773
- } else {
3774
- committedUsd += spent.usd;
3775
- }
3776
- }
3777
- function observe(spend) {
3778
- if (usdCapped && spend.usdKnown === false) {
3779
- throw new Error(
3780
- "budget pool: cannot observe unknown dollar cost under a dollar-capped budget"
3781
- );
3782
- }
3783
- const tokens = totalTokens(spend.tokens);
3784
- freeTokens -= tokens;
3785
- committedTokens += tokens;
3786
- freeIterations -= spend.iterations;
3787
- committedIterations += spend.iterations;
3788
- committedUsd += spend.usd;
3789
- if (usdCapped) freeUsd -= spend.usd;
3790
- }
3791
- function readout() {
3792
- return {
3793
- tokensLeft: freeTokens,
3794
- usdLeft: usdCapped ? freeUsd : 0,
3795
- usdCapped,
3796
- deadlineMs: absoluteDeadlineMs,
3797
- reservedTokens
3798
- };
3799
- }
3800
- function assertNoOpenTickets() {
3801
- if (open.size > 0) {
3802
- throw new Error(
3803
- `budget pool: ${open.size} reservation(s) still open at join barrier (leaked ticket ids: ${[...open].join(", ")}) \u2014 conserved-pool invariant violated`
3804
- );
3805
- }
3806
- }
3807
- return {
3808
- reserve,
3809
- reconcile,
3810
- spendFrom: foldUsage,
3811
- readout,
3812
- observe,
3813
- assertNoOpenTickets
3814
- };
3815
- }
3816
-
3817
- // src/runtime/supervise/supervisor.ts
3818
- var defaultMaxDepth = 4;
3819
- function createSupervisor() {
3820
- let attached;
3821
- async function run(root, task, opts) {
3822
- const now = opts.now ?? Date.now;
3823
- const pool = createBudgetPool(opts.budget, now);
3824
- await opts.journal.beginTree(opts.runId, new Date(now()).toISOString());
3825
- await opts.journal.appendEvent(opts.runId, {
3826
- kind: "spawned",
3827
- id: opts.runId,
3828
- label: "root",
3829
- budget: opts.budget,
3830
- runtime: "inline",
3831
- seq: 0,
3832
- at: new Date(now()).toISOString()
3833
- });
3834
- const controller = new AbortController();
3835
- const cascadeAbort = (reason) => {
3836
- if (controller.signal.aborted) return;
3837
- controller.abort(reason);
3838
- };
3839
- const onCallerAbort = () => cascadeAbort("caller signal aborted");
3840
- if (opts.signal) {
3841
- if (opts.signal.aborted) cascadeAbort("caller signal aborted");
3842
- else opts.signal.addEventListener("abort", onCallerAbort, { once: true });
3843
- }
3844
- const breaker = createIntensityBreaker(opts, () => cascadeAbort("intensity breaker tripped"));
3845
- const journal = wrapJournalForBreaker(opts.journal, breaker);
3846
- const scope = createScope({
3847
- parentId: opts.runId,
3848
- root: opts.runId,
3849
- pool,
3850
- journal,
3851
- blobs: opts.blobs,
3852
- executors: opts.executors,
3853
- seams: {},
3854
- depth: 0,
3855
- maxDepth: opts.maxDepth ?? defaultMaxDepth,
3856
- signal: controller.signal,
3857
- now,
3858
- hooks: opts.hooks
3859
- });
3860
- const openScope = scope;
3861
- if (attached) {
3862
- attached.bind({ scope: openScope, cascadeAbort, signal: pushRootSignal(cascadeAbort) });
3863
- }
3864
- let actOutcome;
3865
- try {
3866
- const out = await root.act(task, scope);
3867
- actOutcome = { ok: true, out };
3868
- } catch (error) {
3869
- actOutcome = { ok: false, error };
3870
- } finally {
3871
- await drainLiveChildren(openScope, controller);
3872
- if (opts.signal) opts.signal.removeEventListener("abort", onCallerAbort);
3873
- if (attached) attached.unbind();
3874
- }
3875
- const tree = scope.view;
3876
- if (actOutcome.ok) {
3877
- pool.assertNoOpenTickets();
3878
- const out = actOutcome.out;
3879
- if (out !== void 0) {
3880
- const outRef = contentAddress(out);
3881
- await opts.blobs.put(outRef, out);
3882
- const { childWork, driverInference } = await spentFromJournal(journal, opts.runId);
3883
- return {
3884
- kind: "winner",
3885
- out,
3886
- outRef,
3887
- tree,
3888
- spentTotal: addSpend(childWork, driverInference),
3889
- ...isNonEmptySpend(driverInference) ? { spentBreakdown: { driverInference, childWork } } : {}
3890
- };
3891
- }
3892
- return noWinner();
3893
- }
3894
- return noWinner();
3895
- async function noWinner() {
3896
- const { childWork, driverInference } = await spentFromJournal(journal, opts.runId);
3897
- return {
3898
- kind: "no-winner",
3899
- reason: classifyNoWinner(controller, pool, opts, breaker),
3900
- tree,
3901
- downCount: breaker.downCount(),
3902
- spentTotal: addSpend(childWork, driverInference)
3903
- };
3904
- }
3905
- }
3906
- function attach(h) {
3907
- const control = rootControls.get(h);
3908
- if (!control) {
3909
- throw new RuntimeRunStateError(
3910
- "supervisor.attach: handle was not minted by createRootHandle (no control channel)"
3911
- );
3912
- }
3913
- attached = control;
3914
- }
3915
- return { run, attach };
3916
- }
3917
- var rootControls = /* @__PURE__ */ new WeakMap();
3918
- function pushRootSignal(cascadeAbort) {
3919
- return (msg) => {
3920
- if (msg.kind === "cancel") cascadeAbort(msg.reason ?? "root signal: cancel");
3921
- };
3922
- }
3923
- function createIntensityBreaker(opts, trip) {
3924
- const max = opts.maxRestarts;
3925
- const within = opts.withinMs;
3926
- const armed = max !== void 0 && within !== void 0;
3927
- const recent = [];
3928
- let total = 0;
3929
- let isTripped = false;
3930
- return {
3931
- recordDown(at) {
3932
- total += 1;
3933
- if (!armed || isTripped) return;
3934
- recent.push(at);
3935
- const cutoff = at - within;
3936
- while (recent.length > 0 && recent[0] < cutoff) recent.shift();
3937
- if (recent.length > max) {
3938
- isTripped = true;
3939
- trip();
3940
- }
3941
- },
3942
- tripped() {
3943
- return isTripped;
3944
- },
3945
- downCount() {
3946
- return total;
3947
- }
3948
- };
3949
- }
3950
- function wrapJournalForBreaker(journal, breaker) {
3951
- return {
3952
- loadTree: (root) => journal.loadTree(root),
3953
- beginTree: (root, at) => journal.beginTree(root, at),
3954
- appendEvent: (root, ev) => {
3955
- if (ev.kind === "settled" && ev.status === "down") breaker.recordDown(Date.parse(ev.at));
3956
- return journal.appendEvent(root, ev);
3957
- }
3958
- };
3959
- }
3960
- async function drainLiveChildren(scope, controller) {
3961
- const hasLive = scope.view.inFlight > 0;
3962
- if (!hasLive) return;
3963
- if (!controller.signal.aborted) controller.abort();
3964
- await Promise.allSettled([drainCursor(scope)]);
3965
- }
3966
- async function drainCursor(scope) {
3967
- for (; ; ) {
3968
- const settled = await scope.next();
3969
- if (settled === null) return;
3970
- }
3971
- }
3972
- function classifyNoWinner(controller, pool, opts, breaker) {
3973
- if (breaker.tripped()) return "all-children-down";
3974
- if (controller.signal.aborted) return "aborted";
3975
- if (poolExhausted(pool, opts)) return "budget-exhausted";
3976
- return "all-children-down";
3977
- }
3978
- function poolExhausted(pool, opts) {
3979
- const r = pool.readout();
3980
- if (r.tokensLeft <= 0) return true;
3981
- if (opts.budget.maxUsd !== void 0 && r.usdLeft <= 0) return true;
3982
- if (opts.budget.deadlineMs !== void 0 && r.deadlineMs > 0 && (opts.now ?? Date.now)() >= r.deadlineMs) {
3983
- return true;
3984
- }
3985
- return false;
3986
- }
3987
- async function spentFromJournal(journal, root) {
3988
- const events = await journal.loadTree(root);
3989
- if (events === void 0) {
3990
- throw new RuntimeRunStateError(
3991
- `supervisor: spawn tree '${root}' is missing from the journal after run (corrupted log)`
3992
- );
3993
- }
3994
- const childWork = { iterations: 0, tokens: { input: 0, output: 0 }, usd: 0, ms: 0 };
3995
- const driverInference = { iterations: 0, tokens: { input: 0, output: 0 }, usd: 0, ms: 0 };
3996
- for (const ev of events) {
3997
- if (ev.kind === "settled") accumulate(childWork, ev.spent);
3998
- else if (ev.kind === "metered") accumulate(driverInference, ev.spend);
3999
- }
4000
- return { childWork, driverInference };
4001
- }
4002
- function accumulate(a, b) {
4003
- a.iterations += b.iterations;
4004
- a.tokens.input += b.tokens.input;
4005
- a.tokens.output += b.tokens.output;
4006
- a.usd += b.usd;
4007
- if (b.usdKnown === false) a.usdKnown = false;
4008
- a.ms += b.ms;
4009
- }
4010
- function addSpend(a, b) {
4011
- return {
4012
- iterations: a.iterations + b.iterations,
4013
- tokens: { input: a.tokens.input + b.tokens.input, output: a.tokens.output + b.tokens.output },
4014
- usd: a.usd + b.usd,
4015
- ...a.usdKnown === false || b.usdKnown === false ? { usdKnown: false } : {},
4016
- ms: a.ms + b.ms
4017
- };
4018
- }
4019
- function isNonEmptySpend(s) {
4020
- return s.iterations > 0 || s.tokens.input > 0 || s.tokens.output > 0 || s.usd > 0 || s.ms > 0;
4021
- }
4022
-
4023
2289
  // src/runtime/supervise/event-bus.ts
4024
2290
  function createEventBus(now = Date.now) {
4025
2291
  const queue = [];
@@ -4676,7 +2942,7 @@ ${narrative}` : roster;
4676
2942
  return `${roster}
4677
2943
 
4678
2944
  ## Progress notes
4679
- Summary unavailable: ${errMessage2(e)}`;
2945
+ Summary unavailable: ${errMessage(e)}`;
4680
2946
  }
4681
2947
  }),
4682
2948
  ...opts.compaction.onCompact ? { onCompact: opts.compaction.onCompact } : {},
@@ -4747,7 +3013,7 @@ function safeJson(v) {
4747
3013
  return String(v);
4748
3014
  }
4749
3015
  }
4750
- function errMessage2(e) {
3016
+ function errMessage(e) {
4751
3017
  return e instanceof Error ? e.message : String(e);
4752
3018
  }
4753
3019
 
@@ -6748,21 +5014,6 @@ async function delegate(intent, opts = {}) {
6748
5014
 
6749
5015
  export {
6750
5016
  gateOnDeliverable,
6751
- defineRuntimeHooks,
6752
- composeRuntimeHooks,
6753
- notifyRuntimeHookEvent,
6754
- notifyRuntimeDecisionPoint,
6755
- createScope,
6756
- settledToIteration,
6757
- withDriverExecutor,
6758
- createWorktree,
6759
- captureWorktreeDiff,
6760
- removeWorktree,
6761
- runWorktreeHarness,
6762
- routerChatWithUsage,
6763
- routerChatWithTools,
6764
- routerToolLoop,
6765
- routerBrain,
6766
5017
  acquireSandbox,
6767
5018
  probeSandboxCapabilities,
6768
5019
  createSandboxLineage,
@@ -6775,9 +5026,6 @@ export {
6775
5026
  createExecutor,
6776
5027
  createExecutorRegistry,
6777
5028
  createInMemoryRunContext,
6778
- spendFromUsageEvents,
6779
- createBudgetPool,
6780
- createSupervisor,
6781
5029
  createEventBus,
6782
5030
  createCoordinationTools,
6783
5031
  driverAgent,
@@ -6836,4 +5084,4 @@ export {
6836
5084
  workerFromBackend,
6837
5085
  supervise
6838
5086
  };
6839
- //# sourceMappingURL=chunk-KVJQV342.js.map
5087
+ //# sourceMappingURL=chunk-6MR4IJRW.js.map