@tangle-network/agent-runtime 0.266.0 → 0.273.3

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 (76) hide show
  1. package/dist/{activation-BERiJjx5.js → activation-Cx2dKA_l.js} +2 -2
  2. package/dist/{activation-BERiJjx5.js.map → activation-Cx2dKA_l.js.map} +1 -1
  3. package/dist/{activation-VpxSbDKJ.d.ts → activation-IfDlhR3J.d.ts} +4 -4
  4. package/dist/agent.d.ts +2 -2
  5. package/dist/agent.js +2 -2
  6. package/dist/candidate-execution/index.js +2 -2
  7. package/dist/{coordination-driver-DdZ-nh_4.js → coordination-driver-CkcW4dxU.js} +173 -92
  8. package/dist/coordination-driver-CkcW4dxU.js.map +1 -0
  9. package/dist/{delegate-Ajx_PVyu.js → delegate-Dvb1-mE-.js} +2 -2
  10. package/dist/{delegate-Ajx_PVyu.js.map → delegate-Dvb1-mE-.js.map} +1 -1
  11. package/dist/durable.d.ts +3 -571
  12. package/dist/durable.js +93 -19
  13. package/dist/durable.js.map +1 -1
  14. package/dist/{graph-CK50N9vG.js → graph-C69Uxtzt.js} +17 -8
  15. package/dist/graph-C69Uxtzt.js.map +1 -0
  16. package/dist/{improvement-cycle-GRPoHLm1.js → improvement-cycle-CO2HRCQq.js} +10 -10
  17. package/dist/improvement-cycle-CO2HRCQq.js.map +1 -0
  18. package/dist/{index-CU2mlMfc.d.ts → index-D2ipSqkP.d.ts} +4335 -3055
  19. package/dist/index.d.ts +7 -451
  20. package/dist/index.js +14 -11
  21. package/dist/index.js.map +1 -1
  22. package/dist/intelligence.d.ts +9 -3
  23. package/dist/intelligence.js +13 -7
  24. package/dist/intelligence.js.map +1 -1
  25. package/dist/kernel.d.ts +4 -4
  26. package/dist/kernel.js +9 -9
  27. package/dist/{loop-runner-bin-cC16EPUq.js → loop-runner-bin-B9MIq9O7.js} +3 -3
  28. package/dist/{loop-runner-bin-cC16EPUq.js.map → loop-runner-bin-B9MIq9O7.js.map} +1 -1
  29. package/dist/{loop-runner-bin-XKZXM08Q.d.ts → loop-runner-bin-ThlwVkvo.d.ts} +3 -3
  30. package/dist/loop-runner-bin.d.ts +1 -1
  31. package/dist/loop-runner-bin.js +1 -1
  32. package/dist/mcp/bin.js +3 -3
  33. package/dist/mcp/index.d.ts +12 -6
  34. package/dist/mcp/index.js +7 -7
  35. package/dist/mcp/memory-bin.js +1 -1
  36. package/dist/{memory-server-Cn8LbAxO.js → memory-server-DXQ8IxGR.js} +2 -2
  37. package/dist/{memory-server-Cn8LbAxO.js.map → memory-server-DXQ8IxGR.js.map} +1 -1
  38. package/dist/{openai-tools-D3ajI_D2.d.ts → openai-tools-Bb0mAr5z.d.ts} +2 -2
  39. package/dist/{prepare-oHUQdC5-.js → prepare-DVlvGP7V.js} +2 -2
  40. package/dist/{prepare-oHUQdC5-.js.map → prepare-DVlvGP7V.js.map} +1 -1
  41. package/dist/profiles.d.ts +2 -2
  42. package/dist/{protected-model-port-DqF0qDU6.js → protected-model-port-BrWgsCnl.js} +2 -2
  43. package/dist/{protected-model-port-DqF0qDU6.js.map → protected-model-port-BrWgsCnl.js.map} +1 -1
  44. package/dist/{protected-redaction--F3v1oo8.js → protected-redaction-DylCC_ot.js} +14 -20
  45. package/dist/protected-redaction-DylCC_ot.js.map +1 -0
  46. package/dist/{provision-supervisor-Bf_bPaCv.js → provision-supervisor-BKAvsDtP.js} +3 -3
  47. package/dist/{provision-supervisor-Bf_bPaCv.js.map → provision-supervisor-BKAvsDtP.js.map} +1 -1
  48. package/dist/{runtime-hOLlAc1i.js → runtime-CHxXrUeZ.js} +1714 -854
  49. package/dist/runtime-CHxXrUeZ.js.map +1 -0
  50. package/dist/{server-DOb67ohd.js → server-2OeFrEVG.js} +4 -4
  51. package/dist/{server-DOb67ohd.js.map → server-2OeFrEVG.js.map} +1 -1
  52. package/dist/{stream-agent-turn-Gw9hLpBn.d.ts → stream-agent-turn-ewm3BZAp.d.ts} +34 -17
  53. package/dist/{structural-rollout-DV9YoQF6.js → structural-rollout-DCUprNpH.js} +2 -2
  54. package/dist/{structural-rollout-DV9YoQF6.js.map → structural-rollout-DCUprNpH.js.map} +1 -1
  55. package/dist/{substrate-CLt9S9ym.d.ts → substrate-VKjmrksz.d.ts} +2 -2
  56. package/dist/{supervise--njTtSL3.js → supervise-Dej5aSDa.js} +220 -52
  57. package/dist/supervise-Dej5aSDa.js.map +1 -0
  58. package/dist/{supervisor-B8UMAXya.js → supervisor-DdKPGluv.js} +1233 -303
  59. package/dist/supervisor-DdKPGluv.js.map +1 -0
  60. package/dist/testing.d.ts +2 -2
  61. package/dist/testing.js +62 -62
  62. package/dist/testing.js.map +1 -1
  63. package/dist/{tool-server-x9NEhvHZ.js → tool-server-Dqer2M4_.js} +30 -12
  64. package/dist/tool-server-Dqer2M4_.js.map +1 -0
  65. package/dist/tui/index.d.ts +1 -1
  66. package/dist/tui/index.js +1 -1
  67. package/dist/{types-CrnwLVYQ.d.ts → types-DMRc3jru.d.ts} +463 -105
  68. package/package.json +6 -5
  69. package/dist/coordination-driver-DdZ-nh_4.js.map +0 -1
  70. package/dist/graph-CK50N9vG.js.map +0 -1
  71. package/dist/improvement-cycle-GRPoHLm1.js.map +0 -1
  72. package/dist/protected-redaction--F3v1oo8.js.map +0 -1
  73. package/dist/runtime-hOLlAc1i.js.map +0 -1
  74. package/dist/supervise--njTtSL3.js.map +0 -1
  75. package/dist/supervisor-B8UMAXya.js.map +0 -1
  76. package/dist/tool-server-x9NEhvHZ.js.map +0 -1
@@ -14,7 +14,8 @@ import { access, chmod, copyFile, mkdir, mkdtemp, open, readFile, readdir, realp
14
14
  import { applyWorkspacePlan, hashWorkspacePlan, materializeProfile, resolveAgentProfileResources } from "@tangle-network/agent-profile-materialize";
15
15
  import { homedir, hostname, tmpdir } from "node:os";
16
16
  import { stripVTControlCharacters } from "node:util";
17
- import { deriveHexId, isW3CSpanId, isW3CTraceId } from "@tangle-network/agent-trace-contract";
17
+ import { ATTR, deriveHexId, isW3CSpanId, isW3CTraceId } from "@tangle-network/agent-trace-contract";
18
+ import { REDACTION_VERSION as REDACTION_VERSION$1, redact } from "@tangle-network/agent-eval/traces";
18
19
  import { SDKError, generateIdempotencyKey, withRetry } from "@tangle-network/agent-core";
19
20
  import { collectAgentFinalMessageText, collectAgentResponseText } from "@tangle-network/sandbox";
20
21
  import { request } from "node:http";
@@ -4797,7 +4798,7 @@ function sanitizeAgentRuntimeEvent(event, options = {}) {
4797
4798
  if (event.type === "questions_end") return {
4798
4799
  ...base,
4799
4800
  questions: event.questions.map((question) => sanitizeQuestion(question, options)),
4800
- userAnswers: options.includeUserAnswers ? event.userAnswers : redactRecord(event.userAnswers)
4801
+ userAnswers: options.includeUserAnswers ? included(event.userAnswers) : redactRecord(event.userAnswers)
4801
4802
  };
4802
4803
  if (event.type === "acquisition_start") return {
4803
4804
  ...base,
@@ -4845,7 +4846,7 @@ function sanitizeRuntimeStreamEvent(event, options = {}) {
4845
4846
  ...withTask,
4846
4847
  timestamp: event.timestamp,
4847
4848
  questions: event.questions.map((question) => sanitizeQuestion(question, options)),
4848
- userAnswers: options.includeUserAnswers ? event.userAnswers : redactRecord(event.userAnswers)
4849
+ userAnswers: options.includeUserAnswers ? included(event.userAnswers) : redactRecord(event.userAnswers)
4849
4850
  };
4850
4851
  if (event.type === "acquisition_start") return {
4851
4852
  type: event.type,
@@ -4868,7 +4869,7 @@ function sanitizeRuntimeStreamEvent(event, options = {}) {
4868
4869
  timestamp: event.timestamp,
4869
4870
  toolName: event.toolName,
4870
4871
  toolCallId: event.toolCallId,
4871
- args: options.includeControlPayloads ? event.args : void 0
4872
+ args: options.includeControlPayloads ? included(event.args) : void 0
4872
4873
  };
4873
4874
  if (event.type === "tool_result") return {
4874
4875
  type: event.type,
@@ -4877,7 +4878,7 @@ function sanitizeRuntimeStreamEvent(event, options = {}) {
4877
4878
  timestamp: event.timestamp,
4878
4879
  toolName: event.toolName,
4879
4880
  toolCallId: event.toolCallId,
4880
- result: options.includeControlPayloads ? event.result : void 0
4881
+ result: options.includeControlPayloads ? included(event.result) : void 0
4881
4882
  };
4882
4883
  if (event.type === "llm_call") return {
4883
4884
  type: event.type,
@@ -4900,8 +4901,8 @@ function sanitizeRuntimeStreamEvent(event, options = {}) {
4900
4901
  name: event.name,
4901
4902
  mimeType: event.mimeType,
4902
4903
  uri: options.includeEvidenceIds ? event.uri : void 0,
4903
- content: options.includeControlPayloads ? event.content : void 0,
4904
- metadata: options.includeMetadata ? event.metadata : void 0
4904
+ content: options.includeControlPayloads ? included(event.content) : void 0,
4905
+ metadata: options.includeMetadata ? included(event.metadata) : void 0
4905
4906
  };
4906
4907
  if (event.type === "proposal_created") return {
4907
4908
  type: event.type,
@@ -4909,16 +4910,16 @@ function sanitizeRuntimeStreamEvent(event, options = {}) {
4909
4910
  ...withSession,
4910
4911
  timestamp: event.timestamp,
4911
4912
  proposalId: event.proposalId,
4912
- title: options.includeControlPayloads ? event.title : void 0,
4913
- content: options.includeControlPayloads ? event.content : void 0,
4913
+ title: options.includeControlPayloads ? included(event.title) : void 0,
4914
+ content: options.includeControlPayloads ? included(event.content) : void 0,
4914
4915
  status: event.status
4915
4916
  };
4916
4917
  if (event.type === "final") {
4917
4918
  const sanitizedError = event.error !== void 0 ? {
4918
4919
  kind: event.error.kind,
4919
- message: event.error.message,
4920
+ message: included(event.error.message),
4920
4921
  status: event.error.status,
4921
- body: options.includeControlPayloads ? event.error.body : void 0
4922
+ body: options.includeControlPayloads ? included(event.error.body) : void 0
4922
4923
  } : void 0;
4923
4924
  return {
4924
4925
  type: event.type,
@@ -4927,8 +4928,8 @@ function sanitizeRuntimeStreamEvent(event, options = {}) {
4927
4928
  timestamp: event.timestamp,
4928
4929
  status: event.status,
4929
4930
  reason: event.reason,
4930
- text: options.includeControlPayloads ? event.text : void 0,
4931
- metadata: options.includeMetadata ? event.metadata : void 0,
4931
+ text: options.includeControlPayloads ? included(event.text) : void 0,
4932
+ metadata: options.includeMetadata ? included(event.metadata) : void 0,
4932
4933
  ...sanitizedError !== void 0 ? { error: sanitizedError } : {}
4933
4934
  };
4934
4935
  }
@@ -4945,9 +4946,9 @@ function sanitizeTask(task, options) {
4945
4946
  id: task.id,
4946
4947
  intent: task.intent,
4947
4948
  domain: task.domain,
4948
- inputs: options.includeInputs ? task.inputs : task.inputs ? "[redacted]" : void 0,
4949
+ inputs: options.includeInputs ? included(task.inputs) : task.inputs ? "[redacted]" : void 0,
4949
4950
  requiredKnowledge: task.requiredKnowledge?.map((requirement) => sanitizeKnowledgeRequirement(requirement, options)),
4950
- metadata: options.includeMetadata ? task.metadata : task.metadata ? "[redacted]" : void 0
4951
+ metadata: options.includeMetadata ? included(task.metadata) : task.metadata ? "[redacted]" : void 0
4951
4952
  };
4952
4953
  }
4953
4954
  function sanitizeRuntimeSession(session, options) {
@@ -4958,7 +4959,7 @@ function sanitizeRuntimeSession(session, options) {
4958
4959
  hasResumeToken: Boolean(session.resumeToken),
4959
4960
  createdAt: session.createdAt,
4960
4961
  updatedAt: session.updatedAt,
4961
- metadata: options.includeMetadata ? session.metadata : session.metadata ? "[redacted]" : void 0
4962
+ metadata: options.includeMetadata ? included(session.metadata) : session.metadata ? "[redacted]" : void 0
4962
4963
  };
4963
4964
  }
4964
4965
  function sanitizeKnowledgeRequirement(requirement, options) {
@@ -5007,8 +5008,8 @@ function sanitizeControlStep(step, options) {
5007
5008
  index: step.index,
5008
5009
  decisionType: step.decision.type,
5009
5010
  reason: step.decision.reason,
5010
- action: options.includeControlPayloads && step.decision.type === "continue" ? step.decision.action : void 0,
5011
- result: options.includeControlPayloads && actionOutcome?.ok ? actionOutcome.result : void 0,
5011
+ action: options.includeControlPayloads && step.decision.type === "continue" ? included(step.decision.action) : void 0,
5012
+ result: options.includeControlPayloads && actionOutcome?.ok ? included(actionOutcome.result) : void 0,
5012
5013
  actionOk: actionOutcome?.ok,
5013
5014
  actionError: actionOutcome?.ok === false ? actionOutcome.error : void 0,
5014
5015
  durationMs: actionOutcome?.durationMs,
@@ -5041,10 +5042,17 @@ function summarizeEvals(evals, options) {
5041
5042
  score: evalResult.score,
5042
5043
  severity: evalResult.severity,
5043
5044
  objective: evalResult.objective,
5044
- detail: options.includeEvalDetails ? evalResult.detail : void 0,
5045
- evidence: options.includeEvalDetails ? evalResult.evidence : void 0
5045
+ detail: options.includeEvalDetails ? included(evalResult.detail) : void 0,
5046
+ evidence: options.includeEvalDetails ? included(evalResult.evidence) : void 0
5046
5047
  }));
5047
5048
  }
5049
+ /**
5050
+ * An opted-in payload still goes through agent-eval's redaction core: the
5051
+ * flags decide whether content is shared, never whether credentials are.
5052
+ */
5053
+ function included(value) {
5054
+ return value === void 0 ? value : redact(value).value;
5055
+ }
5048
5056
  function redactRecord(record) {
5049
5057
  return Object.fromEntries(Object.keys(record).map((key) => [key, "[redacted]"]));
5050
5058
  }
@@ -5058,7 +5066,7 @@ function pickPublicStreamFields(event) {
5058
5066
  } : void 0;
5059
5067
  return {
5060
5068
  backend: event.backend,
5061
- message: event.message,
5069
+ message: included(event.message),
5062
5070
  recoverable: event.recoverable,
5063
5071
  ...sanitizedError !== void 0 ? { error: sanitizedError } : {}
5064
5072
  };
@@ -5171,25 +5179,30 @@ const GEN_AI = {
5171
5179
  * useless for the runs you most want to look at.
5172
5180
  */
5173
5181
  function createOpenInferenceFileExporter(filePath) {
5174
- const lines = [];
5182
+ let written = 0;
5183
+ let dropped = 0;
5175
5184
  let failed;
5176
- const append = (line) => {
5177
- try {
5178
- appendFileSync(filePath, `${line}\n`, "utf8");
5179
- } catch (error) {
5180
- failed ??= error instanceof Error ? error : new Error(String(error));
5181
- }
5182
- };
5183
5185
  return {
5184
5186
  exportSpan(span) {
5185
- append(JSON.stringify(toOpenInferenceLine(span)));
5186
- lines.push("");
5187
+ try {
5188
+ appendFileSync(filePath, `${JSON.stringify(toOpenInferenceLine(span))}\n`, "utf8");
5189
+ written += 1;
5190
+ } catch (error) {
5191
+ dropped += 1;
5192
+ failed ??= error instanceof Error ? error : new Error(String(error));
5193
+ }
5187
5194
  },
5188
5195
  async flush() {
5189
- if (failed) throw new Error(`OpenInference file exporter failed writing ${filePath}: ${failed.message}`);
5196
+ if (failed) throw new Error(`OpenInference file exporter failed writing ${filePath} (${dropped} spans dropped): ${failed.message}`);
5190
5197
  },
5191
- async shutdown() {
5192
- lines.length = 0;
5198
+ async shutdown() {},
5199
+ stats() {
5200
+ return {
5201
+ written,
5202
+ dropped,
5203
+ pending: 0,
5204
+ ...failed ? { lastError: failed.message } : {}
5205
+ };
5193
5206
  }
5194
5207
  };
5195
5208
  }
@@ -5240,68 +5253,172 @@ function toOpenInferenceLine(span) {
5240
5253
  };
5241
5254
  }
5242
5255
  /**
5243
- * Create an OTEL exporter. Returns undefined when no endpoint is configured.
5256
+ * Create an OTLP/HTTP exporter. Returns undefined when no endpoint is configured.
5257
+ *
5258
+ * One batch is in flight at a time; spans that arrive meanwhile wait in a queue bounded by
5259
+ * `maxQueueSize`. Every span ends in exactly one of `written` or `dropped`: a non-2xx response, a
5260
+ * network error, a timeout, an OTLP `partialSuccess.rejectedSpans` count and a full queue each count
5261
+ * as drops and set `lastError`. Nothing here throws into the caller's run; `flush()` reports the
5262
+ * loss, the same rule {@link createOpenInferenceFileExporter} follows.
5244
5263
  */
5245
5264
  function createOtelExporter(config) {
5246
5265
  const resolvedEndpoint = config?.endpoint ?? (typeof process !== "undefined" ? process.env.OTEL_EXPORTER_OTLP_ENDPOINT : void 0);
5247
5266
  if (!resolvedEndpoint) return void 0;
5248
- const endpoint = resolvedEndpoint;
5267
+ const url = `${resolvedEndpoint.replace(/\/+$/, "")}/v1/traces`;
5249
5268
  const headers = config?.headers ?? parseHeadersFromEnv();
5250
- const batchSize = config?.batchSize ?? 64;
5269
+ const batchSize = positiveInteger(config?.batchSize, 64);
5251
5270
  const flushIntervalMs = config?.flushIntervalMs ?? 5e3;
5252
- const serviceName = config?.serviceName ?? "agent-runtime";
5253
- const resourceAttrs = config?.resourceAttributes ?? {};
5254
- const pending = [];
5255
- let timer;
5271
+ const maxQueueSize = Math.max(positiveInteger(config?.maxQueueSize, 2048), batchSize);
5272
+ const timeoutMs = positiveInteger(config?.timeoutMs, 1e4);
5273
+ const resource = { attributes: toOtelAttributes({
5274
+ "service.name": config?.serviceName ?? "agent-runtime",
5275
+ ...config?.resourceAttributes ?? {}
5276
+ }) };
5277
+ const queue = [];
5278
+ let inFlight = 0;
5279
+ let written = 0;
5280
+ let dropped = 0;
5281
+ let droppedAtLastFlush = 0;
5282
+ let lastError;
5283
+ let sending;
5256
5284
  let stopped = false;
5257
- const exporter = {
5258
- exportSpan(span) {
5259
- if (stopped) return;
5260
- pending.push(span);
5261
- if (pending.length >= batchSize) doFlush();
5262
- },
5263
- async flush() {
5264
- await doFlush();
5265
- },
5266
- async shutdown() {
5267
- stopped = true;
5268
- if (timer !== void 0) {
5269
- clearInterval(timer);
5270
- timer = void 0;
5271
- }
5272
- await doFlush();
5273
- }
5285
+ const drop = (count, reason) => {
5286
+ dropped += count;
5287
+ lastError = reason;
5274
5288
  };
5275
- timer = setInterval(() => {
5276
- if (pending.length > 0) doFlush();
5277
- }, flushIntervalMs);
5278
- if (typeof timer === "object" && "unref" in timer) timer.unref();
5279
- async function doFlush() {
5280
- if (pending.length === 0) return;
5281
- const batch = pending.splice(0);
5289
+ async function send(batch) {
5282
5290
  const body = { resourceSpans: [{
5283
- resource: { attributes: toOtelAttributes({
5284
- "service.name": serviceName,
5285
- ...resourceAttrs
5286
- }) },
5291
+ resource,
5287
5292
  scopeSpans: [{
5288
5293
  scope: SCOPE,
5289
5294
  spans: batch
5290
5295
  }]
5291
5296
  }] };
5292
- const url = `${endpoint.replace(/\/+$/, "")}/v1/traces`;
5293
5297
  try {
5294
- await fetch(url, {
5298
+ const response = await fetch(url, {
5295
5299
  method: "POST",
5296
5300
  headers: {
5297
5301
  "content-type": "application/json",
5298
5302
  ...headers
5299
5303
  },
5300
- body: JSON.stringify(body)
5304
+ body: JSON.stringify(body),
5305
+ signal: AbortSignal.timeout(timeoutMs)
5301
5306
  });
5302
- } catch {}
5307
+ const text = await response.text().catch(() => "");
5308
+ if (!response.ok) {
5309
+ const detail = text ? `: ${text.slice(0, 200)}` : "";
5310
+ drop(batch.length, `HTTP ${response.status} from ${url}${detail}`);
5311
+ return;
5312
+ }
5313
+ const rejected = rejectedSpans(text, batch.length);
5314
+ if (rejected.count > 0) drop(rejected.count, `collector rejected ${rejected.count} spans: ${rejected.message}`);
5315
+ written += batch.length - rejected.count;
5316
+ } catch (error) {
5317
+ drop(batch.length, `POST ${url} failed: ${describeFetchError(error)}`);
5318
+ }
5319
+ }
5320
+ /** The single sender: it drains the queue batch by batch until the queue is empty. */
5321
+ function drain() {
5322
+ sending ??= (async () => {
5323
+ try {
5324
+ while (queue.length > 0) {
5325
+ const batch = queue.splice(0, batchSize);
5326
+ inFlight = batch.length;
5327
+ await send(batch);
5328
+ inFlight = 0;
5329
+ }
5330
+ } finally {
5331
+ sending = void 0;
5332
+ }
5333
+ })();
5334
+ return sending;
5335
+ }
5336
+ const timer = setInterval(() => {
5337
+ if (queue.length > 0) drain();
5338
+ }, flushIntervalMs);
5339
+ if (typeof timer === "object" && "unref" in timer) timer.unref();
5340
+ return {
5341
+ exportSpan(span) {
5342
+ if (stopped) {
5343
+ drop(1, "span exported after the exporter stopped");
5344
+ return;
5345
+ }
5346
+ if (queue.length + inFlight >= maxQueueSize) {
5347
+ drop(1, `queue full: ${maxQueueSize} spans already waiting on ${url}`);
5348
+ return;
5349
+ }
5350
+ queue.push(span);
5351
+ if (queue.length >= batchSize) drain();
5352
+ },
5353
+ async flush() {
5354
+ await drain();
5355
+ const lost = dropped - droppedAtLastFlush;
5356
+ droppedAtLastFlush = dropped;
5357
+ if (lost > 0) throw new Error(`OTLP exporter dropped ${lost} spans since the last flush: ${lastError}`);
5358
+ },
5359
+ async shutdown() {
5360
+ stopped = true;
5361
+ clearInterval(timer);
5362
+ await drain();
5363
+ },
5364
+ stats() {
5365
+ return {
5366
+ written,
5367
+ dropped,
5368
+ pending: queue.length + inFlight,
5369
+ ...lastError !== void 0 ? { lastError } : {}
5370
+ };
5371
+ }
5372
+ };
5373
+ }
5374
+ /**
5375
+ * Spans a 2xx OTLP/HTTP response still refused. The spec lets a collector accept a request and
5376
+ * reject part of it through `partialSuccess.rejectedSpans`; reading only the status would count
5377
+ * those spans as delivered. An empty or non-JSON body is a full success.
5378
+ */
5379
+ function rejectedSpans(text, batchLength) {
5380
+ if (!text.trim()) return {
5381
+ count: 0,
5382
+ message: ""
5383
+ };
5384
+ let parsed;
5385
+ try {
5386
+ parsed = JSON.parse(text);
5387
+ } catch {
5388
+ return {
5389
+ count: 0,
5390
+ message: ""
5391
+ };
5303
5392
  }
5304
- return exporter;
5393
+ if (parsed === null || typeof parsed !== "object") return {
5394
+ count: 0,
5395
+ message: ""
5396
+ };
5397
+ const partial = parsed.partialSuccess;
5398
+ if (partial === null || typeof partial !== "object") return {
5399
+ count: 0,
5400
+ message: ""
5401
+ };
5402
+ const { rejectedSpans: raw, errorMessage } = partial;
5403
+ const count = typeof raw === "string" ? Number(raw) : typeof raw === "number" ? raw : 0;
5404
+ if (!Number.isSafeInteger(count) || count <= 0) return {
5405
+ count: 0,
5406
+ message: ""
5407
+ };
5408
+ return {
5409
+ count: Math.min(count, batchLength),
5410
+ message: typeof errorMessage === "string" && errorMessage ? errorMessage : "no message"
5411
+ };
5412
+ }
5413
+ /** Node's fetch reports every socket failure as "fetch failed"; the cause names which one. */
5414
+ function describeFetchError(error) {
5415
+ if (!(error instanceof Error)) return String(error);
5416
+ const cause = error.cause;
5417
+ const code = cause && typeof cause === "object" && "code" in cause && typeof cause.code === "string" ? cause.code : void 0;
5418
+ return code ? `${error.message} (${code})` : error.message;
5419
+ }
5420
+ function positiveInteger(value, fallback) {
5421
+ return value !== void 0 && Number.isSafeInteger(value) && value > 0 ? value : fallback;
5305
5422
  }
5306
5423
  /**
5307
5424
  * Convert a LoopTraceEvent into an OtelSpan for export.
@@ -5382,8 +5499,10 @@ function buildRuntimeEventOtelSpans(events, traceId, parentSpanId, options = {})
5382
5499
  "tangle.runtime.event": serialized(record)
5383
5500
  };
5384
5501
  let name = `tangle.runtime.${event.type}`;
5502
+ if (parentSpanId) attrs[ATTR.parentConfidence] = "explicit";
5385
5503
  if (event.type === "tool_call" || event.type === "tool_result") {
5386
5504
  name = `agent.${event.type}`;
5505
+ if (event.type === "tool_call") attrs[ATTR.spanKind] = "TOOL";
5387
5506
  attrs["tool.name"] = event.toolName;
5388
5507
  if (event.toolCallId) attrs["tool.call_id"] = event.toolCallId;
5389
5508
  const mcp = mcpIdentity(event.toolName);
@@ -5393,6 +5512,7 @@ function buildRuntimeEventOtelSpans(events, traceId, parentSpanId, options = {})
5393
5512
  if (payload !== void 0) attrs[event.type === "tool_call" ? "tool.input" : "tool.output"] = serialized(payload);
5394
5513
  } else if (event.type === "llm_call") {
5395
5514
  name = "gen_ai.client.inference";
5515
+ attrs[ATTR.spanKind] = "LLM";
5396
5516
  attrs["gen_ai.request.model"] = event.model;
5397
5517
  if (event.tokensIn !== void 0) attrs["gen_ai.usage.input_tokens"] = event.tokensIn;
5398
5518
  if (event.tokensOut !== void 0) attrs["gen_ai.usage.output_tokens"] = event.tokensOut;
@@ -5446,11 +5566,25 @@ function buildLoopOtelSpans(events, traceId, rootParentSpanId) {
5446
5566
  kind: 1,
5447
5567
  startTimeUnixNano: msToNs(node.startMs),
5448
5568
  endTimeUnixNano: msToNs(node.endMs),
5449
- attributes: toOtelAttributes(node.attrs),
5569
+ attributes: toOtelAttributes({
5570
+ ...node.attrs,
5571
+ [ATTR.spanKind]: LOOP_SPAN_KIND[node.kind],
5572
+ ...node.parentSpanId === void 0 && rootParentSpanId ? { [ATTR.parentConfidence]: "explicit" } : {}
5573
+ }),
5450
5574
  status: { code: node.error ? 2 : 1 }
5451
5575
  }));
5452
5576
  }
5453
5577
  /**
5578
+ * The declared kind of each loop level. An iteration span carries its own token total, and an
5579
+ * undeclared span with tokens reads as an LLM call, so declaring AGENT keeps those tokens from
5580
+ * being counted a second time beside the model-call spans beneath it.
5581
+ */
5582
+ const LOOP_SPAN_KIND = {
5583
+ loop: "CHAIN",
5584
+ round: "CHAIN",
5585
+ branch: "AGENT"
5586
+ };
5587
+ /**
5454
5588
  * Sink-neutral core behind {@link buildLoopOtelSpans}: reconstruct the
5455
5589
  * loop → round → branch span tree from one run's ordered `LoopTraceEvent`
5456
5590
  * stream. Consumed by the OTEL mapper above and by the MCP delegation
@@ -5506,10 +5640,15 @@ function buildLoopSpanNodes(events) {
5506
5640
  const iterStartTs = /* @__PURE__ */ new Map();
5507
5641
  const placementByIdx = /* @__PURE__ */ new Map();
5508
5642
  let currentRoundId;
5643
+ /** Plan round index → its span id, so an iteration joins the round it records (`groupId`). */
5644
+ const roundIdByIndex = /* @__PURE__ */ new Map();
5509
5645
  let pendingRound;
5510
5646
  const flushRound = (endMs) => {
5511
5647
  if (!pendingRound) return;
5512
- out.push(make(pendingRound.id, rootId, "loop.round", "round", pendingRound.start, endMs, pendingRound.attrs));
5648
+ out.push(make(pendingRound.id, rootId, "loop.round", "round", pendingRound.start, endMs, {
5649
+ ...pendingRound.attrs,
5650
+ [ATTR.parentConfidence]: "explicit"
5651
+ }));
5513
5652
  pendingRound = void 0;
5514
5653
  };
5515
5654
  for (const e of events) {
@@ -5537,6 +5676,7 @@ function buildLoopSpanNodes(events) {
5537
5676
  attrs
5538
5677
  };
5539
5678
  currentRoundId = id;
5679
+ roundIdByIndex.set(roundIdx, id);
5540
5680
  break;
5541
5681
  }
5542
5682
  case "loop.iteration.started": {
@@ -5583,6 +5723,8 @@ function buildLoopSpanNodes(events) {
5583
5723
  if (err) attrs["tangle.loop.error"] = err;
5584
5724
  const gid = num(p.groupId);
5585
5725
  if (gid !== void 0) attrs["tangle.loop.iteration.group_id"] = gid;
5726
+ const recordedRoundId = gid === void 0 ? void 0 : roundIdByIndex.get(gid);
5727
+ attrs[ATTR.parentConfidence] = recordedRoundId ? "explicit" : "heuristic";
5586
5728
  const par = num(p.parentIndex);
5587
5729
  if (par !== void 0) attrs["tangle.loop.iteration.parent_index"] = par;
5588
5730
  const dur = num(p.durationMs);
@@ -5590,7 +5732,7 @@ function buildLoopSpanNodes(events) {
5590
5732
  const preview = str(p.outputPreview);
5591
5733
  if (preview) attrs["tangle.loop.iteration.output_preview"] = preview;
5592
5734
  Object.assign(attrs, placementByIdx.get(idx) ?? {});
5593
- out.push(make(generateSpanId(), currentRoundId ?? rootId, "loop.iteration", "branch", start, e.timestamp, attrs, err !== void 0));
5735
+ out.push(make(generateSpanId(), recordedRoundId ?? currentRoundId ?? rootId, "loop.iteration", "branch", start, e.timestamp, attrs, err !== void 0));
5594
5736
  break;
5595
5737
  }
5596
5738
  case "loop.decision":
@@ -5931,11 +6073,11 @@ const HARNESS_ROOTS = Object.freeze({
5931
6073
  ]),
5932
6074
  codex: Object.freeze([".codex/sessions", ".codex/history.jsonl"]),
5933
6075
  opencode: Object.freeze([
5934
- ".local/share/opencode/storage",
5935
- ".local/share/opencode/export",
5936
- ".local/share/opencode/log",
5937
6076
  ".opencode/sessions",
5938
- ".opencode/messages"
6077
+ ".opencode/messages",
6078
+ ".local/share/opencode/export",
6079
+ ".local/share/opencode/storage",
6080
+ ".local/share/opencode/log"
5939
6081
  ]),
5940
6082
  pi: Object.freeze([".pi/agent/sessions"])
5941
6083
  });
@@ -5973,6 +6115,126 @@ function harnessTranscriptUnavailable(reason) {
5973
6115
  return unavailable$2(reason);
5974
6116
  }
5975
6117
  /**
6118
+ * Read one executor's harness-transcript receipt without letting a broken port escape.
6119
+ *
6120
+ * The three answers this has to keep apart, because #1214 and #1244 are both about an artifact
6121
+ * that reads as coverage without being coverage:
6122
+ * - `available` the transcript survived;
6123
+ * - a reason the CAPTURE produced a box existed and could not be read;
6124
+ * - `executor-exposes-no-transcript` this runtime has no transcript to offer at all;
6125
+ * - `execution-never-started` no environment was ever created (the executor's
6126
+ * own seed, set before `create`);
6127
+ * - `capture-did-not-run` the port answered nothing, so the capture was
6128
+ * skipped rather than attempted and failed.
6129
+ *
6130
+ * Mirrors the supervise scope's `readInteractiveSession`: an absence is always a named reason,
6131
+ * never `undefined`. The scope reads each child with it, and `supervise` reads the root with it.
6132
+ */
6133
+ function readHarnessTranscript(executor) {
6134
+ if (!executor.harnessTranscript) return harnessTranscriptUnavailable("executor-exposes-no-transcript");
6135
+ let reported;
6136
+ try {
6137
+ reported = executor.harnessTranscript();
6138
+ } catch {
6139
+ return harnessTranscriptUnavailable("executor-exposes-no-transcript");
6140
+ }
6141
+ if (reported === void 0) return harnessTranscriptUnavailable("capture-did-not-run");
6142
+ const capture = reported;
6143
+ if (capture.status === "captured" && capture.artifact) return capture;
6144
+ if (capture.status === "unavailable" && capture.reason) return capture;
6145
+ return harnessTranscriptUnavailable("executor-exposes-no-transcript");
6146
+ }
6147
+ /**
6148
+ * Bounds on the subagent export, per capture. The capture runs after every turn and again at
6149
+ * release, so they bound how long a turn's end or a teardown can wait on it; each session they
6150
+ * leave out is named in `skipped`.
6151
+ */
6152
+ const MAX_SUBAGENT_EXPORTS = 32;
6153
+ const SUBAGENT_EXPORT_SECONDS = 120;
6154
+ /** The script starts no export after SUBAGENT_EXPORT_SECONDS and bounds each one at 30 s, so it
6155
+ * ends inside this. It is passed to `exec`, because the Sandbox SDK's default is 30 s. */
6156
+ const SUBAGENT_EXPORT_EXEC_MS = 180 * 1e3;
6157
+ const SUBAGENT_EXPORT_DIR = "~/.local/share/opencode/export";
6158
+ /**
6159
+ * The export, run in the box. For each sidecar record it reads the runtime home and the parent
6160
+ * session, collects the subagent sessions its messages name, and writes `opencode export` of each
6161
+ * one under `export`, where the capture reads it. It prints one `<state> <sessionId>` line per
6162
+ * subagent: `exported`, `failed`, or `unexported` (over a bound), then `done`. Every capture exports again,
6163
+ * because a later turn can continue a subagent and the store changes with every turn; an export
6164
+ * takes about 2 s in a Tangle box. Each export goes to a temporary file first, so a failed or
6165
+ * interrupted export never leaves a partial file for the capture to read.
6166
+ */
6167
+ const SUBAGENT_EXPORT_SCRIPT = String.raw`cd "$HOME" 2>/dev/null || exit 0
6168
+ out="$HOME/.local/share/opencode/export"
6169
+ t=""; command -v timeout >/dev/null 2>&1 && t="timeout 30"
6170
+ start=$(date +%s); n=0
6171
+ for rec in .opencode/sessions/*.json; do
6172
+ [ -f "$rec" ] || continue
6173
+ h=$(sed -n 's/.*"providerSessionHome"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$rec" | head -n 1)
6174
+ p=$(sed -n 's/.*"providerSessionId"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$rec" | head -n 1)
6175
+ db="$h/.local/share/opencode/opencode.db"
6176
+ case "$h" in /*) [ -f "$db" ] || continue ;; *) continue ;; esac
6177
+ ids=$(grep -rhoE '<task id=\\?"ses_[A-Za-z0-9]+|task_id: ses_[A-Za-z0-9]+|"sessionId"[[:space:]]*:[[:space:]]*"ses_[A-Za-z0-9]+' ".opencode/messages/$(basename "$rec" .json)" 2>/dev/null | grep -oE 'ses_[A-Za-z0-9]+' | sort -u)
6178
+ for id in $ids; do
6179
+ [ "$id" = "$p" ] && continue
6180
+ n=$((n + 1))
6181
+ if [ "$n" -gt ${MAX_SUBAGENT_EXPORTS} ] || [ $(($(date +%s) - start)) -ge ${SUBAGENT_EXPORT_SECONDS} ]; then echo "unexported $id"; continue; fi
6182
+ mkdir -p "$out" && tmp=$(mktemp) || { echo "failed $id"; continue; }
6183
+ if HOME="$h" XDG_DATA_HOME="$h/.local/share" XDG_CONFIG_HOME="$h/.config" XDG_STATE_HOME="$h/.local/state" XDG_CACHE_HOME="$h/.cache" OPENCODE_DISABLE_AUTOUPDATE=1 OPENCODE_DISABLE_MODELS_FETCH=1 $t opencode export "$id" > "$tmp" 2>/dev/null && [ -s "$tmp" ]; then
6184
+ mv "$tmp" "$out/$id.json" && echo "exported $id"
6185
+ else
6186
+ rm -f "$tmp"; echo "failed $id"
6187
+ fi
6188
+ done
6189
+ done
6190
+ echo done`;
6191
+ /**
6192
+ * Export each opencode subagent session a Tangle box's sidecar names, so the capture carries the
6193
+ * subagent's own steps (#1264).
6194
+ *
6195
+ * The sidecar runs opencode under a private runtime home and records the parent session under
6196
+ * `.opencode/sessions` and `.opencode/messages`. A `task` subagent runs in a child session, and
6197
+ * those records name it only in the tool's result (`<task id="ses_…">`, or `task_id: ses_…` on a
6198
+ * failure). Its steps are only in the runtime home's `opencode.db`, which a text capture cannot
6199
+ * carry. Each sidecar record names that home as `providerSessionHome`, so `opencode export` reads
6200
+ * the child from there. A shared-box worker exports its own subagents after each turn (#1371) and
6201
+ * keeps no sidecar record, so the export finds nothing to do for it.
6202
+ *
6203
+ * Returns the sessions it could not export, as `skipped` entries. An export that did not run, or
6204
+ * stopped before its `done` line, is named once, because the subagents it did not reach are
6205
+ * unknown.
6206
+ */
6207
+ async function exportSubagentSessions(environment, signal) {
6208
+ if (!environment.exec || signal?.aborted) return [];
6209
+ let stdout;
6210
+ try {
6211
+ stdout = (await environment.exec(SUBAGENT_EXPORT_SCRIPT, {
6212
+ timeoutMs: SUBAGENT_EXPORT_EXEC_MS,
6213
+ ...signal ? { signal } : {}
6214
+ })).stdout ?? "";
6215
+ } catch {
6216
+ return [{
6217
+ path: SUBAGENT_EXPORT_DIR,
6218
+ reason: "subagent-export-did-not-run"
6219
+ }];
6220
+ }
6221
+ const lines = stdout.split("\n").map((line) => line.trim());
6222
+ const gaps = [];
6223
+ for (const line of lines) {
6224
+ const match = /^(failed|unexported) (ses_[A-Za-z0-9]+)$/u.exec(line);
6225
+ if (match === null) continue;
6226
+ gaps.push({
6227
+ path: `${SUBAGENT_EXPORT_DIR}/${match[2]}.json`,
6228
+ reason: match[1] === "failed" ? "subagent-export-failed" : "subagent-export-over-bound"
6229
+ });
6230
+ }
6231
+ if (!lines.includes("done")) gaps.push({
6232
+ path: SUBAGENT_EXPORT_DIR,
6233
+ reason: "subagent-export-incomplete"
6234
+ });
6235
+ return gaps;
6236
+ }
6237
+ /**
5976
6238
  * Enumerate candidate transcript paths inside the environment.
5977
6239
  *
5978
6240
  * `find -printf` is given the roots and prints one `size<TAB>path` line per file. A missing root
@@ -6033,12 +6295,13 @@ async function captureHarnessTranscript(environment, harness, signal) {
6033
6295
  if (harness === void 0) return unavailable$2("unknown-harness");
6034
6296
  const roots = HARNESS_ROOTS[harness];
6035
6297
  if (!roots) return unavailable$2("unknown-harness");
6298
+ const unexported = harness === "opencode" ? await exportSubagentSessions(environment, signal) : [];
6036
6299
  const enumerated = await enumerate(environment, roots, signal);
6037
6300
  if (enumerated === void 0) return unavailable$2("enumeration-failed");
6038
6301
  const { paths } = enumerated;
6039
- if (paths.length === 0 && enumerated.omitted.length === 0) return unavailable$2("no-transcript");
6302
+ if (paths.length === 0 && enumerated.omitted.length === 0 && unexported.length === 0) return unavailable$2("no-transcript");
6040
6303
  const files = [];
6041
- const skipped = [...enumerated.omitted];
6304
+ const skipped = [...unexported, ...enumerated.omitted];
6042
6305
  let total = 0;
6043
6306
  for (const path of paths) {
6044
6307
  if (signal?.aborted) {
@@ -6112,6 +6375,73 @@ async function captureHarnessTranscript(environment, harness, signal) {
6112
6375
  });
6113
6376
  }
6114
6377
  /**
6378
+ * A transcript this process holds in memory, one JSON line per record, as a capture under the same
6379
+ * bounds a box's session files get: each file at most MAX_FILE_BYTES, all files together at most
6380
+ * MAX_TOTAL_BYTES. Lines fill `<name>-000.jsonl`, `<name>-001.jsonl`, ... in order, and a line is
6381
+ * never split. A line longer than one file, and every line past the total, is named in `skipped`
6382
+ * with its line number, so a cut transcript never reads as the whole one.
6383
+ */
6384
+ function harnessTranscriptFromLines(harness, name, lines) {
6385
+ if (lines.length === 0) return unavailable$2("no-transcript");
6386
+ const files = [];
6387
+ const skipped = [];
6388
+ let total = 0;
6389
+ let chunk = [];
6390
+ let chunkBytes = 0;
6391
+ const flush = () => {
6392
+ if (chunk.length === 0) return;
6393
+ const content = `${chunk.join("\n")}\n`;
6394
+ files.push(Object.freeze({
6395
+ path: `${name}-${String(files.length).padStart(3, "0")}.jsonl`,
6396
+ bytes: Buffer.byteLength(content, "utf8"),
6397
+ content
6398
+ }));
6399
+ chunk = [];
6400
+ chunkBytes = 0;
6401
+ };
6402
+ lines.forEach((line, index) => {
6403
+ const bytes = Buffer.byteLength(line, "utf8") + 1;
6404
+ const where = `${name} line ${index + 1}`;
6405
+ if (bytes > MAX_FILE_BYTES) {
6406
+ skipped.push({
6407
+ path: where,
6408
+ reason: "file-exceeds-byte-bound"
6409
+ });
6410
+ return;
6411
+ }
6412
+ if (total + bytes > MAX_TOTAL_BYTES) {
6413
+ skipped.push({
6414
+ path: where,
6415
+ reason: "total-byte-budget-exhausted"
6416
+ });
6417
+ return;
6418
+ }
6419
+ if (chunkBytes + bytes > MAX_FILE_BYTES) flush();
6420
+ chunk.push(line);
6421
+ chunkBytes += bytes;
6422
+ total += bytes;
6423
+ });
6424
+ flush();
6425
+ if (files.length === 0) return Object.freeze({
6426
+ status: "unavailable",
6427
+ reason: "nothing-carried",
6428
+ skipped: Object.freeze(skipped)
6429
+ });
6430
+ const artifact = Object.freeze({
6431
+ schemaVersion: 1,
6432
+ harness,
6433
+ files: Object.freeze(files),
6434
+ skipped: Object.freeze(skipped)
6435
+ });
6436
+ return Object.freeze({
6437
+ status: "captured",
6438
+ artifact,
6439
+ fileCount: files.length,
6440
+ totalBytes: total,
6441
+ skippedCount: skipped.length
6442
+ });
6443
+ }
6444
+ /**
6115
6445
  * Persist a capture under its own content ref and return the receipt a settlement carries.
6116
6446
  *
6117
6447
  * The scope calls this, not the executor: storage stays out of every provider and destroy site,
@@ -6267,81 +6597,40 @@ function publicCreateOptions(create) {
6267
6597
  }
6268
6598
  //#endregion
6269
6599
  //#region src/redact.ts
6270
- const redactedMarker = "[redacted]";
6271
- /** Secret-bearing key names: when an object key matches, its value is fully
6272
- * replaced regardless of the value's own content. Lowercased compare. */
6273
- const secretKeyPattern = /(api[-_]?key|secret|token|password|passwd|authorization|auth|private[-_]?key|credential|access[-_]?key|client[-_]?secret|session[-_]?(id|token)|cookie|bearer)/i;
6274
- /** AgentProfile's numeric model limits describe compute, not credentials. */
6275
- const tokenLimitKeyPattern = /^max(?:VisibleOutput|Reasoning|TotalOutput)Tokens$/;
6276
- /** In-value secret/PII patterns scrubbed from any string, regardless of key. */
6277
- const valuePatterns = [
6278
- /\bBearer\s+[A-Za-z0-9._\-+/=]{8,}/gi,
6279
- /\b(?:sk|pk|rk|ak)[-_][A-Za-z0-9_-]{12,}/g,
6280
- /\bgh[pousr]_[A-Za-z0-9]{20,}/g,
6281
- /\bAKIA[0-9A-Z]{16}\b/g,
6282
- /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g,
6283
- /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g
6284
- ];
6285
- /** Secret assignments embedded inside an otherwise opaque string, including
6286
- * serialized JSON and log-style `key=value` text. */
6287
- const secretAssignmentPattern = /((?:"|')?(?:api[-_]?key|secret|token|password|passwd|authorization|auth|private[-_]?key|credential|access[-_]?key|client[-_]?secret|session[-_]?(?:id|token)|cookie|bearer)(?:"|')?\s*[:=]\s*)(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|[^\s,;}]+)/gi;
6288
- /** Scrub a single string of in-value secret/PII patterns. */
6289
- function scrubString(input) {
6290
- let out = input;
6291
- for (const pattern of valuePatterns) out = out.replace(pattern, redactedMarker);
6292
- return out.replace(secretAssignmentPattern, `$1${redactedMarker}`);
6293
- }
6294
6600
  /**
6295
- * The built-in redactor. Walks objects and arrays; replaces values under
6296
- * secret-bearing keys wholesale; scrubs in-value patterns from every string.
6297
- * Cycle-safe (a seen-set short-circuits self-referential payloads to
6298
- * `'[circular]'`), depth-bounded, and total — never throws on customer input.
6601
+ * Redaction for values that may leave the Runtime process. The built-in
6602
+ * redactor is agent-eval's redaction core (`@tangle-network/agent-eval/traces`,
6603
+ * default profile): credentials found by field name or value shape are
6604
+ * replaced whole, email, card, SSN and phone values in place, and token counts
6605
+ * such as `inputTokens` or `max_tokens` are kept. A customer with
6606
+ * domain-specific PII supplies their own `redact` hook.
6607
+ *
6608
+ * This is narrower than `src/sanitize.ts`, which drops fields of the runtime's
6609
+ * *event envelope* unless the caller opts in: here the value is opaque customer
6610
+ * payload, so the scrub is value-shaped, not schema-shaped.
6611
+ *
6612
+ * @experimental
6613
+ */
6614
+ /**
6615
+ * The built-in redactor. Cycle-safe, depth-bounded and total: it never throws
6616
+ * on customer input and never mutates it.
6299
6617
  */
6300
6618
  function defaultRedactor(value) {
6301
- return walk(value, /* @__PURE__ */ new WeakSet(), 0);
6302
- }
6303
- const maxDepth = 32;
6304
- function walk(value, seen, depth) {
6305
- if (depth > maxDepth) return "[truncated]";
6306
- if (typeof value === "string") return scrubString(value);
6307
- if (value === null || typeof value !== "object") return value;
6308
- if (seen.has(value)) return "[circular]";
6309
- seen.add(value);
6310
- if (Array.isArray(value)) return value.map((item) => walk(item, seen, depth + 1));
6311
- const out = {};
6312
- for (const [key, v] of Object.entries(value)) {
6313
- const tokenLimit = tokenLimitKeyPattern.test(key) && typeof v === "number" && Number.isSafeInteger(v) && v >= 0;
6314
- if (secretKeyPattern.test(key) && !tokenLimit) {
6315
- out[key] = redactedMarker;
6316
- continue;
6317
- }
6318
- out[key] = walk(v, seen, depth + 1);
6319
- }
6320
- return out;
6619
+ return redact(value).value;
6321
6620
  }
6322
6621
  /** Stable identity input for saved work that depends on built-in redaction behavior. */
6323
6622
  function defaultRedactorIdentityMaterial() {
6324
- const patternIdentity = (pattern) => ({
6325
- source: pattern.source,
6326
- flags: pattern.flags
6327
- });
6328
6623
  return {
6329
- marker: redactedMarker,
6330
- secretKeyPattern: patternIdentity(secretKeyPattern),
6331
- tokenLimitKeyPattern: patternIdentity(tokenLimitKeyPattern),
6332
- valuePatterns: valuePatterns.map(patternIdentity),
6333
- secretAssignmentPattern: patternIdentity(secretAssignmentPattern),
6334
- maxDepth,
6335
- scrubString: Function.prototype.toString.call(scrubString),
6336
- walk: Function.prototype.toString.call(walk),
6337
- defaultRedactor: Function.prototype.toString.call(defaultRedactor)
6624
+ core: "@tangle-network/agent-eval/traces redact",
6625
+ profile: "default",
6626
+ version: REDACTION_VERSION$1
6338
6627
  };
6339
6628
  }
6340
6629
  /**
6341
6630
  * Resolve the redactor a client uses. A caller-supplied hook handles
6342
6631
  * domain-specific values first, then the built-in scrubber still removes
6343
- * common credentials and email addresses. Returning `false` is the explicit
6344
- * opt-out for already-reviewed public values.
6632
+ * credentials and personal data. Returning `false` is the explicit opt-out for
6633
+ * already-reviewed public values.
6345
6634
  */
6346
6635
  function resolveRedactor(redact) {
6347
6636
  if (redact === false) return (value) => value;
@@ -7404,7 +7693,8 @@ function assertRetainedRunReplayMaterial(provider, replay, admission) {
7404
7693
  }, identity, retainedContextTransfer(replay.turn.contextTransfer)));
7405
7694
  }
7406
7695
  function retainedRunIntent(options, identity, contextTransfer) {
7407
- const requestedProfileDigest = canonicalCandidateDigest(options.environment.profile);
7696
+ const { profile } = options.environment;
7697
+ const requestedProfileDigest = typeof profile === "string" ? canonicalCandidateDigest(profile) : canonicalAgentProfileDigest(profile);
7408
7698
  const requestDigest = canonicalCandidateDigest({
7409
7699
  kind: "retained-run-intent.v1",
7410
7700
  provider: options.provider.name,
@@ -8263,6 +8553,7 @@ function createProviderExecutor(provider, profile, ctx, options, placement) {
8263
8553
  let workspaceCapturePromise;
8264
8554
  let workspaceCleanupPromise;
8265
8555
  let retainedReleasePromise;
8556
+ let releaseReadTried = false;
8266
8557
  let workspaceOutcome;
8267
8558
  let workspacePreservationRequired = false;
8268
8559
  let workspaceRunActive = false;
@@ -8615,6 +8906,11 @@ function createProviderExecutor(provider, profile, ctx, options, placement) {
8615
8906
  environment = target;
8616
8907
  resetWorkspaceState(target);
8617
8908
  }
8909
+ if (harnessTranscript.status !== "captured" && !releaseReadTried) {
8910
+ releaseReadTried = true;
8911
+ const capture = await captureHarnessTranscript(target, profile.harness, signal);
8912
+ if (capture.status === "captured") harnessTranscript = capture;
8913
+ }
8618
8914
  const result = await destroyEnvironment(signal);
8619
8915
  if (!result.destroyed) return [receipt(false, result.detail, result.permanent)];
8620
8916
  pending = false;
@@ -8966,7 +9262,7 @@ async function providerExecutionSource(args, turn, signal) {
8966
9262
  const dispatched = [...admissions].reverse().find((admission) => admission.phase === "dispatched");
8967
9263
  const intent = admissions.find((admission) => admission.phase === "intent");
8968
9264
  const environmentAdmission = admissions.find((admission) => admission.phase === "environment");
8969
- if (args.recovering) {
9265
+ if (args.recovering && admissions.length > 0) {
8970
9266
  if (!intent) throw new Error("retained provider execution has no original intent");
8971
9267
  assertRetainedRunReplayMaterial(args.provider, material, intent);
8972
9268
  }
@@ -9014,7 +9310,7 @@ async function providerExecutionSource(args, turn, signal) {
9014
9310
  if (recovered.outcome !== "recovered") throw new Error(`retained provider execution is ${recovered.outcome}`);
9015
9311
  handle = recovered.handle;
9016
9312
  } else {
9017
- if (args.recovering) throw new Error("retained provider execution has no durable admission");
9313
+ if (args.recovering && admissions.length > 0) throw new Error("retained provider execution has no durable admission");
9018
9314
  handle = await startRetainedRun({
9019
9315
  provider: args.provider,
9020
9316
  ...material,
@@ -16636,6 +16932,7 @@ var FileResultBlobStore = class {
16636
16932
  return `${this.dir}/${outRef.replace(/:/g, "-")}.json`;
16637
16933
  }
16638
16934
  };
16935
+ /** @internal shared with the SQL-backed store. */
16639
16936
  function encodeResultBlob(outRef, artifact) {
16640
16937
  const detached = detachedSnapshot(artifact, "result blob");
16641
16938
  assertContentAddress(outRef, detached);
@@ -16648,11 +16945,21 @@ function encodeResultBlob(outRef, artifact) {
16648
16945
  text
16649
16946
  };
16650
16947
  }
16948
+ /** @internal shared with the SQL-backed store. */
16651
16949
  function assertContentAddress(outRef, artifact) {
16652
16950
  const expected = contentAddress(artifact);
16653
16951
  if (outRef !== expected) throw new Error(`blob outRef '${outRef}' does not match the artifact content hash '${expected}'; a content-addressed store refuses a mismatched ref (breaks the replay invariant)`);
16654
16952
  }
16655
16953
  /**
16954
+ * Append every event as one grouped publication where the journal supports it (`appendEvents`),
16955
+ * preserving legacy per-event appends otherwise — the SQL contexts' fenced head advances once.
16956
+ * @internal
16957
+ */
16958
+ async function appendSpawnEvents(journal, root, events) {
16959
+ if (journal.appendEvents !== void 0) return journal.appendEvents(root, events);
16960
+ for (const event of events) await journal.appendEvent(root, event);
16961
+ }
16962
+ /**
16656
16963
  * In-memory `SpawnJournal`. Appends are observed-committed only; the impl enforces
16657
16964
  * the corruption guards a durable replay rests on:
16658
16965
  * - an event before `beginTree` is a corrupted tree (fail loud),
@@ -17085,6 +17392,7 @@ function servedIdentityParts(model) {
17085
17392
  };
17086
17393
  }
17087
17394
  /** One validation implementation for memory, durable append, and cold replay. */
17395
+ /** @internal shared with the SQL-backed store. */
17088
17396
  var SpawnEventIndex = class {
17089
17397
  root;
17090
17398
  nodes = /* @__PURE__ */ new Map();
@@ -17752,6 +18060,96 @@ function executionTaskPrompt$1(task, configuredPrompt) {
17752
18060
  return prompt;
17753
18061
  }
17754
18062
  //#endregion
18063
+ //#region src/runtime/supervise/router-transcript.ts
18064
+ /**
18065
+ * The conversation of a router-brained agent, kept as it happens.
18066
+ *
18067
+ * A router-brained agent (`harness` omitted or `cli-base`) runs its tool loop in this process, so
18068
+ * its whole conversation is in the loop's `messages` and nowhere else. Before this, Runtime
18069
+ * metered each turn's usage and tool-call names and kept nothing the agent said, saw, or asked a
18070
+ * tool to do: a 316-agent tree on 2026-09-24 settled with 0 of 316 transcripts, and the 37 agents
18071
+ * still running when its driver process stopped left no record at all (agent-runtime#1377).
18072
+ *
18073
+ * The recorder keeps each message once, in the order the model saw it, and serves two readers:
18074
+ * - each turn's `agent.turn` event carries the messages that turn added (the loop's inputs since
18075
+ * the previous turn, then the reply), so an observer journal holds every agent's conversation
18076
+ * while the run is live;
18077
+ * - `capture()` returns the whole conversation as a harness transcript, so the agent settles
18078
+ * with an `available` receipt instead of `executor-exposes-no-transcript`.
18079
+ *
18080
+ * The loop mutates `messages` in place: it appends the reply it was given, each tool result, and
18081
+ * any inbox message, and a compaction replaces the middle with a distilled note. The recorder
18082
+ * therefore reads new messages twice per turn, before compaction can remove them and again when
18083
+ * the model is called, and it identifies a message by object identity. The loop's own copy of a
18084
+ * reply is skipped, because the recorder already kept the reply when the model returned it.
18085
+ */
18086
+ /** The harness name a router-brained agent's transcript carries. */
18087
+ const ROUTER_TRANSCRIPT_HARNESS = "router";
18088
+ /**
18089
+ * The most bytes of one message's `content` a turn event carries. A longer content is cut, and
18090
+ * the message says so with its full length, so a reader never takes a cut message for the whole.
18091
+ * The settled transcript keeps the full content, within the bounds of `harnessTranscriptFromLines`.
18092
+ */
18093
+ const TURN_CONTENT_BYTES = 256 * 1024;
18094
+ function createRouterTranscript() {
18095
+ const kept = [];
18096
+ const seen = /* @__PURE__ */ new WeakSet();
18097
+ let turnStart = 0;
18098
+ let replyEchoPending = false;
18099
+ let live;
18100
+ const observe = (messages) => {
18101
+ live = messages;
18102
+ for (const message of messages) {
18103
+ if (message === null || typeof message !== "object" || seen.has(message)) continue;
18104
+ seen.add(message);
18105
+ if (replyEchoPending) {
18106
+ replyEchoPending = false;
18107
+ if (message.role === "assistant") continue;
18108
+ }
18109
+ kept.push(message);
18110
+ }
18111
+ };
18112
+ return {
18113
+ observe,
18114
+ reply(reply) {
18115
+ const message = {
18116
+ role: "assistant",
18117
+ content: reply.content ?? "",
18118
+ ...reply.toolCalls && reply.toolCalls.length > 0 ? { tool_calls: reply.toolCalls.map((call) => ({
18119
+ id: call.id,
18120
+ type: "function",
18121
+ function: {
18122
+ name: call.name,
18123
+ arguments: call.arguments
18124
+ }
18125
+ })) } : {}
18126
+ };
18127
+ kept.push(message);
18128
+ replyEchoPending = true;
18129
+ const added = kept.slice(turnStart).map(forTurnEvent);
18130
+ turnStart = kept.length;
18131
+ return added;
18132
+ },
18133
+ capture() {
18134
+ if (live !== void 0) observe(live);
18135
+ if (kept.length === 0) return harnessTranscriptUnavailable("execution-never-started");
18136
+ return harnessTranscriptFromLines(ROUTER_TRANSCRIPT_HARNESS, "conversation", kept.map((message) => JSON.stringify(message)));
18137
+ }
18138
+ };
18139
+ }
18140
+ function forTurnEvent(message) {
18141
+ const content = message.content;
18142
+ if (typeof content !== "string") return message;
18143
+ const bytes = Buffer.byteLength(content);
18144
+ if (bytes <= 262144) return message;
18145
+ return {
18146
+ ...message,
18147
+ content: Buffer.from(content).subarray(0, TURN_CONTENT_BYTES).toString("utf8"),
18148
+ contentBytes: bytes,
18149
+ contentCut: true
18150
+ };
18151
+ }
18152
+ //#endregion
17755
18153
  //#region src/runtime/supervise/sandbox-session.ts
17756
18154
  /** Ceiling on continuation turns. Turn 0 is the task; every later turn is a folded steer, so
17757
18155
  * this bounds how many times a supervisor may redirect ONE worker before it must respawn. */
@@ -18363,6 +18761,7 @@ const routerInlineExecutor = (spec, ctx) => {
18363
18761
  const requestIdentity = routerRequestIdentity(ctx);
18364
18762
  const controller = linkAbort(ctx.signal);
18365
18763
  let artifact;
18764
+ const transcript = createRouterTranscript();
18366
18765
  const executionId = ctx.node?.nodeId ?? `router-request-${randomUUID()}`;
18367
18766
  const attemptId = ctx.node?.attemptId ?? newExecutionAttemptId(executionId);
18368
18767
  let executor;
@@ -18370,6 +18769,7 @@ const routerInlineExecutor = (spec, ctx) => {
18370
18769
  runtime: "router",
18371
18770
  async execute(task, signal) {
18372
18771
  const messages = taskToMessages(task, spec, profileExecution.systemPrompt);
18772
+ transcript.observe(messages);
18373
18773
  const started = Date.now();
18374
18774
  const linked = linkAbort(signal, controller.signal).signal;
18375
18775
  const extraBody = {
@@ -18407,6 +18807,10 @@ const routerInlineExecutor = (spec, ctx) => {
18407
18807
  ...requestIdentity
18408
18808
  }));
18409
18809
  if (r.model !== void 0) recordRuntimeOwnedProviderModel(executor, r.model);
18810
+ transcript.reply({
18811
+ content: r.content,
18812
+ toolCalls: "toolCalls" in r ? r.toolCalls : []
18813
+ });
18410
18814
  const spent = {
18411
18815
  ...addResourceSpend(r.resources),
18412
18816
  iterations: 1,
@@ -18442,6 +18846,7 @@ const routerInlineExecutor = (spec, ctx) => {
18442
18846
  };
18443
18847
  return artifact;
18444
18848
  },
18849
+ harnessTranscript: () => transcript.capture(),
18445
18850
  cancel(_request) {
18446
18851
  controller.abort("executor cancelled");
18447
18852
  return Promise.resolve(localAbortCancellation("the Router chat-completions API exposes no cancel operation; the local request was aborted and the provider may still bill the completion"));
@@ -18542,12 +18947,14 @@ const routerToolsInlineExecutor = (spec, ctx) => {
18542
18947
  const controller = linkAbort(ctx.signal);
18543
18948
  const inbox = createInbox();
18544
18949
  let artifact;
18950
+ const transcript = createRouterTranscript();
18545
18951
  const executionId = ctx.node?.nodeId ?? `router-tools-run-${randomUUID()}`;
18546
18952
  const attemptId = ctx.node?.attemptId ?? newExecutionAttemptId(executionId);
18547
18953
  let executor;
18548
18954
  executor = attestRuntimeOwnedExecutor({
18549
18955
  runtime: "router",
18550
18956
  deliver: (m) => inbox.deliver(m),
18957
+ harnessTranscript: () => transcript.capture(),
18551
18958
  async execute(task, signal) {
18552
18959
  const started = Date.now();
18553
18960
  const messages = seam.initialMessages ? taskToMessages({ messages: [...seam.initialMessages, {
@@ -18586,6 +18993,7 @@ const routerToolsInlineExecutor = (spec, ctx) => {
18586
18993
  interruptSig.addEventListener("abort", abortTurn, { once: true });
18587
18994
  const cleanup = () => external.removeEventListener("abort", abortTurn);
18588
18995
  let res;
18996
+ transcript.observe(messages);
18589
18997
  try {
18590
18998
  recordRuntimeOwnedProviderAttemptStart(executor);
18591
18999
  res = await (profileExecution.stream === true ? streamRouterChatWithTools : routerChatWithTools)({
@@ -18622,6 +19030,10 @@ const routerToolsInlineExecutor = (spec, ctx) => {
18622
19030
  }
18623
19031
  cleanup();
18624
19032
  turns += 1;
19033
+ transcript.reply({
19034
+ content: res.content,
19035
+ toolCalls: res.toolCalls
19036
+ });
18625
19037
  const priorResources = resources;
18626
19038
  resources = addResourceSpend(resources, res.resources).resources;
18627
19039
  resources = addResourceSpend(Object.fromEntries(Object.entries(resources ?? {}).map(([name, value]) => [name, {
@@ -21025,14 +21437,15 @@ function settledNodeEvidence(subject, settlement, settledAt) {
21025
21437
  trace: detachedSnapshot(settlement.trace, "worker trace evidence")
21026
21438
  };
21027
21439
  }
21028
- /** The `agent.child` payload of the release: the settlement restated as released, `settledAt`
21029
- * kept at the settlement instant and `metered` omitted so the driver's inference is not summed
21030
- * twice. The sweep and the resume heal emit it from the same builder. */
21031
- function releasedChildPayload(subject, settlement, settledAt, releasedAt) {
21440
+ /** The `agent.child` payload of a closed retained slot: the settlement restated with the state
21441
+ * the slot closed in, `settledAt` kept at the settlement instant and `metered` omitted so the
21442
+ * driver's inference is not summed twice. The sweep, the final close and the resume heal emit
21443
+ * it from the same builder. */
21444
+ function releasedChildPayload(subject, settlement, settledAt, releasedAt, retainedExecution = "released") {
21032
21445
  return {
21033
21446
  childId: subject.id,
21034
21447
  status: "down",
21035
- retainedExecution: "released",
21448
+ retainedExecution,
21036
21449
  ...settlement.retainedPendingCause === void 0 ? {} : { retainedPendingCause: settlement.retainedPendingCause },
21037
21450
  releasedAt,
21038
21451
  ...settlement.outRef === void 0 ? {} : { outRef: settlement.outRef },
@@ -21180,7 +21593,7 @@ async function prepareInterruptedExecutors(opts, events, signal, now, parentId =
21180
21593
  continue;
21181
21594
  }
21182
21595
  const admissions = current.flatMap((event) => event.kind === "execution-admitted" ? [event.admission] : []);
21183
- if (!opts.recoverExecutor || admissions.length === 0 && !node.ownedTreeRoot) continue;
21596
+ if (!opts.recoverExecutor || admissions.length === 0 && !node.ownedTreeRoot && (opts.journal.appendEvents === void 0 || latestInput === void 0)) continue;
21184
21597
  const taskRef = inputs[0]?.taskRef;
21185
21598
  if (!node.profileRef || !taskRef || !node.identity?.profileDigest || !node.identity.taskDigest) throw new RuntimeRunStateError(`cannot recover '${node.id}' without exact profile and task bytes`);
21186
21599
  const profile = agentProfileSchema.parse(await opts.blobs.get(node.profileRef));
@@ -21273,7 +21686,11 @@ async function assertRecordedResult(node, result, events, opts) {
21273
21686
  * The keyed assignments a prior journal proves: every `spawned` event carrying a `key`, resolved
21274
21687
  * against the replayed settlements. A key spawned more than once (a retry chain) resolves to its
21275
21688
  * LATEST attempt — iterate in ordinal order so later spawns overwrite earlier ones. A spawned
21276
- * event with no matching settlement is `in-doubt`: the process died with it in flight.
21689
+ * event with no matching settlement is `in-doubt`: the process died with it in flight — UNLESS
21690
+ * the spawn's own runtime proves the execution cannot have outlived the process (`inline`, the
21691
+ * same predicate the budget layer charges no uncertain reservation for), in which case the resume
21692
+ * itself is the terminal evidence and the key resolves `down` with a derived reason, so a re-spawn
21693
+ * under the same key retries instead of wedging in-doubt.
21277
21694
  */
21278
21695
  function keyedAssignments(events, settled) {
21279
21696
  const byId = new Map(settled.map((s) => [s.handle.id, s]));
@@ -21283,7 +21700,13 @@ function keyedAssignments(events, settled) {
21283
21700
  if (ev.key === void 0) continue;
21284
21701
  if (ev.identity === void 0) throw new RuntimeRunStateError(`supervisor: keyed node '${ev.id}' has no durable execution identity`);
21285
21702
  const s = byId.get(ev.id);
21286
- keys.set(ev.key, s === void 0 ? {
21703
+ keys.set(ev.key, s === void 0 ? ev.runtime === "inline" ? {
21704
+ id: ev.id,
21705
+ label: ev.label,
21706
+ identity: ev.identity,
21707
+ state: "down",
21708
+ reason: `interrupted: the process died with '${ev.label}' in flight and its '${ev.runtime}' runtime cannot outlive that process, so the resume proves the attempt dead`
21709
+ } : {
21287
21710
  id: ev.id,
21288
21711
  label: ev.label,
21289
21712
  identity: ev.identity,
@@ -22620,6 +23043,7 @@ const runtimeOwnedProviderMeters = /* @__PURE__ */ new WeakMap();
22620
23043
  const pauseRecorders = /* @__PURE__ */ new WeakMap();
22621
23044
  const recoveryStarters = /* @__PURE__ */ new WeakMap();
22622
23045
  const retainedReleasers = /* @__PURE__ */ new WeakMap();
23046
+ const retainedSlotClosers = /* @__PURE__ */ new WeakMap();
22623
23047
  const teardownRetriers = /* @__PURE__ */ new WeakMap();
22624
23048
  const teardownRetriable = /* @__PURE__ */ new WeakMap();
22625
23049
  /** The retained owner environments a scope's last release could not confirm destroyed. */
@@ -22707,6 +23131,25 @@ async function releaseRetainedEnvironments(scope) {
22707
23131
  return unconfirmedTeardowns(scope);
22708
23132
  }
22709
23133
  /**
23134
+ * @internal Close the cursor slot of every retained child this scope and its nested scopes still
23135
+ * hold open, once the settlement is final and the release and its retries are done.
23136
+ *
23137
+ * The release sweep closes a slot only when it confirms the environment destroyed, and nothing
23138
+ * else ever closed the rest: a refused delete, a teardown probe that failed after a destroy, or an
23139
+ * admission that timed out before `create` named an environment. Measured on the Discovery fleet
23140
+ * of 2026-09-23/24 (Runtime 0.249.1 to 0.261.0): 338 of 1,620 agents never settled, so they had no
23141
+ * terminal record, no spend but the reservation ceiling, and no transcript receipt (#1301). A
23142
+ * settlement under `retainedAtSettlement: 'release'` is final, so no process will recover these
23143
+ * executions. Each slot closes with the settlement the driver already received, under the seq it
23144
+ * saw, marked `retainedExecution: 'release-unconfirmed'`. The environment it may still hold stays
23145
+ * named by its `teardown-unconfirmed` record for a sweeper. Never call this on a run a later
23146
+ * process may resume.
23147
+ */
23148
+ async function closeRetainedSlots(scope) {
23149
+ const close = retainedSlotClosers.get(scope);
23150
+ if (close) await close();
23151
+ }
23152
+ /**
22710
23153
  * @internal Everything this scope cannot prove destroyed: its settled children whose teardown is
22711
23154
  * unconfirmed and, after a release, the retained owner environment that release could not
22712
23155
  * confirm. Read live, so a later retry that confirms a node removes it.
@@ -22877,6 +23320,14 @@ function createScope(args) {
22877
23320
  identity: prior.identity,
22878
23321
  reason: prior.settled.reason
22879
23322
  });
23323
+ } else if (prior.state === "down" && prior.settled === void 0) {
23324
+ if (prior.identity === void 0) continue;
23325
+ keyed.set(key, {
23326
+ state: "down",
23327
+ id: prior.id,
23328
+ identity: prior.identity,
23329
+ reason: prior.reason ?? "interrupted: resume proved the prior attempt dead"
23330
+ });
22880
23331
  } else if (prior.identity !== void 0) keyed.set(key, {
22881
23332
  state: "in-doubt",
22882
23333
  id: prior.id,
@@ -23225,6 +23676,7 @@ function createScope(args) {
23225
23676
  askTeardown,
23226
23677
  ...executor.heldEnvironments ? { readHeldEnvironments: executor.heldEnvironments.bind(executor) } : {},
23227
23678
  ...nestedTeardownScopes.has(executor) ? { readNestedScope: nestedTeardownScopes.get(executor) } : {},
23679
+ ...executor.harnessTranscript ? { readTranscriptAtRelease: () => persistHarnessTranscript(readHarnessTranscript(executor), args.blobs) } : {},
23228
23680
  teardownAttempts: 0,
23229
23681
  abortChild: (reason) => controller.abort(reason)
23230
23682
  };
@@ -23241,29 +23693,31 @@ function createScope(args) {
23241
23693
  });
23242
23694
  const profileRef = contentAddress(spec.profile);
23243
23695
  const taskRef = identity?.taskDigest === void 0 ? void 0 : contentAddress(task);
23244
- const spawnCommitted = recovery ? Promise.resolve() : args.blobs.put(profileRef, spec.profile).then(() => taskRef === void 0 ? void 0 : args.blobs.put(taskRef, task)).then(() => args.journal.appendEvent(args.root, {
23245
- kind: "spawned",
23246
- id,
23247
- parent: args.parentId,
23248
- label: opts.label,
23249
- ...opts.key !== void 0 ? { key: opts.key } : {},
23250
- ...opts.assignmentId === void 0 ? {} : { assignmentId: opts.assignmentId },
23251
- ...opts.successorOf === void 0 ? {} : { successorOf: opts.successorOf },
23252
- budget: opts.budget,
23253
- runtime: executor.runtime,
23254
- ...ownedTreeRoot === void 0 ? {} : { ownedTreeRoot },
23255
- ...identity ? { identity } : {},
23256
- profileRef,
23257
- seq: ordinal,
23258
- at: new Date(now()).toISOString()
23259
- })).then(async () => {
23260
- if (taskRef !== void 0) await args.journal.appendEvent(args.root, {
23696
+ const spawnCommitted = recovery ? Promise.resolve() : args.blobs.put(profileRef, spec.profile).then(() => taskRef === void 0 ? void 0 : args.blobs.put(taskRef, task)).then(async () => {
23697
+ const events = [{
23698
+ kind: "spawned",
23699
+ id,
23700
+ parent: args.parentId,
23701
+ label: opts.label,
23702
+ ...opts.key !== void 0 ? { key: opts.key } : {},
23703
+ ...opts.assignmentId === void 0 ? {} : { assignmentId: opts.assignmentId },
23704
+ ...opts.successorOf === void 0 ? {} : { successorOf: opts.successorOf },
23705
+ budget: opts.budget,
23706
+ runtime: executor.runtime,
23707
+ ...ownedTreeRoot === void 0 ? {} : { ownedTreeRoot },
23708
+ ...identity ? { identity } : {},
23709
+ profileRef,
23710
+ seq: ordinal,
23711
+ at: new Date(now()).toISOString()
23712
+ }];
23713
+ if (taskRef !== void 0) events.push({
23261
23714
  kind: "execution-input",
23262
23715
  id,
23263
23716
  taskRef,
23264
23717
  seq: ordinal,
23265
23718
  at: new Date(now()).toISOString()
23266
23719
  });
23720
+ await appendSpawnEvents(args.journal, args.root, events);
23267
23721
  }).then(async () => {
23268
23722
  if (args.workerTraceUnpropagated === void 0 || workerTrace === void 0) return;
23269
23723
  await args.journal.appendEvent(args.root, {
@@ -23393,6 +23847,7 @@ function createScope(args) {
23393
23847
  childId: id,
23394
23848
  label: opts.label,
23395
23849
  ...opts.assignmentId === void 0 ? {} : { assignmentId: opts.assignmentId },
23850
+ ...opts.key === void 0 ? {} : { key: opts.key },
23396
23851
  ...opts.successorOf === void 0 ? {} : { successorOf: opts.successorOf },
23397
23852
  runtime: executor.runtime,
23398
23853
  ...identity ? { identity } : {},
@@ -23916,24 +24371,44 @@ function createScope(args) {
23916
24371
  const prior = released.length > 0 ? await args.journal.loadTree(args.root) ?? [] : [];
23917
24372
  for (const { child, receipts } of released) {
23918
24373
  for (const receipt of receipts) await appendEnvironmentTeardown(args.journal, args.root, child.id, receipt, new Date(now()).toISOString());
23919
- if (child.cleanupConfirmed && child.recoveryPending === true && child.resolved?.kind === "down" && child.settledSeq !== void 0 && child.settledAt !== void 0 && !prior.some((event) => event.id === child.id && closesCursorSlot(event))) {
23920
- child.budgetViolation = child.retainedViolation;
23921
- const settledAt = child.settledAt;
23922
- await args.journal.appendEvent(args.root, terminalDownEvent(child, child.resolved, child.settledSeq, new Date(settledAt).toISOString(), "released"));
23923
- child.retainedExecution = "released";
23924
- const releasedAt = now();
23925
- notifyRuntimeHookEvent(args.hooks, {
23926
- id: `${child.id}:released`,
23927
- runId: args.root,
23928
- target: "agent.child",
23929
- phase: "after",
23930
- timestamp: releasedAt,
23931
- stepIndex: child.settledSeq,
23932
- parentId: args.parentId,
23933
- payload: releasedChildPayload(child, child.resolved, settledAt, releasedAt)
23934
- }, { signal: args.signal });
23935
- }
24374
+ if (child.cleanupConfirmed) await closeRetainedSlot(child, "released", prior);
24375
+ }
24376
+ });
24377
+ const closeRetainedSlot = async (child, state, prior) => {
24378
+ if (child.recoveryPending !== true || child.resolved?.kind !== "down" || child.settledSeq === void 0 || child.settledAt === void 0 || child.retainedExecution === "released" || child.retainedExecution === "release-unconfirmed" || prior.some((event) => event.id === child.id && closesCursorSlot(event))) return;
24379
+ child.budgetViolation = child.retainedViolation;
24380
+ const settledAt = child.settledAt;
24381
+ let settlement = child.resolved;
24382
+ if (settlement.harnessTranscript?.status !== "available" && child.readTranscriptAtRelease) {
24383
+ const atRelease = await child.readTranscriptAtRelease();
24384
+ if (atRelease.status === "available") settlement = {
24385
+ ...settlement,
24386
+ harnessTranscript: atRelease
24387
+ };
24388
+ }
24389
+ await args.journal.appendEvent(args.root, terminalDownEvent(child, settlement, child.settledSeq, new Date(settledAt).toISOString(), state));
24390
+ child.retainedExecution = state;
24391
+ const closedAt = now();
24392
+ notifyRuntimeHookEvent(args.hooks, {
24393
+ id: `${child.id}:${state}`,
24394
+ runId: args.root,
24395
+ target: "agent.child",
24396
+ phase: "after",
24397
+ timestamp: closedAt,
24398
+ stepIndex: child.settledSeq,
24399
+ parentId: args.parentId,
24400
+ payload: releasedChildPayload(child, settlement, settledAt, closedAt, state)
24401
+ }, { signal: args.signal });
24402
+ };
24403
+ retainedSlotClosers.set(scope, async () => {
24404
+ for (const child of children.values()) {
24405
+ const nested = child.readNestedScope?.();
24406
+ if (nested !== void 0) await closeRetainedSlots(nested);
23936
24407
  }
24408
+ const open = [...children.values()].filter((child) => child.recoveryPending === true && !child.cleanupConfirmed && isTerminalNodeStatus(child.status) && child.retainedExecution !== "released" && child.retainedExecution !== "release-unconfirmed");
24409
+ if (open.length === 0) return;
24410
+ const prior = await args.journal.loadTree(args.root) ?? [];
24411
+ for (const child of open) await closeRetainedSlot(child, "release-unconfirmed", prior);
23937
24412
  });
23938
24413
  registerScopeRetainedOwner(scope, {
23939
24414
  rootId: args.root,
@@ -24033,7 +24508,7 @@ async function recordScopeOwnerMaterialization(scope, runtime, declaration, bind
24033
24508
  /** @internal Kernel identity for constructing the exact deferred owner executor. */
24034
24509
  /**
24035
24510
  * @internal Each driver attempt of the scope owner is its own execution attempt. A driver retry
24036
- * after a failed drive, and the `repromptOnUnmet` re-entry after an unmet completion check, both
24511
+ * after a failed drive, and the continuation re-entry after an unmet completion check, both
24037
24512
  * run the harness again and report a new execution binding; the journal keys owner bindings by
24038
24513
  * attempt id, so every attempt after the first is given a fresh kernel-minted id and its
24039
24514
  * published flags are cleared, and the new binding lands beside the earlier ones. The first
@@ -25039,35 +25514,6 @@ function downRecord(reason, infra, trace, metered, providerModel, outRef, harnes
25039
25514
  ...outRef === void 0 ? {} : { outRef }
25040
25515
  };
25041
25516
  }
25042
- /**
25043
- * Read one executor's harness-transcript receipt without letting a broken port escape.
25044
- *
25045
- * The three answers this has to keep apart, because #1214 and #1244 are both about an artifact
25046
- * that reads as coverage without being coverage:
25047
- * - `available` the transcript survived;
25048
- * - a reason the CAPTURE produced a box existed and could not be read;
25049
- * - `executor-exposes-no-transcript` this runtime has no transcript to offer at all;
25050
- * - `execution-never-started` no environment was ever created (the executor's
25051
- * own seed, set before `create`);
25052
- * - `capture-did-not-run` the port answered nothing, so the capture was
25053
- * skipped rather than attempted and failed.
25054
- *
25055
- * Mirrors `readInteractiveSession` above: an absence is always a named reason, never `undefined`.
25056
- */
25057
- function readHarnessTranscript(executor) {
25058
- if (!executor.harnessTranscript) return harnessTranscriptUnavailable("executor-exposes-no-transcript");
25059
- let reported;
25060
- try {
25061
- reported = executor.harnessTranscript();
25062
- } catch {
25063
- return harnessTranscriptUnavailable("executor-exposes-no-transcript");
25064
- }
25065
- if (reported === void 0) return harnessTranscriptUnavailable("capture-did-not-run");
25066
- const capture = reported;
25067
- if (capture.status === "captured" && capture.artifact) return capture;
25068
- if (capture.status === "unavailable" && capture.reason) return capture;
25069
- return harnessTranscriptUnavailable("executor-exposes-no-transcript");
25070
- }
25071
25517
  /** The one place an absent interactive process is spelled, so every refusal reads the same. */
25072
25518
  function noInteractiveSession(reason) {
25073
25519
  return Object.freeze({
@@ -25487,6 +25933,493 @@ function unreportedSpend(total, prior) {
25487
25933
  };
25488
25934
  }
25489
25935
  //#endregion
25936
+ //#region src/runtime/supervise/continuation.ts
25937
+ /**
25938
+ * The continuation: what a manager with a completion check is told when its turn ends and the
25939
+ * check is unmet, and the one rule that decides whether it is sent back.
25940
+ *
25941
+ * Measured on discovery-lab before this module (2026-09-24, 670 settled runs, 1,596 re-entries):
25942
+ * 1,565 re-entries followed a failed turn and resent the original task, and 31 carried note text.
25943
+ * The note Runtime wrote itself held seven fixed lines and no field for the check's verdict. Of 40
25944
+ * episodes where the director ended on its own and the outside check disagreed, 33 were told
25945
+ * nothing before they ended. 100 of 236 resubmits sent the identical packet. So the director
25946
+ * mostly graded itself, and when it was wrong it heard nothing it could use.
25947
+ *
25948
+ * The design (discovery `docs/38-one-loop-and-continuation.md`) makes three things single, and
25949
+ * this module holds the part Runtime owns:
25950
+ *
25951
+ * - ONE CHECK. A check reading is a {@link CheckVerdict}: pass, the items it read, the composite,
25952
+ * and one `FAIL <item> <where>: <reason>` line per failed item. The same check decides
25953
+ * `submit_result`, runs when a turn ends without an accepted result, scores the finished run,
25954
+ * and ranks versions. A check that could not run gives no verdict ({@link CheckUnavailableError}),
25955
+ * and the loop pauses instead of blaming the director.
25956
+ * - ONE RESEND RULE. {@link ContinuationPolicy} is required for a manager with a check. It holds a
25957
+ * deadline and `maxBarren`, the re-entered turns in a row that may end without progress. There
25958
+ * is no re-prompt count and no default: a retry default in source is a research decision.
25959
+ * - ONE NOTE. {@link composeContinuationNote} writes it. Runtime owns the facts and their order;
25960
+ * the {@link ContinuationProfile} owns every instruction word, so an optimizer can change the
25961
+ * words without touching code. A play may append a section, never remove or rewrite one.
25962
+ *
25963
+ * Evidence behind the note's shape: located errors help (given the first mistake's true location,
25964
+ * fix rates rose 23.5 to 43.9 points, Tyen 2023); unsupported pressure does not (threats and tips
25965
+ * had no significant effect, Wharton 2025; challenges without evidence flipped correct answers,
25966
+ * FlipFlop); repeated summaries drop detail while itemized additions do not (ACE). So the note is
25967
+ * a list of located facts, findings are added and marked resolved rather than rewritten, and the
25968
+ * profile, not this file, decides how blunt the words are.
25969
+ */
25970
+ /**
25971
+ * The check could not run: its box did not start, its judge's provider refused, its program
25972
+ * crashed. It is not a verdict on the result. Inside a run the loop pauses, as it does for an
25973
+ * unavailable upstream, and the refusal tells the director its result was not judged.
25974
+ */
25975
+ var CheckUnavailableError = class extends Error {
25976
+ constructor(message, options) {
25977
+ super(message, options);
25978
+ this.name = "CheckUnavailableError";
25979
+ }
25980
+ };
25981
+ /** Read a check function's return value into a verdict. Anything but `true` or a passing verdict
25982
+ * is a failure: a check fails closed. */
25983
+ function checkVerdictOf(outcome) {
25984
+ if (outcome === true) return { pass: true };
25985
+ if (typeof outcome !== "object" || outcome === null || Array.isArray(outcome)) return { pass: false };
25986
+ const raw = outcome;
25987
+ const items = typeof raw.items === "object" && raw.items !== null && !Array.isArray(raw.items) ? Object.fromEntries(Object.entries(raw.items).filter((entry) => typeof entry[1] === "number" && Number.isFinite(entry[1]))) : void 0;
25988
+ const failures = Array.isArray(raw.failures) ? raw.failures.filter((line) => typeof line === "string" && line.trim() !== "") : void 0;
25989
+ return Object.freeze({
25990
+ pass: raw.pass === true,
25991
+ ...items === void 0 ? {} : { items: Object.freeze(items) },
25992
+ ...finite(raw.composite) ? { composite: raw.composite } : {},
25993
+ ...finite(raw.threshold) ? { threshold: raw.threshold } : {},
25994
+ ...failures === void 0 ? {} : { failures: Object.freeze(failures) },
25995
+ ...typeof raw.review === "string" && raw.review.trim() !== "" ? { review: raw.review.trim() } : {}
25996
+ });
25997
+ }
25998
+ /**
25999
+ * Read an agent-eval `JudgeScore` from a check program into a verdict.
26000
+ *
26001
+ * Each dimension is a checked item. `notes` lines that start with `FAIL ` are the failures; the
26002
+ * remaining lines are the check's review. The verdict passes when `composite >= threshold` and the
26003
+ * score is not marked `failed`; a `failed` score means the judge itself did not run, which is
26004
+ * {@link CheckUnavailableError}, not a verdict.
26005
+ */
26006
+ function verdictFromJudgeScore(score, threshold) {
26007
+ if (score.failed === true) throw new CheckUnavailableError(`the check's judge did not run: ${score.notes}`);
26008
+ const lines = score.notes.split("\n").map((line) => line.trimEnd());
26009
+ const failures = lines.filter((line) => line.startsWith("FAIL "));
26010
+ const review = lines.filter((line) => !line.startsWith("FAIL ") && line.trim() !== "").join("\n");
26011
+ return checkVerdictOf({
26012
+ pass: score.composite >= threshold,
26013
+ items: score.dimensions,
26014
+ composite: score.composite,
26015
+ threshold,
26016
+ failures,
26017
+ ...review === "" ? {} : { review }
26018
+ });
26019
+ }
26020
+ /** Items that fail in `verdict`: every item below 1, or the named items of its FAIL lines. */
26021
+ function failedItems(verdict) {
26022
+ if (verdict.items !== void 0) return Object.entries(verdict.items).filter(([, value]) => value < 1).map(([name]) => name);
26023
+ return (verdict.failures ?? []).map((line) => line.slice(5).split(/[\s:]/u)[0] ?? "");
26024
+ }
26025
+ /** Items that pass in `verdict`. */
26026
+ function passedItems(verdict) {
26027
+ return Object.entries(verdict.items ?? {}).filter(([, value]) => value >= 1).map(([name]) => name);
26028
+ }
26029
+ /** Resolve and check a policy before any compute. Returns the deadline in epoch ms. */
26030
+ function admitContinuationPolicy(policy, context) {
26031
+ if (typeof policy !== "object" || policy === null) throw new ValidationError$1(`${context}: continuation must be an object`);
26032
+ const deadlineMs = typeof policy.deadline === "string" ? Date.parse(policy.deadline) : policy.deadline;
26033
+ if (typeof deadlineMs !== "number" || !Number.isFinite(deadlineMs) || deadlineMs <= 0) throw new ValidationError$1(`${context}: continuation.deadline must be a finite time (epoch ms or ISO 8601)`);
26034
+ if (!Number.isInteger(policy.maxBarren) || policy.maxBarren < 1) throw new ValidationError$1(`${context}: continuation.maxBarren must be an integer >= 1`);
26035
+ if (policy.failures !== "verbatim" && policy.failures !== "off") throw new ValidationError$1(`${context}: continuation.failures must be 'verbatim' or 'off'`);
26036
+ if (policy.panel !== "on" && policy.panel !== "off") throw new ValidationError$1(`${context}: continuation.panel must be 'on' or 'off'`);
26037
+ if (policy.bar !== "on" && policy.bar !== "off") throw new ValidationError$1(`${context}: continuation.bar must be 'on' or 'off'`);
26038
+ if (policy.panel === "on") {
26039
+ if (typeof policy.runPanel !== "function") throw new ValidationError$1(`${context}: continuation.panel 'on' needs runPanel`);
26040
+ const usd = policy.panelUsd;
26041
+ if (usd === void 0 || !finite(usd.perContinuation) || !finite(usd.perRun) || usd.perContinuation <= 0 || usd.perRun < usd.perContinuation) throw new ValidationError$1(`${context}: continuation.panel 'on' needs panelUsd with 0 < perContinuation <= perRun`);
26042
+ }
26043
+ if (policy.append !== void 0 && typeof policy.append !== "function") throw new ValidationError$1(`${context}: continuation.append must be a function`);
26044
+ admitContinuationProfile(policy.profile, context);
26045
+ return deadlineMs;
26046
+ }
26047
+ /** The facts a profile template may name. */
26048
+ const CONTINUATION_FACTS = [
26049
+ "composite",
26050
+ "threshold",
26051
+ "failed",
26052
+ "total",
26053
+ "reads",
26054
+ "owed",
26055
+ "settled",
26056
+ "delivered",
26057
+ "continuation"
26058
+ ];
26059
+ const factNames = new Set(CONTINUATION_FACTS);
26060
+ const placeholder = /\{([a-zA-Z]+)\}/gu;
26061
+ function admitContinuationProfile(profile, context) {
26062
+ if (typeof profile !== "object" || profile === null) throw new ValidationError$1(`${context}: continuation.profile must be an object`);
26063
+ if (typeof profile.id !== "string" || profile.id.trim() === "") throw new ValidationError$1(`${context}: continuation.profile.id must be non-empty`);
26064
+ const texts = [
26065
+ ["opening", profile.opening],
26066
+ ["plan", profile.plan],
26067
+ ["rules", profile.rules],
26068
+ ...Object.entries(profile.headings ?? {}).map(([key, value]) => [`headings.${key}`, value]),
26069
+ ...profile.barRule === void 0 ? [] : [["barRule", profile.barRule]]
26070
+ ];
26071
+ for (const key of [
26072
+ "failures",
26073
+ "protected",
26074
+ "changed",
26075
+ "findings",
26076
+ "bar",
26077
+ "plan",
26078
+ "rules"
26079
+ ]) if (typeof profile.headings?.[key] !== "string") throw new ValidationError$1(`${context}: continuation.profile.headings.${key} must be a string`);
26080
+ for (const [key, text] of texts) {
26081
+ if (typeof text !== "string") throw new ValidationError$1(`${context}: continuation.profile.${key} must be a string`);
26082
+ for (const match of text.matchAll(placeholder)) if (!factNames.has(match[1] ?? "")) throw new ValidationError$1(`${context}: continuation.profile.${key} names {${match[1]}}, which is not a fact Runtime supplies (${CONTINUATION_FACTS.join(", ")})`);
26083
+ }
26084
+ if (profile.review !== void 0) {
26085
+ if (typeof profile.review !== "string" || profile.review.trim() === "") throw new ValidationError$1(`${context}: continuation.profile.review must be non-empty`);
26086
+ for (const match of profile.review.matchAll(placeholder)) if (![
26087
+ "version",
26088
+ "path",
26089
+ "score"
26090
+ ].includes(match[1] ?? "")) throw new ValidationError$1(`${context}: continuation.profile.review names {${match[1]}}; it may name {version}, {path} and {score}`);
26091
+ }
26092
+ if (profile.opening.trim() === "") throw new ValidationError$1(`${context}: continuation.profile.opening must be non-empty`);
26093
+ for (const [index, question] of (profile.questions ?? []).entries()) if (typeof question !== "string" || question.trim() === "") throw new ValidationError$1(`${context}: continuation.profile.questions[${index}] must be a non-empty string`);
26094
+ }
26095
+ /** Findings reach the note only when every citation resolves, at least two distinct spans are
26096
+ * cited, and the independent verifier agreed. The best method in Who&When found the failing step
26097
+ * 14.2% of the time, so an unverified finding is noise with a citation. */
26098
+ function admitFinding(finding) {
26099
+ if (!finding.verified) return false;
26100
+ if (finding.citations.length === 0) return false;
26101
+ if (!finding.citations.every((citation) => citation.resolved)) return false;
26102
+ return new Set(finding.citations.map((citation) => citation.uri)).size >= 2;
26103
+ }
26104
+ /** About 1,500 tokens of findings. */
26105
+ const FINDINGS_CHAR_CAP = 6e3;
26106
+ /**
26107
+ * Rank the admitted findings by how many failed items they explain, drop repeats, and keep them
26108
+ * within the note's cap. Earlier findings stay as they were written (ACE: itemized additions keep
26109
+ * detail that repeated rewrites lose); a finding whose items all pass now is marked resolved.
26110
+ */
26111
+ function distillFindings(prior, proposed, failing, continuation) {
26112
+ const key = (claim) => claim.toLowerCase().replace(/\s+/gu, " ").trim();
26113
+ const known = new Set(prior.map((finding) => key(finding.claim)));
26114
+ const carried = prior.map((finding) => finding.resolvedAt === void 0 && (finding.items?.length ?? 0) > 0 && (finding.items ?? []).every((item) => !failing.has(item)) ? {
26115
+ ...finding,
26116
+ resolvedAt: continuation
26117
+ } : finding);
26118
+ const fresh = proposed.filter(admitFinding).filter((finding) => {
26119
+ const k = key(finding.claim);
26120
+ if (known.has(k)) return false;
26121
+ known.add(k);
26122
+ return true;
26123
+ }).map((finding) => ({
26124
+ finding,
26125
+ links: (finding.items ?? []).filter((item) => failing.has(item)).length
26126
+ })).sort((a, b) => b.links - a.links);
26127
+ const out = [...carried];
26128
+ let used = carried.filter((finding) => finding.resolvedAt === void 0).reduce((sum, finding) => sum + finding.claim.length, 0);
26129
+ for (const { finding } of fresh) {
26130
+ if (used + finding.claim.length > FINDINGS_CHAR_CAP) break;
26131
+ used += finding.claim.length;
26132
+ out.push({
26133
+ ...finding,
26134
+ admittedAt: continuation
26135
+ });
26136
+ }
26137
+ return out;
26138
+ }
26139
+ /** Expand the profile's question templates over the failed items and the settled workers. */
26140
+ function expandQuestions(templates, failing, workers) {
26141
+ const out = [];
26142
+ for (const template of templates) {
26143
+ const hasItem = template.includes("{item}");
26144
+ const hasWorker = template.includes("{worker}");
26145
+ if (!hasItem && !hasWorker) {
26146
+ out.push(template);
26147
+ continue;
26148
+ }
26149
+ const items = hasItem ? failing : [""];
26150
+ const each = hasWorker ? workers.map((worker) => `${worker.id} (${worker.label})`) : [""];
26151
+ for (const item of items) for (const worker of each) out.push(template.replaceAll("{item}", item).replaceAll("{worker}", worker));
26152
+ }
26153
+ return out;
26154
+ }
26155
+ /**
26156
+ * Write one continuation note, sections 1 to 8 of docs/38. Section 9, the run's state, is
26157
+ * `composeReentryTask`, which wraps this text. Pure: the same input writes the same note.
26158
+ */
26159
+ function composeContinuationNote(input) {
26160
+ const { profile, verdict } = input;
26161
+ const items = verdict?.items ?? {};
26162
+ const total = Object.keys(items).length;
26163
+ const failing = verdict === void 0 ? [] : failedItems(verdict);
26164
+ const facts = {
26165
+ composite: verdict?.composite === void 0 ? "unknown" : format(verdict.composite),
26166
+ threshold: verdict?.threshold === void 0 ? "unknown" : format(verdict.threshold),
26167
+ failed: verdict === void 0 || total === 0 && (verdict.failures?.length ?? 0) === 0 ? "unknown" : String(failing.length),
26168
+ total: total === 0 ? "unknown" : String(total),
26169
+ reads: String(input.reads),
26170
+ owed: input.owed?.trim() || "not described",
26171
+ settled: String(input.progress.settledCount),
26172
+ delivered: String(input.progress.deliveredCount ?? 0),
26173
+ continuation: String(input.continuation)
26174
+ };
26175
+ const fill = (text) => text.replace(placeholder, (_, name) => facts[name] ?? `{${name}}`);
26176
+ const sections = [verdict === void 0 ? "No result has reached the check yet. The run ends only when a result passes it through submit_result." : verdict.pass ? "The check passes on the current state, but no result was submitted. Call submit_result to end the run." : fill(profile.opening).trim()];
26177
+ const section = (heading, body) => {
26178
+ if (body.length === 0) return;
26179
+ sections.push([...heading.trim() === "" ? [] : [`## ${fill(heading)}`], ...body].join("\n"));
26180
+ };
26181
+ if (input.failures === "verbatim" && verdict !== void 0) {
26182
+ const lines = verdict.failures ?? [];
26183
+ const shown = lines.slice(0, 40);
26184
+ const more = lines.length - shown.length;
26185
+ section(profile.headings.failures, [...shown, ...more > 0 ? [input.canReadMore ? `${more} more failure lines: call read_continuation with continuation ${input.continuation}.` : `${more} more failure lines are not shown.`] : []]);
26186
+ const passing = passedItems(verdict);
26187
+ section(profile.headings.protected, passing.length === 0 ? [] : [passing.join(", ")]);
26188
+ if (input.previous !== void 0) {
26189
+ const before = new Set(failedItems(input.previous));
26190
+ const now = new Set(failing);
26191
+ const fixed = [...before].filter((item) => !now.has(item));
26192
+ const broke = [...now].filter((item) => !before.has(item));
26193
+ section(profile.headings.changed, [
26194
+ ...fixed.length === 0 ? [] : [`Now passing: ${fixed.join(", ")}.`],
26195
+ ...broke.length === 0 ? [] : [`Newly failing: ${broke.join(", ")}.`],
26196
+ ...fixed.length === 0 && broke.length === 0 ? ["No item changed since the last note."] : [],
26197
+ ...input.previous.composite !== void 0 && verdict.composite !== void 0 ? [`Composite: ${format(input.previous.composite)} then ${format(verdict.composite)}.`] : []
26198
+ ]);
26199
+ }
26200
+ }
26201
+ if (input.findings !== void 0) {
26202
+ const open = input.findings.filter((finding) => finding.resolvedAt === void 0);
26203
+ const resolved = input.findings.filter((finding) => finding.resolvedAt === input.continuation);
26204
+ section(profile.headings.findings, [...open.map((finding) => `- [hypothesis] ${finding.claim}` + (finding.items?.length ? ` (items: ${finding.items.join(", ")})` : "") + ` Evidence: ${finding.citations.map((citation) => citation.uri).join(", ")}`), ...resolved.map((finding) => `- [resolved] ${finding.claim}`)]);
26205
+ }
26206
+ if (input.bar !== void 0 && verdict !== void 0) {
26207
+ const body = [];
26208
+ if (profile.barRule?.trim()) body.push(fill(profile.barRule).trim());
26209
+ for (const [item, value] of Object.entries(items)) {
26210
+ const best = input.bar.best?.verdict.items?.[item];
26211
+ body.push(`- ${item}: ${value >= 1 ? "passes" : `fails (${format(value)})`}` + (best === void 0 ? "" : ` / ${input.bar.best?.label}: ${best >= 1 ? "passes" : `fails (${format(best)})`}`));
26212
+ }
26213
+ if (input.bar.best?.verdict.composite !== void 0) body.push(`Best version ${input.bar.best.label}: composite ${format(input.bar.best.verdict.composite)}.`);
26214
+ if (input.bar.reference?.trim()) body.push(`Reference result: ${input.bar.reference.trim()}`);
26215
+ if (verdict.review?.trim()) body.push(`The check's review: ${verdict.review.trim()}`);
26216
+ section(profile.headings.bar, body);
26217
+ }
26218
+ section(profile.headings.plan, profile.plan.trim() === "" ? [] : [fill(profile.plan).trim()]);
26219
+ section(profile.headings.rules, [...profile.rules.trim() === "" ? [] : [fill(profile.rules).trim()], ...input.sealed ? ["The score comes from cases you cannot see."] : []]);
26220
+ for (const appended of input.appended ?? []) section(appended.heading, appended.text.trim() === "" ? [] : [appended.text.trim()]);
26221
+ return sections.join("\n\n");
26222
+ }
26223
+ function summarizeVerdict(verdict) {
26224
+ if (verdict === void 0) return null;
26225
+ const total = Object.keys(verdict.items ?? {}).length;
26226
+ return {
26227
+ pass: verdict.pass,
26228
+ ...verdict.composite === void 0 ? {} : { composite: verdict.composite },
26229
+ ...total === 0 ? {} : {
26230
+ failed: failedItems(verdict).length,
26231
+ total
26232
+ }
26233
+ };
26234
+ }
26235
+ function noteDigest(note) {
26236
+ return `sha256:${createHash("sha256").update(note).digest("hex")}`;
26237
+ }
26238
+ /** A run directory's continuation files: the root's at `<runDir>/continuations/<n>/`, a nested
26239
+ * manager's at `<runDir>/continuations/managers/<owner>/<n>/`. */
26240
+ const CONTINUATIONS_DIR = "continuations";
26241
+ /**
26242
+ * Write one continuation's files under `<dir>/<n>/`: `note.md`, `verdict.json`, and
26243
+ * `panel.jsonl` when the panel ran. The director reads them through `read_continuation`, because
26244
+ * its box cannot read the driver's run directory.
26245
+ */
26246
+ async function writeContinuationFiles(dir, continuation, files) {
26247
+ const at = join(dir, String(continuation));
26248
+ await mkdir(at, { recursive: true });
26249
+ await writeFile(join(at, "note.md"), `${files.note}\n`, "utf8");
26250
+ await writeFile(join(at, "verdict.json"), `${JSON.stringify(files.verdict ?? null, null, 2)}\n`, "utf8");
26251
+ if (files.panel !== void 0) await writeFile(join(at, "panel.jsonl"), files.panel.map((line) => JSON.stringify(line)).join("\n") + (files.panel.length ? "\n" : ""), "utf8");
26252
+ }
26253
+ /** The best composite across `reads`, or `undefined` when no read scored. */
26254
+ function bestComposite(reads) {
26255
+ let best;
26256
+ for (const read of reads) {
26257
+ const value = read.verdict?.composite;
26258
+ if (value !== void 0 && (best === void 0 || value > best)) best = value;
26259
+ }
26260
+ return best;
26261
+ }
26262
+ function finite(value) {
26263
+ return typeof value === "number" && Number.isFinite(value);
26264
+ }
26265
+ function format(value) {
26266
+ return Number.isInteger(value) ? String(value) : value.toFixed(3).replace(/0+$/u, "");
26267
+ }
26268
+ /** Build the continuation state for one manager with a check. */
26269
+ function createContinuationKeeper(input) {
26270
+ const { policy } = input;
26271
+ const failures = input.feedback === "pass-only" ? "off" : policy.failures;
26272
+ const entries = [];
26273
+ const notes = [];
26274
+ let findings = [];
26275
+ let panelUsd = 0;
26276
+ let panelUsdKnown = true;
26277
+ const latestVerdict = () => {
26278
+ const reads = input.reads();
26279
+ for (let i = reads.length - 1; i >= 0; i -= 1) {
26280
+ const read = reads[i];
26281
+ if (read?.verdict !== void 0) return {
26282
+ verdict: read.verdict,
26283
+ read: read.read
26284
+ };
26285
+ }
26286
+ return { read: 0 };
26287
+ };
26288
+ const closePrevious = () => {
26289
+ const last = entries.at(-1);
26290
+ const lastNote = notes.at(-1);
26291
+ if (last === void 0 || lastNote === void 0) return;
26292
+ const latest = latestVerdict();
26293
+ entries[entries.length - 1] = {
26294
+ ...last,
26295
+ after: latest.read > lastNote.read ? summarizeVerdict(latest.verdict) : null
26296
+ };
26297
+ };
26298
+ return {
26299
+ async compose(context) {
26300
+ closePrevious();
26301
+ const continuation = entries.length + 1;
26302
+ const { verdict, read } = latestVerdict();
26303
+ const failing = verdict === void 0 ? [] : failedItems(verdict);
26304
+ let panelRecord;
26305
+ let panelLines;
26306
+ if (policy.panel === "on" && policy.runPanel !== void 0 && policy.panelUsd !== void 0) {
26307
+ const workers = input.workers();
26308
+ const questions = expandQuestions(policy.profile.questions ?? [], failing, workers);
26309
+ const left = policy.panelUsd.perRun - panelUsd;
26310
+ const usdCap = Math.min(policy.panelUsd.perContinuation, left);
26311
+ if (questions.length > 0 && usdCap > 0 && panelUsdKnown) {
26312
+ const result = await policy.runPanel({
26313
+ continuation,
26314
+ task: input.task,
26315
+ ...verdict === void 0 ? {} : { verdict },
26316
+ reads: input.reads(),
26317
+ questions,
26318
+ ...input.rootStreamPath === void 0 ? {} : { rootStreamPath: input.rootStreamPath },
26319
+ workers,
26320
+ ...policy.best === void 0 ? {} : { bar: policy.best },
26321
+ ...policy.reference === void 0 ? {} : { reference: policy.reference },
26322
+ usdCap,
26323
+ signal: context.signal
26324
+ });
26325
+ if (result.usd === null) panelUsdKnown = false;
26326
+ else panelUsd += result.usd;
26327
+ findings = distillFindings(findings, result.findings, new Set(failing), continuation);
26328
+ panelRecord = {
26329
+ asked: questions.length,
26330
+ proposed: result.findings.length,
26331
+ admitted: findings.filter((finding) => finding.admittedAt === continuation).length,
26332
+ usd: result.usd
26333
+ };
26334
+ panelLines = [...result.findings.map((finding) => ({
26335
+ kind: "finding",
26336
+ admitted: admitFinding(finding),
26337
+ ...finding
26338
+ })), ...result.receipts === void 0 ? [] : [{
26339
+ kind: "receipts",
26340
+ receipts: result.receipts
26341
+ }]];
26342
+ } else panelRecord = {
26343
+ asked: 0,
26344
+ proposed: 0,
26345
+ admitted: 0,
26346
+ usd: 0
26347
+ };
26348
+ }
26349
+ const appended = policy.append ? await policy.append({
26350
+ continuation,
26351
+ ...verdict === void 0 ? {} : { verdict },
26352
+ reads: input.reads(),
26353
+ signal: context.signal
26354
+ }) : void 0;
26355
+ const note = composeContinuationNote({
26356
+ profile: policy.profile,
26357
+ continuation,
26358
+ ...verdict === void 0 ? {} : { verdict },
26359
+ ...notes.at(-1)?.verdict === void 0 ? {} : { previous: notes.at(-1)?.verdict },
26360
+ reads: input.reads().length,
26361
+ failures,
26362
+ ...policy.panel === "on" ? { findings } : {},
26363
+ ...policy.bar === "on" ? { bar: {
26364
+ ...policy.best === void 0 ? {} : { best: policy.best },
26365
+ ...policy.reference === void 0 ? {} : { reference: policy.reference }
26366
+ } } : {},
26367
+ ...appended === void 0 ? {} : { appended: [appended] },
26368
+ ...input.owed === void 0 ? {} : { owed: input.owed },
26369
+ progress: context.progress,
26370
+ canReadMore: input.canReadMore,
26371
+ ...input.sealed === true ? { sealed: true } : {}
26372
+ });
26373
+ notes.push({
26374
+ note,
26375
+ ...verdict === void 0 ? {} : { verdict },
26376
+ ...panelLines === void 0 ? {} : { panel: panelLines },
26377
+ read
26378
+ });
26379
+ entries.push({
26380
+ continuation,
26381
+ attempt: context.attempt,
26382
+ noteDigest: noteDigest(note),
26383
+ profile: policy.profile.id,
26384
+ switches: {
26385
+ failures,
26386
+ panel: policy.panel,
26387
+ bar: policy.bar
26388
+ },
26389
+ before: summarizeVerdict(verdict),
26390
+ after: null,
26391
+ ...panelRecord === void 0 ? {} : { panel: panelRecord },
26392
+ appended: appended === void 0 ? 0 : 1
26393
+ });
26394
+ if (input.dir !== void 0) await writeContinuationFiles(input.dir, continuation, {
26395
+ note,
26396
+ ...verdict === void 0 ? {} : { verdict },
26397
+ ...panelLines === void 0 ? {} : { panel: panelLines }
26398
+ });
26399
+ return note;
26400
+ },
26401
+ read(continuation) {
26402
+ const index = continuation === void 0 ? notes.length - 1 : continuation - 1;
26403
+ const entry = notes[index];
26404
+ if (entry === void 0) return {
26405
+ found: false,
26406
+ reason: notes.length === 0 ? "no continuation has been sent in this run" : `continuations run from 1 to ${notes.length}`
26407
+ };
26408
+ return {
26409
+ found: true,
26410
+ continuation: index + 1,
26411
+ note: entry.note,
26412
+ verdict: failures === "off" && entry.verdict !== void 0 ? { pass: entry.verdict.pass } : entry.verdict ?? null,
26413
+ findings: findings.filter((finding) => finding.admittedAt <= index + 1)
26414
+ };
26415
+ },
26416
+ entries() {
26417
+ closePrevious();
26418
+ return entries.map((entry) => ({ ...entry }));
26419
+ }
26420
+ };
26421
+ }
26422
+ //#endregion
25490
26423
  //#region src/runtime/supervise/driver-retry.ts
25491
26424
  /**
25492
26425
  * Root-driver retry — the root gets the same second chance a worker's transport already has.
@@ -25534,22 +26467,21 @@ function unreportedSpend(total, prior) {
25534
26467
  * driver that RETURNED with the contract unmet ended the run silently — 376 of 376 winning lab runs
25535
26468
  * ended on this loop's own `stop: 'completed'`, with the completion gate left to label the result
25536
26469
  * rather than to change it. A completed drive whose contract is unmet is now a first-class moment:
25537
- * `reprompt.maxReprompts` re-enters the driver with the unmet items, and every re-entry crosses the
25538
- * same budget, deadline, and abort bounds. Successful continuations do not consume the failure
25539
- * retry allowance.
26470
+ * the manager's `continuation` policy (`./continuation.ts`) re-enters the driver with Runtime's
26471
+ * continuation note, and every re-entry crosses the same budget, deadline, and abort bounds.
26472
+ * Successful continuations do not consume the failure retry allowance.
25540
26473
  *
25541
26474
  * This loop decides WHETHER to re-enter; it does not know WHERE the next drive runs. Whether the
25542
26475
  * re-entered driver continues the same harness session, the same environment, or a replacement is
25543
26476
  * the drive harness's fact, and the caller composes the re-entry task from it (see
25544
- * `./reentry.ts`). A re-prompt re-enters the same session only on a backend that proves it.
26477
+ * `./reentry.ts`). A continuation re-enters the same session only on a backend that proves it.
25545
26478
  *
25546
- * Progress bounds the re-prompts too. The same delivery reading that resets the barren failure
25547
- * counter decides whether a re-prompted drive earned another: `reprompt.maxBarren` consecutive
25548
- * re-entered drives that completed without a delivery end the loop with `repromptRefusedBy:
25549
- * 'no-progress'`. Before this, a completed drive reset the barren counter and `decideReprompt`
25550
- * read only the count cap, budget, and deadline, so a director with `repromptOnUnmet: 100` or
25551
- * `'until-complete'` that delivered nothing was re-prompted until the budget or deadline ended it;
25552
- * the old prompt-owned loop logged 896 of 1,011 rounds with no progress.
26479
+ * Progress bounds the continuations, and nothing else counts them. The same delivery reading that
26480
+ * resets the barren failure counter decides whether a continued drive earned another:
26481
+ * `continuation.maxBarren` consecutive re-entered drives that completed without progress end the
26482
+ * loop with `repromptRefusedBy: 'no-progress'`. Progress is a delivery or a rise in the check's
26483
+ * best composite. There is no count cap and no caller veto: the old prompt-owned loop logged 896
26484
+ * of 1,011 rounds with no progress, and 650 recorded inputs chose seven different re-prompt counts.
25553
26485
  *
25554
26486
  * A THIRD CLASS sits between the two: the upstream said "not now". A model provider's exhausted
25555
26487
  * quota, a rate limit, or an overloaded service (HTTP 429, 503, 529, or the router's own codes for
@@ -25561,28 +26493,8 @@ function unreportedSpend(total, prior) {
25561
26493
  * the router answered some turns in between (one lead spent 1.7M and 3.3M input tokens on two of
25562
26494
  * them) and each run's budget and 8-hour deadline were almost untouched.
25563
26495
  */
25564
- /**
25565
- * The instruction a completed-but-undelivered drive is re-entered with when the caller supplies no
25566
- * `onUnmetContract`. It states the verdict, names what is owed, reports the ledger, and gives the
25567
- * three steps — the same shape `depthStrategy` re-prompts a resumed session with, said in the
25568
- * driver's own terms.
25569
- */
25570
- function defaultUnmetContractSteer(context) {
25571
- const owed = context.describe?.trim();
25572
- return [
25573
- "The completion check has not passed. This run has delivered nothing yet.",
25574
- owed === void 0 || owed.length === 0 ? "The deliverable this run owes is still missing." : `The deliverable this run owes: ${owed}`,
25575
- `Workers settled: ${context.progress.settledCount}. Workers that passed the check: ${context.progress.deliveredCount ?? 0}.`,
25576
- "Do the unfinished work with the tools.",
25577
- "Verify that the check passes.",
25578
- "Then submit the result.",
25579
- "Do not restate work you already did."
25580
- ].join("\n");
25581
- }
25582
26496
  const DEFAULT_MAX_CONSECUTIVE_FAILURES = 3;
25583
26497
  const DEFAULT_MAX_ATTEMPTS = 8;
25584
- /** Two re-prompted drives in a row that deliver nothing end the re-prompts. */
25585
- const DEFAULT_MAX_BARREN_REPROMPTS = 2;
25586
26498
  const DEFAULT_INITIAL_BACKOFF_MS = 2e3;
25587
26499
  const DEFAULT_MAX_BACKOFF_MS = 3e4;
25588
26500
  /**
@@ -25628,6 +26540,7 @@ var HarnessTurnFailedError = class extends Error {
25628
26540
  */
25629
26541
  function upstreamUnavailableSignal(error) {
25630
26542
  if (!(error instanceof Error)) return void 0;
26543
+ if (error instanceof CheckUnavailableError) return "check-unavailable";
25631
26544
  if (error instanceof HarnessTurnFailedError) return unavailableSignalOfFailure({
25632
26545
  error: error.message,
25633
26546
  ...error.errorCode === void 0 ? {} : { errorCode: error.errorCode }
@@ -25711,13 +26624,15 @@ function contractOf(mark) {
25711
26624
  /**
25712
26625
  * Did this attempt move the run toward its DELIVERABLE?
25713
26626
  *
25714
- * A delivery always counts: an accepted submission, one more child that passed the check, or the
25715
- * contract turning met. Spend and settlements count only while no declared check is outstanding —
25716
- * with a check unmet they are the burn-rate reading this module's header measures and rejects.
26627
+ * A delivery always counts: an accepted submission, one more child that passed the check, the
26628
+ * contract turning met, or a rise in the check's best composite. Spend and settlements count only
26629
+ * while no declared check is outstanding — with a check unmet they are the burn-rate reading this
26630
+ * module's header measures and rejects.
25717
26631
  */
25718
26632
  function madeProgress(before, after) {
25719
26633
  if (after.submitted && !before.submitted) return true;
25720
26634
  if ((after.deliveredCount ?? 0) > (before.deliveredCount ?? 0)) return true;
26635
+ if (after.composite !== void 0 && after.composite > (before.composite ?? -Infinity)) return true;
25721
26636
  if (contractOf(before) !== "met" && contractOf(after) === "met") return true;
25722
26637
  if (contractOf(after) === "unmet") return false;
25723
26638
  return after.poolTokensSpent > before.poolTokensSpent || after.settledCount > before.settledCount;
@@ -25763,10 +26678,11 @@ async function defaultSleep(ms, signal) {
25763
26678
  /**
25764
26679
  * Run the driver until it completes WITH ITS CONTRACT MET, or until the budget, the deadline, an
25765
26680
  * abort, a terminal error, or a ceiling stops it. Transient failures are retried. A drive that
25766
- * returns with its completion check unmet is re-entered on the same live session with the unmet
25767
- * items, up to `reprompt.maxReprompts`. Throws `DriverAttemptsExhaustedError` (cause = the last
25768
- * real failure) when a FAILURE ends the loop; a completed drive returns, met contract or not,
25769
- * because deciding what an undelivered run is worth belongs to the finalizer, not to this loop.
26681
+ * returns with its completion check unmet is re-entered with Runtime's continuation note until the
26682
+ * continuation's deadline or `maxBarren` turns without progress. Throws
26683
+ * `DriverAttemptsExhaustedError` (cause = the last real failure) when a FAILURE ends the loop; a
26684
+ * completed drive returns, met contract or not, because deciding what an undelivered run is worth
26685
+ * belongs to the finalizer, not to this loop.
25770
26686
  */
25771
26687
  async function runDriverWithRetry(run) {
25772
26688
  const now = run.now ?? Date.now;
@@ -25777,19 +26693,18 @@ async function runDriverWithRetry(run) {
25777
26693
  const maxAttempts = Math.max(1, policy.maxAttempts ?? DEFAULT_MAX_ATTEMPTS);
25778
26694
  const initialBackoff = Math.max(0, policy.initialBackoffMs ?? DEFAULT_INITIAL_BACKOFF_MS);
25779
26695
  const maxBackoff = Math.max(initialBackoff, policy.maxBackoffMs ?? DEFAULT_MAX_BACKOFF_MS);
25780
- const maxReprompts = run.reprompt?.maxReprompts ?? 0;
25781
- if (maxReprompts === "until-complete") {
25782
- const deadline = run.budget().deadlineMs;
25783
- if (!Number.isFinite(deadline) || deadline <= 0) throw new ValidationError$1("runDriverWithRetry: until-complete requires a finite positive deadline");
26696
+ const continuation = run.continuation;
26697
+ if (continuation !== void 0) {
26698
+ if (!Number.isFinite(continuation.deadlineMs) || continuation.deadlineMs <= 0) throw new ValidationError$1("runDriverWithRetry: a continuation needs a finite positive deadline");
26699
+ if (!Number.isInteger(continuation.maxBarren) || continuation.maxBarren < 1) throw new ValidationError$1("runDriverWithRetry: continuation.maxBarren must be an integer >= 1");
25784
26700
  }
25785
- const maxBarren = Math.max(1, run.reprompt?.maxBarren ?? 2);
25786
26701
  const attempts = [];
25787
26702
  let consecutiveBarren = 0;
25788
26703
  let barrenReentries = 0;
25789
26704
  let failures = 0;
25790
26705
  let consecutivePauses = 0;
25791
26706
  let pauses = 0;
25792
- let reprompts = 0;
26707
+ let continuations = 0;
25793
26708
  let reentry;
25794
26709
  const emit = async (record) => {
25795
26710
  const entered = reentry === void 0 ? {} : { reentry: reentry.reason };
@@ -25801,32 +26716,33 @@ async function runDriverWithRetry(run) {
25801
26716
  await run.onAttempt?.(stamped);
25802
26717
  };
25803
26718
  /**
25804
- * Decide what a completed-but-undelivered drive does next. Every bound the FAILURE path applies
25805
- * is applied here too — that is the fix for `budgetStop` having lived only in the catch arm — and
25806
- * the caller's hook is consulted last, so no hook can talk the loop past a deadline.
26719
+ * Decide what a completed drive with its check unmet does next. Every bound the FAILURE path
26720
+ * applies is applied here too — that is the fix for `budgetStop` having lived only in the catch
26721
+ * arm — and they are read again after the note is composed, because composing may run the
26722
+ * question panel.
25807
26723
  */
25808
- const decideReprompt = async (attempt, after) => {
25809
- if (maxReprompts !== "until-complete" && reprompts >= maxReprompts) return { refusedBy: "reprompts-exhausted" };
25810
- if (barrenReentries >= maxBarren) return { refusedBy: "no-progress" };
25811
- if (run.signal.aborted) return { refusedBy: "aborted" };
25812
- const byBudget = budgetStop(run.budget(), now());
25813
- if (byBudget === "deadline" || byBudget === "budget-exhausted") return { refusedBy: byBudget };
25814
- const context = {
26724
+ const decideContinuation = async (policy, attempt, after) => {
26725
+ const bounds = () => {
26726
+ if (policy.closed()) return "closed";
26727
+ if (run.signal.aborted) return "aborted";
26728
+ if (now() >= policy.deadlineMs) return "deadline";
26729
+ const byBudget = budgetStop(run.budget(), now());
26730
+ return byBudget === "deadline" || byBudget === "budget-exhausted" ? byBudget : void 0;
26731
+ };
26732
+ if (barrenReentries >= policy.maxBarren) return { refusedBy: "no-progress" };
26733
+ const before = bounds();
26734
+ if (before !== void 0) return { refusedBy: before };
26735
+ const steer = (await policy.compose({
25815
26736
  attempt,
25816
- reprompts,
25817
- maxReprompts,
26737
+ continuations,
25818
26738
  progress: after,
25819
26739
  budget: run.budget(),
25820
- ...run.reprompt?.describe === void 0 ? {} : { describe: run.reprompt.describe },
25821
- barrenReentries
25822
- };
25823
- const decision = await run.reprompt?.onUnmetContract?.(context) ?? { steer: defaultUnmetContractSteer(context) };
25824
- if (decision === "stop") return { refusedBy: "caller-stop" };
25825
- if (run.signal.aborted) return { refusedBy: "aborted" };
25826
- const afterHook = budgetStop(run.budget(), now());
25827
- if (afterHook === "deadline" || afterHook === "budget-exhausted") return { refusedBy: afterHook };
25828
- const steer = typeof decision.steer === "string" ? decision.steer.trim() : "";
25829
- if (steer.length === 0) throw new ValidationError$1("runDriverWithRetry: onUnmetContract returned an empty steer — return a non-empty instruction or 'stop'");
26740
+ barrenReentries,
26741
+ signal: run.signal
26742
+ })).trim();
26743
+ const afterCompose = bounds();
26744
+ if (afterCompose !== void 0) return { refusedBy: afterCompose };
26745
+ if (steer.length === 0) throw new ValidationError$1("runDriverWithRetry: the continuation note is empty");
25830
26746
  return { steer };
25831
26747
  };
25832
26748
  for (let attempt = 1;; attempt += 1) {
@@ -25940,10 +26856,10 @@ async function runDriverWithRetry(run) {
25940
26856
  const contractField = contract === "none" ? {} : { contract };
25941
26857
  if (progressed) barrenReentries = 0;
25942
26858
  else if (reentry !== void 0 && contract === "unmet") barrenReentries += 1;
25943
- if (contract === "unmet" && (maxReprompts === "until-complete" || maxReprompts > 0)) {
25944
- const decision = await decideReprompt(attempt, after);
26859
+ if (contract === "unmet" && continuation !== void 0) {
26860
+ const decision = await decideContinuation(continuation, attempt, after);
25945
26861
  if ("steer" in decision) {
25946
- reprompts += 1;
26862
+ continuations += 1;
25947
26863
  await emit({
25948
26864
  attempt,
25949
26865
  durationMs,
@@ -25955,7 +26871,7 @@ async function runDriverWithRetry(run) {
25955
26871
  reentry = {
25956
26872
  reason: "unmet-contract",
25957
26873
  steer: decision.steer,
25958
- reprompt: reprompts
26874
+ continuation: continuations
25959
26875
  };
25960
26876
  continue;
25961
26877
  }
@@ -26083,8 +26999,9 @@ async function runFinalizer(finalizer, args) {
26083
26999
  if (candidate === void 0) return false;
26084
27000
  if (args.deliverable === void 0) return true;
26085
27001
  try {
26086
- return await args.deliverable.check(candidate) === true;
27002
+ return checkVerdictOf(await args.deliverable.check(candidate)).pass;
26087
27003
  } catch (error) {
27004
+ if (error instanceof CheckUnavailableError) throw error;
26088
27005
  throw new ValidationError$1(`finalizer: parent completion check threw: ${error instanceof Error ? error.message : String(error)}`);
26089
27006
  }
26090
27007
  };
@@ -26349,10 +27266,10 @@ function createSupervisor() {
26349
27266
  pool = createBudgetPool(opts.budget, runEpochMs, restored.poolRestore);
26350
27267
  } else {
26351
27268
  pool = createBudgetPool(opts.budget, runStartedAtMs);
26352
- await opts.journal.beginTree(opts.runId, runStartedAt);
27269
+ if (existing === void 0) await opts.journal.beginTree(opts.runId, runStartedAt);
26353
27270
  const rootReceipt = rootMaterializationReceipt(opts);
26354
27271
  const rootRuntime = opts.rootMaterialization?.runtime ?? "inline";
26355
- await opts.journal.appendEvent(opts.runId, {
27272
+ const rootEvents = [{
26356
27273
  kind: "spawned",
26357
27274
  id: opts.runId,
26358
27275
  label: "root",
@@ -26362,14 +27279,15 @@ function createSupervisor() {
26362
27279
  ...opts.rootIdentity ? { identity: opts.rootIdentity } : {},
26363
27280
  seq: 0,
26364
27281
  at: runStartedAt
26365
- });
26366
- if (rootReceipt !== void 0) await opts.journal.appendEvent(opts.runId, {
27282
+ }];
27283
+ if (rootReceipt !== void 0) rootEvents.push({
26367
27284
  kind: "materialized",
26368
27285
  id: opts.runId,
26369
27286
  receipt: rootReceipt,
26370
27287
  seq: 0,
26371
27288
  at: runStartedAt
26372
27289
  });
27290
+ await appendSpawnEvents(opts.journal, opts.runId, rootEvents);
26373
27291
  }
26374
27292
  const stableRootReceipt = resuming ? prior?.find((event) => event.kind === "materialized" && event.id === opts.runId)?.receipt : rootMaterializationReceipt(opts);
26375
27293
  if (stableRootReceipt !== void 0) {
@@ -26501,6 +27419,7 @@ function createSupervisor() {
26501
27419
  seq: teardownSeq++,
26502
27420
  at: new Date(now()).toISOString()
26503
27421
  });
27422
+ if (releasing) await closeRetainedSlots(openScope);
26504
27423
  } catch (error) {
26505
27424
  if (actOutcome?.ok !== false) actOutcome = {
26506
27425
  ok: false,
@@ -26706,11 +27625,18 @@ function createIntensityBreaker(opts, trip) {
26706
27625
  * settlement either (it writes no `settled` record then), so `downCount` stays what it was:
26707
27626
  * ordinary downs only; `fleetYield.down` is where a retained child is counted. */
26708
27627
  function wrapJournalForBreaker(journal, breaker) {
27628
+ const recordDown = (ev) => {
27629
+ if (ev.kind === "settled" && ev.status === "down" && ev.retainedExecution === void 0) breaker.recordDown(Date.parse(ev.at));
27630
+ };
26709
27631
  return {
26710
27632
  loadTree: (root) => journal.loadTree(root),
26711
27633
  beginTree: (root, at) => journal.beginTree(root, at),
27634
+ ...journal.appendEvents === void 0 ? {} : { appendEvents: (root, events) => {
27635
+ for (const event of events) recordDown(event);
27636
+ return journal.appendEvents?.(root, events) ?? Promise.resolve();
27637
+ } },
26712
27638
  appendEvent: (root, ev) => {
26713
- if (ev.kind === "settled" && ev.status === "down" && ev.retainedExecution === void 0) breaker.recordDown(Date.parse(ev.at));
27639
+ recordDown(ev);
26714
27640
  return journal.appendEvent(root, ev);
26715
27641
  }
26716
27642
  };
@@ -26917,13 +27843,16 @@ function fleetYieldFromForest(forest) {
26917
27843
  const spawned = /* @__PURE__ */ new Set();
26918
27844
  const terminal = /* @__PURE__ */ new Map();
26919
27845
  const released = /* @__PURE__ */ new Set();
27846
+ const unconfirmed = /* @__PURE__ */ new Set();
26920
27847
  for (const { event } of forest.events) if (event.kind === "spawned") {
26921
27848
  if (event.parent !== void 0) spawned.add(event.id);
26922
27849
  } else if (event.kind === "settled" || event.kind === "cancelled") {
26923
27850
  const bucket = event.kind === "cancelled" ? "cancelled" : event.status;
26924
27851
  terminal.set(event.id, bucket);
26925
- if (event.retainedExecution === "released" && bucket !== "done") released.add(event.id);
26926
- else released.delete(event.id);
27852
+ released.delete(event.id);
27853
+ unconfirmed.delete(event.id);
27854
+ if (bucket !== "done" && event.retainedExecution === "released") released.add(event.id);
27855
+ if (bucket !== "done" && event.retainedExecution === "release-unconfirmed") unconfirmed.add(event.id);
26927
27856
  }
26928
27857
  const count = (bucket) => [...terminal.values()].filter((value) => value === bucket).length;
26929
27858
  const fleetYield = {
@@ -26932,10 +27861,11 @@ function fleetYieldFromForest(forest) {
26932
27861
  down: count("down"),
26933
27862
  cancelled: count("cancelled"),
26934
27863
  neverSettled: forest.inDoubt.length,
26935
- releasedUnrecovered: released.size
27864
+ releasedUnrecovered: released.size,
27865
+ releaseUnconfirmed: unconfirmed.size
26936
27866
  };
26937
27867
  if (fleetYield.done + fleetYield.down + fleetYield.cancelled + fleetYield.neverSettled !== fleetYield.spawned) throw new RuntimeRunStateError(`supervisor: fleet yield does not partition the spawned children of '${forest.root}' (${JSON.stringify(fleetYield)})`);
26938
- if (fleetYield.releasedUnrecovered > fleetYield.down + fleetYield.cancelled) throw new RuntimeRunStateError(`supervisor: released children exceed down + cancelled for '${forest.root}' (${JSON.stringify(fleetYield)})`);
27868
+ if (fleetYield.releasedUnrecovered + fleetYield.releaseUnconfirmed > fleetYield.down + fleetYield.cancelled) throw new RuntimeRunStateError(`supervisor: released children exceed down + cancelled for '${forest.root}' (${JSON.stringify(fleetYield)})`);
26939
27869
  return fleetYield;
26940
27870
  }
26941
27871
  /** The journaled nodes whose usage accounting is incomplete — one `SpendGap` per node+kind,
@@ -27000,6 +27930,6 @@ function isNonEmptySpend(s) {
27000
27930
  return s.iterations > 0 || s.tokens.input > 0 || s.tokens.output > 0 || s.usd > 0 || s.ms > 0 || s.tokensKnown === false || s.usdKnown === false || Object.values(s.resources ?? {}).some((resource) => resource.amount > 0 || !resource.known);
27001
27931
  }
27002
27932
  //#endregion
27003
- export { interactiveAdmissionSeamKey as $, cloneSpend as $i, retainedCreateMaterial as $n, profileMaterializationAxes$1 as $r, readWorkerProgress as $t, restoreScopeOwnerAcceptedExecution as A, runtimeOwnedScopeOwnerRuntime as Ai, routerBrain as An, createRuntimeEventCollector as Ar, pendingWaits as At, bindScopeRetainedOwnerEnvironmentId as B, canonicalStreamEventFromSandboxEvent as Bi, sandboxClientAsProvider as Bn, DEFAULT_LOCAL_HARNESS as Br, createBudgetPool as Bt, beginScopeOwnerAttempt as C, promptOptionsFromAgentTurnInput as Ca, providerAttemptEvidence as Ci, isTerminalDecision as Cn, exportEvalRuns as Cr, FileResultBlobStore as Ct, meterRuntimeOwnedProviderAttempt as D, runtimeOwnedExecutorMaterialization as Di, acquireSandbox as Dn, padSpanId as Dr, insideCursorNamespace as Dt, meterRuntimeOwnedAccounting as E, runtimeOwnedExecutorExecutionBinding as Ei, probeSandboxCapabilities as En, loopEventToOtelSpan as Er, InMemorySpawnJournal as Et, isWaitOutcome as F, detachedFrozen as Fi, LEAF_CONTINUATION_TASK as Fn, runSettledCommand as Fr, parseWorkerToolTraceArtifact as Ft, scopeRetainedOwnerContext as G, mapSandboxEvent as Gi, sandboxSessionTraceSource as Gn, parseCodexTokenUsage as Gr, WORKER_TRACE_PROPAGATION as Gt, consumeScopeRetainedOwnerResult as H, createSandboxUsageLedger as Hi, unavailableSignalOfFailure as Hn, harnessInvocation as Hr, newUsageTotals as Ht, pollFor as I, detachedSnapshot as Ii, createAgentEnvironmentProviderRegistry as In, runWorktreeHarness as Ir, workerTraceAnalysisStore as It, scopeRetainedOwnerResult as J, sandboxEventServedBackend as Ji, errMessage as Jn, AGENT_PROFILE_MATERIALIZATION_AXES as Jr, workerTraceHeaders as Jt, scopeRetainedOwnerPriorSpend as K, mapSandboxToolEvent as Ki, registerRetainedExecutorPreparation as Kn, CodexExecutionDiagnosticError as Kr, readWorkerTraceContext as Kt, timerAt as L, projectSandboxOutcome as Li, providerAsExecutor as Ln, captureWorktreeDiff as Lr, BudgetReconcileFault as Lt, settledToIteration as M, unknownMaterializationReceipt as Mi, canonicalObservedModelParts as Mn, sanitizeAgentRuntimeEvent as Mr, WORKER_TOOL_TRACE_SCHEMA_VERSION as Mt, createWorkerSlots as N, executableAgentProfileSnapshot as Ni, observedModelMatchesDeclared as Nn, sanitizeKnowledgeReadinessReport as Nr, captureWorkerTraceEvidence as Nt, recordScopeOwnerMaterialization as O, runtimeOwnedExecutorProviderEvidence as Oi, assertBoxlessPromptOptions as On, padTraceId as Or, loadSpawnForest as Ot, createWaitProbes as P, executableAgentSpecSnapshot as Pi, DEFAULT_SANDBOX_IDLE_TIMEOUT_SECONDS as Pn, sanitizeRuntimeStreamEvent as Pr, isTraceAnalysisStore as Pt, resolveSpawnResourcePaths as Q, chargedTokens as Qi, startRetainedRunInEnvironment as Qn, fullProfileMaterialization as Qr, createActivityLog as Qt, validateWaitSpec as R, readSandboxOutcome as Ri, providerAsSandboxClient as Rn, createWorktree as Rr, ReservationWaitRefused as Rt, assertRecursiveReservationPolicy as S, promptFromAgentTurnInput as Sa, newExecutionAttemptId as Si, defaultSelectWinner as Sn, createOtelExporter as Sr, createInPlaceCliExecutor as St, deriveNodeExecutionIdentity as T, runtimeOwnedDriveHarnessProviderEvidence as Ti, createSandboxLineage as Tn, generateSpanId as Tr, InMemoryResultBlobStore as Tt, prepareScopeRetainedOwnerTask as U, extractLlmCallEvent as Ui, createPushTraceSource as Un, harnessSupportsReasoningEffort as Ur, spendFromUsageEvents as Ut, bindScopeRetainedOwnerProvider as V, createSandboxToolPartState as Vi, unavailablePauseMs as Vn, LOCAL_HARNESSES as Vr, meterUsageEvent as Vt, reconcileScopeRetainedOwnerEnvironment as W, isSandboxTerminalEvent as Wi, decodeToolPart as Wn, localHarnessExecutable as Wr, spendFromUsageTotals as Wt, environmentReader as X, sumSandboxUsage as Xi, recoverRetainedRun as Xn, controlProfileMaterialization as Xr, taskToPrompt as Xt, SPAWN_RESOURCE_PATH_MAX_BYTES as Y, sandboxProgressEvents as Yi, reconnectRetainedRun as Yn, assertProfileMaterialization as Yr, workerTraceSeamKey as Yt, hostDirectoryReader as Z, addSpend as Zi, startRetainedRun as Zn, defineProfileMaterializationContract as Zr, DEFAULT_STALL_AFTER_MS as Zt, driverChild as _, awaitAbortable$1 as _a, authoredProfileDigest as _i, readCodexRolloutSession as _n, INTELLIGENCE_WIRE_VERSION as _r, createExecutorRegistry as _t, collectDelivered as a, sleep as aa, renderUnsupported as ai, createPeerMailbox as an, runAbortable as ar, workerInteractiveBindingsDir as at, withDriverExecutor as b, teardownExecutor as ba, knownExecutionBindingReceipt as bi, TERMINAL_DECISIONS as bn, buildRuntimeEventOtelSpans as br, DEFAULT_SANDBOX_STEERING_MAX_TURNS as bt, runTree as c, throwIfAborted as ca, validateProfileMaterialization as ci, peerMailVerbNames as cn, resolveRedactor as cr, startRetainedInteractiveRun as ct, HarnessTurnFailedError as d, zeroSpend as da, parseCommittedJsonLines as di, executorFailure as dn, persistHarnessTranscript as dr, rollingDispatch as dt, deleteBoxSafe as ea, promptControlProfileMaterialization as ei, createInbox as en, destroyInteractiveEnvironment as er, readWorkerInteractiveAdmissions as et, classifyDriverFailure as f, addResourceSpend as fa, prepareJsonlAppend as fi, bridgeAdmissionRefusal as fn, contentAddress as fr, bindReusableExecutorExecutionId as ft, upstreamUnavailableSignal as g, abortError$2 as ga, attestRuntimeOwnedScopeOwner as gi, harnessUsageIsEmpty as gn, traceContextToEnv as gr, createExecutor as gt, summarizeDriverAttempts as h, decodeHarnessUsage as ha, attestRuntimeOwnedPendingExecutor as hi, createCodexRolloutStoreReader as hn, readTraceContextFromEnv as hr, cliWorktreeExecutor as ht, bestDelivered as i, randomSuffix as ia, renderProfileMaterializationIssues as ii, claimsAuthority as in, linkAbort as ir, workerInteractiveBindingFile as it, scopeOwnerExecutorNodeContext as j, unknownExecutionBindingReceipt as ji, runBrainLoop as jn, createRuntimeStreamEventCollector as jr, replaySpawnTree as jt, recordScopeOwnerPause as k, runtimeOwnedPendingExecutorMaterialization as ki, readPromptOptions as kn, toOtelAttributes as kr, materializeTreeView as kt, DEFAULT_MAX_BARREN_REPROMPTS as l, unmeteredSpend as la, worktreeCliProfileMaterialization as li, isLiveNodeStatus as ln, captureHarnessTranscript as lr, freeSlots as lt, runDriverWithRetry as m, withBudgetResources as ma, writeAllBytes as mi, addHarnessUsage as mn, mergeTraceEnv as mr, cliInPlaceExecutor as mt, createRootHandle as n, isAbortError$2 as na, promptOnlyProfileMaterialization as ni, DEFAULT_PEER_MAIL_LIMITS as nn, RunCancellationReason as nr, attachWorker as nt, pickBestDelivered as o, stringifySafe as oa, sandboxActProfileMaterialization as oi, isPeerMailEnvelope as on, defaultRedactor as or, reconnectRetainedInteractiveRun as ot, defaultUnmetContractSteer as p, resourceTelemetry as pa, readCommittedJsonLines as pi, bridgeModelRouteRefusal as pn, createPropagatingTraceEmitter as pr, captureReusableExecutorConfig as pt, scopeRetainedOwnerResourceReader as q, notifySandboxEventObserver as qi, retainedExecutorSeamKey as qn, terminateProcessTreeAndConfirm as qr, workerTraceEnv as qt, createSupervisor as r, promptCacheTokenClasses as ra, promptResourceProfileMaterialization as ri, PEER_MAIL_WIRE_KEY as rn, abortError as rr, readWorkerInteractiveBinding as rt, runFinalizer as s, throwAbort as sa, unsupportedProfileDimensions as si, peerMailTools as sn, defaultRedactorIdentityMaterial as sr, recoverRetainedInteractiveRun as st, DEFAULT_MAX_DEPTH as t, hasCompleteCacheBreakdown as ta, promptModelProfileMaterialization as ti, AUTHORITY_MARKERS as tn, environmentGone as tr, workerInteractiveAdmissionFile as tt, DriverAttemptsExhaustedError as u, withTimeout as ua, isNoEntError as ui, isTerminalNodeStatus as un, harnessTranscriptArtifact as ur, queueOf as ut, driverExecutorFactory as v, DEFAULT_SUCCESSFUL_SHUTDOWN_MS as va, finalizeRuntimeOwnedPendingExecutor as vi, bridgeRuntimeAttachmentsKey as vn, buildLoopOtelSpans as vr, snapshotExecutorConfig as vt, createScope as w, providerMessageText as wa, recordRuntimeOwnedDriveHarnessProviderEvidence as wi, runAgentRounds as wn, flatOtelSpan as wr, FileSpawnJournal as wt, SUBTREE_RESULT_LIMIT as x, teardownSurfaces as xa, knownMaterializationReceipt as xi, createSandboxForSpec as xn, createOpenInferenceFileExporter as xr, createSteerableSandboxSession as xt, isDriverSpec as y, armDeadlineTimer as ya, inheritRuntimeOwnedExecutorAttestation as yi, bridgeStopSignalKey as yn, buildLoopSpanNodes as yr, createWorktreeCliExecutor as yt, waitUntil as z, assertSandboxServedModel as zi, resolveAgentEnvironmentProvider as zn, removeWorktree as zr, assertValidBudget as zt };
27933
+ export { bindScopeRetainedOwnerProvider as $, detachedSnapshot as $i, providerAsExecutor as $n, runWorktreeHarness as $r, BudgetReconcileFault as $t, driverExecutorFactory as A, resourceTelemetry as Aa, readCommittedJsonLines as Ai, addHarnessUsage as An, createPropagatingTraceEmitter as Ar, snapshotExecutorConfig as At, recordScopeOwnerMaterialization as B, promptOptionsFromAgentTurnInput as Ba, providerAttemptEvidence as Bi, runAgentRounds as Bn, exportEvalRuns as Br, SpawnEventIndex as Bt, createContinuationKeeper as C, stringifySafe as Ca, sandboxActProfileMaterialization as Ci, peerMailTools as Cn, defaultRedactorIdentityMaterial as Cr, rollingDispatch as Ct, passedItems as D, withTimeout as Da, isNoEntError as Di, executorFailure as Dn, persistHarnessTranscript as Dr, cliWorktreeExecutor as Dt, failedItems as E, unmeteredSpend as Ea, worktreeCliProfileMaterialization as Ei, isTerminalNodeStatus as En, harnessTranscriptArtifact as Er, cliInPlaceExecutor as Et, beginScopeOwnerAttempt as F, DEFAULT_SUCCESSFUL_SHUTDOWN_MS as Fa, finalizeRuntimeOwnedPendingExecutor as Fi, bridgeStopSignalKey as Fn, buildLoopOtelSpans as Fr, createInPlaceCliExecutor as Ft, createWorkerSlots as G, runtimeOwnedExecutorProviderEvidence as Gi, readPromptOptions as Gn, padTraceId as Gr, materializeTreeView as Gt, restoreScopeOwnerAcceptedExecution as H, runtimeOwnedDriveHarnessProviderEvidence as Hi, probeSandboxCapabilities as Hn, generateSpanId as Hr, encodeResultBlob as Ht, createScope as I, armDeadlineTimer as Ia, inheritRuntimeOwnedExecutorAttestation as Ii, TERMINAL_DECISIONS as In, buildLoopSpanNodes as Ir, FileResultBlobStore as It, pollFor as J, unknownExecutionBindingReceipt as Ji, canonicalObservedModelParts as Jn, createRuntimeStreamEventCollector as Jr, WORKER_TOOL_TRACE_SCHEMA_VERSION as Jt, createWaitProbes as K, runtimeOwnedPendingExecutorMaterialization as Ki, routerBrain as Kn, toOtelAttributes as Kr, pendingWaits as Kt, deriveNodeExecutionIdentity as L, teardownExecutor as La, knownExecutionBindingReceipt as Li, createSandboxForSpec as Ln, buildRuntimeEventOtelSpans as Lr, FileSpawnJournal as Lt, withDriverExecutor as M, decodeHarnessUsage as Ma, attestRuntimeOwnedPendingExecutor as Mi, harnessUsageIsEmpty as Mn, readTraceContextFromEnv as Mr, DEFAULT_SANDBOX_STEERING_MAX_TURNS as Mt, SUBTREE_RESULT_LIMIT as N, abortError$2 as Na, attestRuntimeOwnedScopeOwner as Ni, readCodexRolloutSession as Nn, traceContextToEnv as Nr, createSteerableSandboxSession as Nt, verdictFromJudgeScore as O, zeroSpend as Oa, parseCommittedJsonLines as Oi, bridgeAdmissionRefusal as On, readHarnessTranscript as Or, createExecutor as Ot, assertRecursiveReservationPolicy as P, awaitAbortable$1 as Pa, authoredProfileDigest as Pi, bridgeRuntimeAttachmentsKey as Pn, INTELLIGENCE_WIRE_VERSION as Pr, createRouterTranscript as Pt, bindScopeRetainedOwnerEnvironmentId as Q, detachedFrozen as Qi, createAgentEnvironmentProviderRegistry as Qn, runSettledCommand as Qr, workerTraceAnalysisStore as Qt, meterRuntimeOwnedAccounting as R, teardownSurfaces as Ra, knownMaterializationReceipt as Ri, defaultSelectWinner as Rn, createOpenInferenceFileExporter as Rr, InMemoryResultBlobStore as Rt, composeContinuationNote as S, sleep as Sa, renderUnsupported as Si, isPeerMailEnvelope as Sn, defaultRedactor as Sr, queueOf as St, expandQuestions as T, throwIfAborted as Ta, validateProfileMaterialization as Ti, isLiveNodeStatus as Tn, captureHarnessTranscript as Tr, captureReusableExecutorConfig as Tt, scopeOwnerExecutorNodeContext as U, runtimeOwnedExecutorExecutionBinding as Ui, acquireSandbox as Un, loopEventToOtelSpan as Ur, insideCursorNamespace as Ut, recordScopeOwnerPause as V, providerMessageText as Va, recordRuntimeOwnedDriveHarnessProviderEvidence as Vi, createSandboxLineage as Vn, flatOtelSpan as Vr, assertContentAddress as Vt, settledToIteration as W, runtimeOwnedExecutorMaterialization as Wi, assertBoxlessPromptOptions as Wn, padSpanId as Wr, loadSpawnForest as Wt, validateWaitSpec as X, executableAgentProfileSnapshot as Xi, DEFAULT_SANDBOX_IDLE_TIMEOUT_SECONDS as Xn, sanitizeKnowledgeReadinessReport as Xr, isTraceAnalysisStore as Xt, timerAt as Y, unknownMaterializationReceipt as Yi, observedModelMatchesDeclared as Yn, sanitizeAgentRuntimeEvent as Yr, captureWorkerTraceEvidence as Yt, waitUntil as Z, executableAgentSpecSnapshot as Zi, LEAF_CONTINUATION_TASK as Zn, sanitizeRuntimeStreamEvent as Zr, parseWorkerToolTraceArtifact as Zt, CheckUnavailableError as _, deleteBoxSafe as _a, promptControlProfileMaterialization as _i, AUTHORITY_MARKERS as _n, environmentGone as _r, workerInteractiveBindingsDir as _t, collectDelivered as a, createSandboxUsageLedger as aa, harnessInvocation as ai, spendFromUsageEvents as an, createPushTraceSource as ar, scopeRetainedOwnerResourceReader as at, bestComposite as b, promptCacheTokenClasses as ba, promptResourceProfileMaterialization as bi, claimsAuthority as bn, linkAbort as br, startRetainedInteractiveRun as bt, runTree as c, mapSandboxEvent as ca, parseCodexTokenUsage as ci, readWorkerTraceContext as cn, registerRetainedExecutorPreparation as cr, environmentReader as ct, classifyDriverFailure as d, sandboxEventServedBackend as da, AGENT_PROFILE_MATERIALIZATION_AXES as di, workerTraceSeamKey as dn, reconnectRetainedRun as dr, interactiveAdmissionSeamKey as dt, projectSandboxOutcome as ea, captureWorktreeDiff as ei, ReservationWaitRefused as en, providerAsSandboxClient as er, consumeScopeRetainedOwnerResult as et, runDriverWithRetry as f, sandboxProgressEvents as fa, assertProfileMaterialization as fi, taskToPrompt as fn, recoverRetainedRun as fr, readWorkerInteractiveAdmissions as ft, CONTINUATION_FACTS as g, cloneSpend as ga, profileMaterializationAxes$1 as gi, createInbox as gn, destroyInteractiveEnvironment as gr, workerInteractiveBindingFile as gt, CONTINUATIONS_DIR as h, chargedTokens as ha, fullProfileMaterialization as hi, readWorkerProgress as hn, retainedCreateMaterial as hr, readWorkerInteractiveBinding as ht, bestDelivered as i, createSandboxToolPartState as ia, LOCAL_HARNESSES as ii, newUsageTotals as in, unavailableSignalOfFailure as ir, scopeRetainedOwnerPriorSpend as it, isDriverSpec as j, withBudgetResources as ja, writeAllBytes as ji, createCodexRolloutStoreReader as jn, mergeTraceEnv as jr, createWorktreeCliExecutor as jt, driverChild as k, addResourceSpend as ka, prepareJsonlAppend as ki, bridgeModelRouteRefusal as kn, contentAddress as kr, createExecutorRegistry as kt, DriverAttemptsExhaustedError as l, mapSandboxToolEvent as la, CodexExecutionDiagnosticError as li, workerTraceEnv as ln, retainedExecutorSeamKey as lr, hostDirectoryReader as lt, upstreamUnavailableSignal as m, addSpend as ma, defineProfileMaterializationContract as mi, createActivityLog as mn, startRetainedRunInEnvironment as mr, attachWorker as mt, createRootHandle as n, assertSandboxServedModel as na, removeWorktree as ni, createBudgetPool as nn, sandboxClientAsProvider as nr, reconcileScopeRetainedOwnerEnvironment as nt, pickBestDelivered as o, extractLlmCallEvent as oa, harnessSupportsReasoningEffort as oi, spendFromUsageTotals as on, decodeToolPart as or, scopeRetainedOwnerResult as ot, summarizeDriverAttempts as p, sumSandboxUsage as pa, controlProfileMaterialization as pi, DEFAULT_STALL_AFTER_MS as pn, startRetainedRun as pr, workerInteractiveAdmissionFile as pt, isWaitOutcome as q, runtimeOwnedScopeOwnerRuntime as qi, runBrainLoop as qn, createRuntimeEventCollector as qr, replaySpawnTree as qt, createSupervisor as r, canonicalStreamEventFromSandboxEvent as ra, DEFAULT_LOCAL_HARNESS as ri, meterUsageEvent as rn, unavailablePauseMs as rr, scopeRetainedOwnerContext as rt, runFinalizer as s, isSandboxTerminalEvent as sa, localHarnessExecutable as si, WORKER_TRACE_PROPAGATION as sn, sandboxSessionTraceSource as sr, SPAWN_RESOURCE_PATH_MAX_BYTES as st, DEFAULT_MAX_DEPTH as t, readSandboxOutcome as ta, createWorktree as ti, assertValidBudget as tn, resolveAgentEnvironmentProvider as tr, prepareScopeRetainedOwnerTask as tt, HarnessTurnFailedError as u, notifySandboxEventObserver as ua, terminateProcessTreeAndConfirm as ui, workerTraceHeaders as un, errMessage as ur, resolveSpawnResourcePaths as ut, admitContinuationPolicy as v, hasCompleteCacheBreakdown as va, promptModelProfileMaterialization as vi, DEFAULT_PEER_MAIL_LIMITS as vn, RunCancellationReason as vr, reconnectRetainedInteractiveRun as vt, distillFindings as w, throwAbort as wa, unsupportedProfileDimensions as wi, peerMailVerbNames as wn, resolveRedactor as wr, bindReusableExecutorExecutionId as wt, checkVerdictOf as x, randomSuffix as xa, renderProfileMaterializationIssues as xi, createPeerMailbox as xn, runAbortable as xr, freeSlots as xt, admitFinding as y, isAbortError$2 as ya, promptOnlyProfileMaterialization as yi, PEER_MAIL_WIRE_KEY as yn, abortError as yr, recoverRetainedInteractiveRun as yt, meterRuntimeOwnedProviderAttempt as z, promptFromAgentTurnInput as za, newExecutionAttemptId as zi, isTerminalDecision as zn, createOtelExporter as zr, InMemorySpawnJournal as zt };
27004
27934
 
27005
- //# sourceMappingURL=supervisor-B8UMAXya.js.map
27935
+ //# sourceMappingURL=supervisor-DdKPGluv.js.map