@tangle-network/agent-runtime 0.193.1 → 0.195.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/dist/{activation-BismttgN.js → activation-DtIbcFOX.js} +3 -3
  2. package/dist/{activation-BismttgN.js.map → activation-DtIbcFOX.js.map} +1 -1
  3. package/dist/agent.d.ts +1 -1
  4. package/dist/agent.js +2 -2
  5. package/dist/candidate-execution/index.js +4 -4
  6. package/dist/{candidate-execution-BSkZErxD.js → candidate-execution-nvqVIMyS.js} +5 -4
  7. package/dist/{candidate-execution-BSkZErxD.js.map → candidate-execution-nvqVIMyS.js.map} +1 -1
  8. package/dist/{conversation-DILnmy84.js → conversation-BXPWMOSd.js} +4 -5
  9. package/dist/{conversation-DILnmy84.js.map → conversation-BXPWMOSd.js.map} +1 -1
  10. package/dist/conversation.d.ts +1 -1
  11. package/dist/conversation.js +1 -1
  12. package/dist/{coordination-driver-DujHiIGa.js → coordination-driver-iSN-m3VX.js} +281 -244
  13. package/dist/coordination-driver-iSN-m3VX.js.map +1 -0
  14. package/dist/{authoring-DWiqKSDY.js → delegate-DCC2muUd.js} +56 -13
  15. package/dist/delegate-DCC2muUd.js.map +1 -0
  16. package/dist/delegation-status-BlsbSeOB.js +358 -0
  17. package/dist/delegation-status-BlsbSeOB.js.map +1 -0
  18. package/dist/durable.d.ts +2 -2
  19. package/dist/durable.js +3 -3
  20. package/dist/{environment-provider-DEwsolvi.js → environment-provider-Dr-wfnHg.js} +422 -8
  21. package/dist/environment-provider-Dr-wfnHg.js.map +1 -0
  22. package/dist/{environment-provider-DpPGJfK-.d.ts → environment-provider-adVa6X7a.d.ts} +2 -2
  23. package/dist/environment-provider.d.ts +1 -1
  24. package/dist/environment-provider.js +1 -1
  25. package/dist/{graph-DORfp9WX.js → graph-DghidDx5.js} +138 -5
  26. package/dist/graph-DghidDx5.js.map +1 -0
  27. package/dist/graph.d.ts +3 -3
  28. package/dist/graph.js +4 -5
  29. package/dist/graph.js.map +1 -1
  30. package/dist/{improve-Bn1zpWHF.d.ts → improve-7VTwse1c.d.ts} +6 -6
  31. package/dist/{improvement-cycle-BbsiYcpH.js → improvement-cycle-bTBySunH.js} +22 -8
  32. package/dist/{improvement-cycle-BbsiYcpH.js.map → improvement-cycle-bTBySunH.js.map} +1 -1
  33. package/dist/{index-Vz-13VZq.d.ts → index-CVD30soi.d.ts} +4 -4
  34. package/dist/{index-DV1lzp9p.d.ts → index-DNx0nWZH.d.ts} +57 -51
  35. package/dist/{index-RM2oRI9s.d.ts → index-DO6DHgRP.d.ts} +2 -2
  36. package/dist/index.d.ts +10 -9
  37. package/dist/index.js +75 -29
  38. package/dist/index.js.map +1 -1
  39. package/dist/intelligence.d.ts +5 -5
  40. package/dist/intelligence.js +7 -6
  41. package/dist/intelligence.js.map +1 -1
  42. package/dist/{executable-spec-DxuiDFAU.js → jsonl-file-Bh1Q9nt0.js} +59 -3
  43. package/dist/jsonl-file-Bh1Q9nt0.js.map +1 -0
  44. package/dist/kernel.d.ts +6 -6
  45. package/dist/kernel.js +11 -12
  46. package/dist/{knowledge-RW1pbZCH.js → knowledge-U8WJ5xCI.js} +7 -17
  47. package/dist/knowledge-U8WJ5xCI.js.map +1 -0
  48. package/dist/knowledge.d.ts +1 -1
  49. package/dist/knowledge.js +1 -1
  50. package/dist/{loop-runner-bin-sBwcyQTc.js → loop-runner-bin-BU2NACsF.js} +3 -3
  51. package/dist/{loop-runner-bin-sBwcyQTc.js.map → loop-runner-bin-BU2NACsF.js.map} +1 -1
  52. package/dist/{loop-runner-bin-CGraqNiA.d.ts → loop-runner-bin-b4585v9Z.d.ts} +3 -3
  53. package/dist/loop-runner-bin.d.ts +1 -1
  54. package/dist/loop-runner-bin.js +1 -1
  55. package/dist/{materialization-CekWK6OO.js → materialization-vZssF9Nx.js} +28 -3
  56. package/dist/materialization-vZssF9Nx.js.map +1 -0
  57. package/dist/mcp/bin.js +3 -3
  58. package/dist/mcp/index.d.ts +4 -4
  59. package/dist/mcp/index.js +8 -8
  60. package/dist/mcp/index.js.map +1 -1
  61. package/dist/{openai-tools-6jUqkGG7.js → openai-tools-DmvmaG0a.js} +2 -2
  62. package/dist/{openai-tools-6jUqkGG7.js.map → openai-tools-DmvmaG0a.js.map} +1 -1
  63. package/dist/{prepare-B5fJ7mLS.js → prepare-DDGp0-rW.js} +4 -59
  64. package/dist/prepare-DDGp0-rW.js.map +1 -0
  65. package/dist/primeintellect/index.d.ts +1 -1
  66. package/dist/profiles.js +454 -1
  67. package/dist/profiles.js.map +1 -1
  68. package/dist/{protected-model-port-B0xFSAjt.js → protected-model-port-DxFN8DLS.js} +3 -2
  69. package/dist/{protected-model-port-B0xFSAjt.js.map → protected-model-port-DxFN8DLS.js.map} +1 -1
  70. package/dist/{protected-redaction--F3v1oo8.js → protected-redaction-wGo44k2K.js} +54 -3
  71. package/dist/protected-redaction-wGo44k2K.js.map +1 -0
  72. package/dist/{provision-supervisor-CddfH9mg.js → provision-supervisor-CRPbnJiB.js} +6 -8
  73. package/dist/{provision-supervisor-CddfH9mg.js.map → provision-supervisor-CRPbnJiB.js.map} +1 -1
  74. package/dist/{redact-D0OzQsyt.js → redact-BOU77QfQ.js} +1013 -24
  75. package/dist/redact-BOU77QfQ.js.map +1 -0
  76. package/dist/{runtime-V91N6sPc.d.ts → runtime-B8x43nGP.d.ts} +5 -4
  77. package/dist/{runtime-ZM4i-jEF.js → runtime-CuNJ0opC.js} +153 -77
  78. package/dist/runtime-CuNJ0opC.js.map +1 -0
  79. package/dist/server-D6XmE1Du.js +1311 -0
  80. package/dist/server-D6XmE1Du.js.map +1 -0
  81. package/dist/{stream-agent-turn-1ahpdeIo.d.ts → stream-agent-turn-B-gtBlOy.d.ts} +2 -2
  82. package/dist/{stream-agent-turn-DWWe_7bh.js → stream-agent-turn-DOtEsvCV.js} +3 -3
  83. package/dist/{stream-agent-turn-DWWe_7bh.js.map → stream-agent-turn-DOtEsvCV.js.map} +1 -1
  84. package/dist/{structural-rollout-CktnUTCC.js → structural-rollout-DxEQ77H7.js} +37 -51
  85. package/dist/structural-rollout-DxEQ77H7.js.map +1 -0
  86. package/dist/{supervise-Dj6zd2C7.js → supervise-C0V3pZXK.js} +154 -1961
  87. package/dist/supervise-C0V3pZXK.js.map +1 -0
  88. package/dist/testing.d.ts +2 -2
  89. package/dist/testing.js +14 -13
  90. package/dist/testing.js.map +1 -1
  91. package/dist/tui/index.d.ts +1 -1
  92. package/dist/tui/index.js +1 -1
  93. package/dist/{types-CGez_ZHQ.d.ts → types-B_pNTBjK.d.ts} +5 -2
  94. package/dist/{workspace-archive-yAPDklLV.js → workspace-archive-Ybomp7AN.js} +3 -2
  95. package/dist/{workspace-archive-yAPDklLV.js.map → workspace-archive-Ybomp7AN.js.map} +1 -1
  96. package/package.json +4 -4
  97. package/skills/agent-graphs/SKILL.md +28 -123
  98. package/skills/agent-graphs/references/authoring.md +34 -0
  99. package/skills/agent-graphs/references/measurement.md +18 -0
  100. package/skills/build-with-agent-runtime/SKILL.md +31 -117
  101. package/skills/build-with-agent-runtime/references/improvement.md +32 -0
  102. package/skills/codemode/SKILL.md +22 -34
  103. package/skills/codemode/references/runtime-execution.md +14 -0
  104. package/skills/generate-eval/SKILL.md +2 -1
  105. package/skills/loop-writer/SKILL.md +30 -84
  106. package/skills/supervise/SKILL.md +43 -77
  107. package/skills/supervise/references/profile-authoring.md +19 -0
  108. package/dist/authoring-DWiqKSDY.js.map +0 -1
  109. package/dist/coordination-driver-DujHiIGa.js.map +0 -1
  110. package/dist/environment-provider-DEwsolvi.js.map +0 -1
  111. package/dist/executable-spec-DxuiDFAU.js.map +0 -1
  112. package/dist/graph-DORfp9WX.js.map +0 -1
  113. package/dist/jsonl-file-CDfsCI5s.js +0 -59
  114. package/dist/jsonl-file-CDfsCI5s.js.map +0 -1
  115. package/dist/knowledge-RW1pbZCH.js.map +0 -1
  116. package/dist/materialization-CekWK6OO.js.map +0 -1
  117. package/dist/prepare-B5fJ7mLS.js.map +0 -1
  118. package/dist/protected-redaction--F3v1oo8.js.map +0 -1
  119. package/dist/redact-D0OzQsyt.js.map +0 -1
  120. package/dist/researcher-hgPa5p9i.js +0 -457
  121. package/dist/researcher-hgPa5p9i.js.map +0 -1
  122. package/dist/runtime-ZM4i-jEF.js.map +0 -1
  123. package/dist/snapshot-CTAf4uuA.js +0 -26
  124. package/dist/snapshot-CTAf4uuA.js.map +0 -1
  125. package/dist/spawn-journal-B9eTmVAn.js +0 -999
  126. package/dist/spawn-journal-B9eTmVAn.js.map +0 -1
  127. package/dist/structural-rollout-CktnUTCC.js.map +0 -1
  128. package/dist/supervise-Dj6zd2C7.js.map +0 -1
  129. package/dist/util-mCNUeboW.js +0 -419
  130. package/dist/util-mCNUeboW.js.map +0 -1
  131. package/skills/agent-graphs/IMPROVE.md +0 -58
@@ -1,6 +1,4 @@
1
- import { I as awaitAbortable, J as sameControlCoordinates, X as promptFromAgentTurnInput, Z as promptOptionsFromAgentTurnInput, o as finalizeRuntimeOwnedPendingExecutor, r as attestRuntimeOwnedPendingExecutor, u as newExecutionAttemptId } from "./materialization-CekWK6OO.js";
2
- import { n as detachedSnapshot } from "./snapshot-CTAf4uuA.js";
3
- import { x as zeroTokenUsage } from "./util-mCNUeboW.js";
1
+ import { $ as promptOptionsFromAgentTurnInput, D as detachedSnapshot, Q as promptFromAgentTurnInput, R as awaitAbortable, X as sameControlCoordinates, o as finalizeRuntimeOwnedPendingExecutor, r as attestRuntimeOwnedPendingExecutor, u as newExecutionAttemptId } from "./materialization-vZssF9Nx.js";
4
2
  import { d as sandboxProgressEvents, f as sandboxTerminalUsageField, n as canonicalStreamEventFromSandboxEvent, o as isSandboxTerminalEvent, r as createSandboxToolPartState } from "./sandbox-events-DWeQRWxg.js";
5
3
  import { a as concreteProfileModel, c as profileModelExecutionSettings, o as enforceTokenLimits } from "./model-policy-Wf2MxXJ9.js";
6
4
  import { AgentExactRunControlRefSchema, AgentInteractiveSessionRefSchema, AgentInteractiveSessionStartSchema, AgentRunCancellationRequestSchema, WorkspaceRequestSchema, agentInteractiveSessionRefMatchesStart, canonicalCandidateDigest, canonicalWorkspaceCwd, harnessSystemPromptIntents, workspaceCwdPathForBase } from "@tangle-network/agent-interface";
@@ -33,7 +31,7 @@ function abortReason(signal, fallback) {
33
31
  return fallback;
34
32
  }
35
33
  /** An `AbortError` carrying the signal's own string reason, or `fallback` when it states none. */
36
- function abortError(signal, fallback) {
34
+ function abortError$1(signal, fallback) {
37
35
  const reason = abortReason(signal, fallback);
38
36
  const error = new Error(typeof reason === "string" && reason.length > 0 ? reason : fallback);
39
37
  error.name = "AbortError";
@@ -95,7 +93,7 @@ function linkAbort(...sources) {
95
93
  * A synchronous throw from `act()` propagates as the rejection, not as an abort.
96
94
  */
97
95
  async function runAbortable(act, signal, fallback) {
98
- if (signal.aborted) throw abortError(signal, fallback);
96
+ if (signal.aborted) throw abortError$1(signal, fallback);
99
97
  return await new Promise((resolve, reject) => {
100
98
  let settled = false;
101
99
  const cleanup = () => signal.removeEventListener("abort", onAbort);
@@ -104,7 +102,7 @@ async function runAbortable(act, signal, fallback) {
104
102
  if (settled) return;
105
103
  settled = true;
106
104
  cleanup();
107
- reject(abortError(signal, fallback));
105
+ reject(abortError$1(signal, fallback));
108
106
  });
109
107
  };
110
108
  signal.addEventListener("abort", onAbort, { once: true });
@@ -130,6 +128,422 @@ async function runAbortable(act, signal, fallback) {
130
128
  });
131
129
  }
132
130
  //#endregion
131
+ //#region src/runtime/util.ts
132
+ /**
133
+ * Best-effort sandbox delete. Skips instances without a `delete` (test fakes);
134
+ * swallows errors (the platform reaps on expiry). Returns `false` when delete
135
+ * threw, `true` otherwise, so callers can surface a leak if they choose.
136
+ */
137
+ async function deleteBoxSafe(box) {
138
+ if (!box || typeof box.delete !== "function") return true;
139
+ try {
140
+ await box.delete();
141
+ return true;
142
+ } catch {
143
+ return false;
144
+ }
145
+ }
146
+ /** Short base36 id for trace correlation. Not cryptographic, not collision-free. */
147
+ function randomSuffix(len = 8) {
148
+ return Math.random().toString(36).slice(2, 2 + len);
149
+ }
150
+ /** Collision-resistant id for sandbox naming (find-by-name recovery must be unique). */
151
+ function randomUuid() {
152
+ return crypto.randomUUID();
153
+ }
154
+ /** Construct an AbortError. Downstream code pattern-matches on `err.name`. */
155
+ function abortError() {
156
+ const err = /* @__PURE__ */ new Error("aborted");
157
+ err.name = "AbortError";
158
+ return err;
159
+ }
160
+ /** Throw an AbortError. */
161
+ function throwAbort() {
162
+ throw abortError();
163
+ }
164
+ /** Throw if the signal is already aborted; otherwise no-op. */
165
+ function throwIfAborted$1(signal) {
166
+ if (signal?.aborted) throw abortError();
167
+ }
168
+ /** True for any error whose `name` is `AbortError` (the cross-kernel abort contract). */
169
+ function isAbortError(err) {
170
+ return err instanceof Error && err.name === "AbortError";
171
+ }
172
+ /**
173
+ * Sleep that resolves early on abort and always clears its timer so it never
174
+ * keeps the event loop alive. Resolves (does not reject) on abort — callers
175
+ * re-check the signal explicitly after the sleep.
176
+ */
177
+ function sleep(ms, signal) {
178
+ return new Promise((resolve) => {
179
+ if (signal?.aborted) {
180
+ resolve();
181
+ return;
182
+ }
183
+ let onAbort;
184
+ const timer = setTimeout(() => {
185
+ if (onAbort && signal) signal.removeEventListener("abort", onAbort);
186
+ resolve();
187
+ }, ms);
188
+ if (signal) {
189
+ onAbort = () => {
190
+ clearTimeout(timer);
191
+ resolve();
192
+ };
193
+ signal.addEventListener("abort", onAbort, { once: true });
194
+ }
195
+ });
196
+ }
197
+ /**
198
+ * Race a promise against a timeout. Resolves with the value if it settles in
199
+ * time, otherwise resolves with `undefined`. Always clears the timer.
200
+ */
201
+ function withTimeout(promise, ms) {
202
+ return new Promise((resolve) => {
203
+ const timer = setTimeout(() => resolve(void 0), ms);
204
+ promise.then((value) => {
205
+ clearTimeout(timer);
206
+ resolve(value);
207
+ }, () => {
208
+ clearTimeout(timer);
209
+ resolve(void 0);
210
+ });
211
+ });
212
+ }
213
+ /**
214
+ * `JSON.stringify` with a `String()` fallback on throw (cyclic / non-JSON).
215
+ * Strings pass through unstringified so a preview of a string output is the
216
+ * string itself, not a quoted re-encoding.
217
+ */
218
+ function stringifySafe(value, opts = {}) {
219
+ let s;
220
+ try {
221
+ if (typeof value === "string") s = value;
222
+ else s = (opts.pretty ? JSON.stringify(value, null, 2) : JSON.stringify(value)) ?? String(value);
223
+ } catch {
224
+ s = String(value);
225
+ }
226
+ if (opts.max !== void 0 && s.length > opts.max) return `${s.slice(0, opts.max)}…`;
227
+ return s;
228
+ }
229
+ /** A fresh zero token-usage accumulator. */
230
+ function zeroTokenUsage() {
231
+ return {
232
+ input: 0,
233
+ output: 0
234
+ };
235
+ }
236
+ /**
237
+ * Sum the catalog-priced part of a dollar total across spends, as a field to spread.
238
+ *
239
+ * Returns nothing when no input carried one. A fold of pure provider receipts must not gain a
240
+ * `usdEstimated: 0`, which would read as "this runtime checked and priced none" on a path that
241
+ * never prices at all.
242
+ */
243
+ function usdEstimatedOf(...spends) {
244
+ let total = 0;
245
+ let priced = false;
246
+ for (const spend of spends) {
247
+ if (spend.usdEstimated === void 0) continue;
248
+ priced = true;
249
+ total += spend.usdEstimated;
250
+ }
251
+ return priced ? { usdEstimated: total } : {};
252
+ }
253
+ /** A conserved spend with every channel at zero and no completeness claim on it. */
254
+ function zeroSpend() {
255
+ return {
256
+ iterations: 0,
257
+ tokens: zeroTokenUsage(),
258
+ usd: 0,
259
+ ms: 0
260
+ };
261
+ }
262
+ /**
263
+ * The spend of work that HAPPENED and reported no usage receipt.
264
+ *
265
+ * Not the same value as {@link zeroSpend} even though both carry `{0,0}` tokens and `$0`. A bare
266
+ * zero asserts a MEASUREMENT — "this ran and cost nothing" — and every consumer downstream reads it
267
+ * that way: the pool keeps reporting `readout().tokensKnown === true`, the journal totals stay
268
+ * clean, the OTEL span records a priced zero, and a caller's token-denominated ceiling can never
269
+ * fire no matter how much the work really burned. A ceiling that cannot fire is worse than no
270
+ * ceiling, because it reads as protection.
271
+ *
272
+ * `tokensKnown` is the marker the substrate already threads end to end for exactly this case
273
+ * (`budget.ts`, `otel-spans.ts`, `spawn-journal.ts`, `supervisor.ts`): the work is recorded, the
274
+ * zero is labelled a floor rather than a total, and every rollup that touches it reports its
275
+ * balance as a ceiling rather than a measurement. Use this — never a bare zero — whenever a runtime
276
+ * cannot see what its worker spent.
277
+ *
278
+ * The same rule applies to dollars. A dollar-capped run must refuse an executor whose billed spend
279
+ * is unknowable; `budgetExempt` does not authorize Runtime to relabel unknown spend as a measured
280
+ * zero. Callers that require dollar accounting must use a backend with a trusted billing receipt.
281
+ */
282
+ function unmeteredSpend(ms) {
283
+ return {
284
+ iterations: 0,
285
+ tokens: zeroTokenUsage(),
286
+ tokensKnown: false,
287
+ usd: 0,
288
+ usdKnown: false,
289
+ ms
290
+ };
291
+ }
292
+ /** Copy a conserved spend without dropping a completeness marker or the catalog-priced part. */
293
+ function cloneSpend(spend) {
294
+ return {
295
+ iterations: spend.iterations,
296
+ tokens: cloneTokenUsage(spend.tokens),
297
+ ...spend.tokensKnown === false ? { tokensKnown: false } : {},
298
+ usd: spend.usd,
299
+ ...spend.usdKnown === false ? { usdKnown: false } : {},
300
+ ...spend.usdEstimated !== void 0 ? { usdEstimated: spend.usdEstimated } : {},
301
+ ms: spend.ms,
302
+ ...boxMinutesOf(spend)
303
+ };
304
+ }
305
+ /**
306
+ * Sum two conserved spends per channel. Tokens and dollars never fold into each other, an
307
+ * incomplete input keeps the sum incomplete on that channel, and the catalog-priced part of the
308
+ * dollar total is summed separately so `usd - usdEstimated` still names what a provider billed.
309
+ */
310
+ function addSpend(a, b) {
311
+ const tokens = cloneTokenUsage(a.tokens);
312
+ addTokenUsage(tokens, b.tokens);
313
+ return {
314
+ iterations: a.iterations + b.iterations,
315
+ tokens,
316
+ ...a.tokensKnown === false || b.tokensKnown === false ? { tokensKnown: false } : {},
317
+ usd: a.usd + b.usd,
318
+ ...a.usdKnown === false || b.usdKnown === false ? { usdKnown: false } : {},
319
+ ...usdEstimatedOf(a, b),
320
+ ms: a.ms + b.ms,
321
+ ...boxMinutesOf(a, b),
322
+ ...tokensProvenanceOf(a, b)
323
+ };
324
+ }
325
+ /**
326
+ * Fold the token-provenance channel across spends, as a field to spread.
327
+ *
328
+ * Returns nothing when no contributor stated one, because ABSENT already means "the executor's own
329
+ * live stream", which is what every path reported before a harness store was readable. A
330
+ * contributor that stated one and a contributor that did not therefore disagree, and the sum is
331
+ * `'mixed'` — the honest answer for a tree whose spend came from two kinds of receipt.
332
+ */
333
+ function tokensProvenanceOf(...spends) {
334
+ let folded;
335
+ let sawStated = false;
336
+ for (const spend of spends) {
337
+ const stated = spend.tokensProvenance ?? "stream-receipt";
338
+ if (spend.tokensProvenance !== void 0) sawStated = true;
339
+ folded = folded === void 0 || folded === stated ? stated : "mixed";
340
+ }
341
+ return !sawStated || folded === void 0 || folded === "stream-receipt" ? {} : { tokensProvenance: folded };
342
+ }
343
+ /**
344
+ * Fold the platform box-time channel across spends, as a field to spread.
345
+ *
346
+ * Returns nothing when no input carried the channel, so a fold over router or cli-bridge work —
347
+ * which runs no box at all — never gains a `boxMinutesProvenance: 'uncaptured'` that would claim
348
+ * a box ran and went unmetered.
349
+ *
350
+ * Three rules, one per field:
351
+ * - `boxMinutes` sums the numbers that are present, and stays ABSENT when none is. A missing
352
+ * measurement never enters the sum as a zero.
353
+ * - `boxMinutesKnown` is sticky-false, like `tokensKnown`: one contributor that could not state
354
+ * its box time makes the whole sum a floor.
355
+ * - `boxMinutesProvenance` degrades. `'observed'` survives only when every contributor that
356
+ * carried a number was observed; one derived number makes the sum `'estimated'`; no number at
357
+ * all is `'uncaptured'`.
358
+ */
359
+ function boxMinutesOf(...spends) {
360
+ const present = spends.filter((spend) => spend.boxMinutesProvenance !== void 0);
361
+ if (present.length === 0) return {};
362
+ let minutes = 0;
363
+ let sawNumber = false;
364
+ let known = true;
365
+ let observedOnly = true;
366
+ for (const spend of present) {
367
+ if (typeof spend.boxMinutes === "number" && Number.isFinite(spend.boxMinutes)) {
368
+ minutes += spend.boxMinutes;
369
+ sawNumber = true;
370
+ if (spend.boxMinutesProvenance !== "observed") observedOnly = false;
371
+ }
372
+ if (spend.boxMinutesKnown !== true) known = false;
373
+ }
374
+ return {
375
+ ...sawNumber ? { boxMinutes: roundBoxMinutes(minutes) } : {},
376
+ boxMinutesKnown: known,
377
+ boxMinutesProvenance: sawNumber ? observedOnly ? "observed" : "estimated" : "uncaptured"
378
+ };
379
+ }
380
+ /**
381
+ * Box minutes at four decimals — a tenth of a second.
382
+ *
383
+ * Fine enough that a box alive for two seconds reports `0.0333` instead of a zero that would read
384
+ * as a measured free box, and coarse enough that summing floats does not print
385
+ * `1.5000000000000002`.
386
+ */
387
+ function roundBoxMinutes(minutes) {
388
+ return Number(minutes.toFixed(4));
389
+ }
390
+ /** Copy a token subtotal without dropping optional provider cache telemetry. */
391
+ function cloneTokenUsage(usage) {
392
+ const cacheBreakdownUnknown = usage.cacheBreakdownKnown === false || usage.input > 0 && !hasClassifiedCacheBreakdown(usage);
393
+ return {
394
+ input: usage.input,
395
+ output: usage.output,
396
+ ...usage.tokensKnown === false ? { tokensKnown: false } : {},
397
+ ...usage.freshInput !== void 0 ? { freshInput: usage.freshInput } : {},
398
+ ...usage.cacheRead !== void 0 ? { cacheRead: usage.cacheRead } : {},
399
+ ...usage.cacheWrite !== void 0 ? { cacheWrite: usage.cacheWrite } : {},
400
+ ...cacheBreakdownUnknown ? { cacheBreakdownKnown: false } : {}
401
+ };
402
+ }
403
+ /** True only when every positive prompt token has a consistent cache classification. */
404
+ function hasCompleteCacheBreakdown(usage) {
405
+ if (usage.cacheBreakdownKnown === false) return false;
406
+ return hasClassifiedCacheBreakdown(usage);
407
+ }
408
+ function hasClassifiedCacheBreakdown(usage) {
409
+ if (usage.input === 0) return true;
410
+ if (usage.freshInput === void 0 || usage.cacheRead === void 0 || usage.cacheWrite === void 0) return false;
411
+ return usage.freshInput + usage.cacheRead + usage.cacheWrite === usage.input;
412
+ }
413
+ /**
414
+ * The token charge for one observation: every token counted ONCE, at the moment it first enters
415
+ * the context — `input − cacheRead + output`.
416
+ *
417
+ * `input` is a rolled-up prompt total that re-counts a cached prefix on every turn that reads it,
418
+ * so charging `input` makes a 100K prefix read 40 times cost 4.1M for content authored once. A
419
+ * cache read is content that was already charged when it was written, so it is the one class the
420
+ * charge subtracts. Under a complete split the result is exactly `freshInput + cacheWrite`. No
421
+ * price weight is involved: this counts work, and money is a separate channel.
422
+ *
423
+ * The subtraction form is what makes the charge ADDITIVE. `input` and `cacheRead` both accumulate
424
+ * through `addTokenUsage`, so the charge on an aggregate equals the sum of the charges on the
425
+ * records that built it — including an aggregate that mixes classified and unclassified turns,
426
+ * where the unclassified remainder is charged in full and only the reported cache reads are
427
+ * credited. A form that read `freshInput + cacheWrite` directly loses that: one unclassified turn
428
+ * would drop the whole aggregate to `input + output` and over-charge every classified turn with it.
429
+ *
430
+ * The one arithmetic guarantee: a set of classes that does not FIT inside the prompt total it
431
+ * partitions credits nothing, so the charge is never below `output` and a class that overflows its
432
+ * own total buys no tokens. It is not a guarantee against a provider that reports a cache read it
433
+ * never served — that provider can under-report `input` just as easily, and the token channel is an
434
+ * accounting unit, not a trust boundary. Prompt tokens the provider left unclassified are charged
435
+ * in full, so a spend with no readable split charges an upper bound on newly-presented work rather
436
+ * than a measurement, and every caller that enforces a ceiling must report the difference
437
+ * (`BudgetPool` does it through `readout().cacheBreakdownKnown`).
438
+ */
439
+ function chargedTokens(usage) {
440
+ return usage.input - creditedCacheRead(usage) + usage.output;
441
+ }
442
+ /** `cacheRead` if the reported classes fit inside `input`, else nothing. */
443
+ function creditedCacheRead(usage) {
444
+ const { cacheRead } = usage;
445
+ if (cacheRead === void 0) return 0;
446
+ return classifiedTotal(usage, cacheRead) > usage.input ? 0 : cacheRead;
447
+ }
448
+ function classifiedTotal(usage, cacheRead) {
449
+ return (usage.freshInput ?? 0) + cacheRead + (usage.cacheWrite ?? 0);
450
+ }
451
+ /**
452
+ * Translate one provider prompt-cache report into the prompt token classes `addTokenUsage` folds
453
+ * and `chargedTokens` credits.
454
+ *
455
+ * The input is the open `promptCache` record an `llm_call` carries, keyed by the `PromptCacheUsage`
456
+ * vocabulary (`readTokens`, `writeTokens`). Providers report that vocabulary unevenly, and the
457
+ * three outcomes are different facts that must not collapse into one another:
458
+ *
459
+ * - **Nothing reported** — no classes and no marker. The caller's own unknown handling decides,
460
+ * because a provider that says nothing about caching has not said the split is unknowable.
461
+ * - **Read and write both reported, and fitting inside `input`** — a complete partition, so
462
+ * `freshInput` is the remainder and the split is known.
463
+ * - **One counter reported, or classes that overflow `input`** — the counters that ARE measured
464
+ * pass through and `cacheBreakdownKnown` is false. A read with no write counter (OpenAI reports
465
+ * no write) still credits the read it measured, while declaring the rest unclassified so the
466
+ * charge stays a declared upper bound. An overflowing claim buys nothing: it cannot be a
467
+ * partition of a total it exceeds.
468
+ *
469
+ * A counter the provider did not report stays absent. A zero would claim the provider measured no
470
+ * cache, which is a different fact from a provider that did not report.
471
+ */
472
+ function promptCacheTokenClasses(input, promptCache) {
473
+ if (promptCache === void 0) return {};
474
+ const read = tokenCount(promptCache.readTokens);
475
+ const write = tokenCount(promptCache.writeTokens);
476
+ if (read === void 0 && write === void 0) return {};
477
+ if (input === void 0 || (read ?? 0) + (write ?? 0) > input) return { cacheBreakdownKnown: false };
478
+ if (read !== void 0 && write !== void 0) return {
479
+ freshInput: input - read - write,
480
+ cacheRead: read,
481
+ cacheWrite: write
482
+ };
483
+ return {
484
+ ...read !== void 0 ? { cacheRead: read } : {},
485
+ ...write !== void 0 ? { cacheWrite: write } : {},
486
+ cacheBreakdownKnown: false
487
+ };
488
+ }
489
+ function tokenCount(value) {
490
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
491
+ }
492
+ /**
493
+ * Add the observed subtotal into `acc`; token and cache incompleteness are sticky.
494
+ *
495
+ * A delta whose classes do not FIT inside its own `input` contributes its prompt total and NO
496
+ * classes. Folding them in would hide the overflow: the accumulator's larger `input` can absorb a
497
+ * class total that overflowed the one delta that reported it, and `chargedTokens` would then credit
498
+ * at the aggregate a cache read it refuses at the record. That is the one way the charge could come
499
+ * out below the sum of the charges on the records that built it.
500
+ */
501
+ function addTokenUsage(acc, delta) {
502
+ acc.input += delta.input ?? 0;
503
+ acc.output += delta.output ?? 0;
504
+ if (delta.tokensKnown === false) acc.tokensKnown = false;
505
+ const input = delta.input ?? 0;
506
+ const fits = classifiedTotal(delta, delta.cacheRead ?? 0) <= input;
507
+ if (fits) {
508
+ if (delta.freshInput !== void 0) acc.freshInput = (acc.freshInput ?? 0) + delta.freshInput;
509
+ if (delta.cacheRead !== void 0) acc.cacheRead = (acc.cacheRead ?? 0) + delta.cacheRead;
510
+ if (delta.cacheWrite !== void 0) acc.cacheWrite = (acc.cacheWrite ?? 0) + delta.cacheWrite;
511
+ }
512
+ const classified = fits && delta.freshInput !== void 0 && delta.cacheRead !== void 0 && delta.cacheWrite !== void 0 && delta.freshInput + delta.cacheRead + delta.cacheWrite === input;
513
+ if (delta.cacheBreakdownKnown === false || input > 0 && !classified) acc.cacheBreakdownKnown = false;
514
+ }
515
+ /**
516
+ * Map `items` through `fn` with at most `limit` calls in flight at once,
517
+ * preserving input order in the result. On the first `fn` rejection no NEW
518
+ * items are picked up; already-in-flight calls are awaited, then the first
519
+ * error is rethrown. `limit` is clamped to ≥ 1.
520
+ *
521
+ * Used where a burst of provisioning (e.g. forking N child boxes) must respect
522
+ * the loop's concurrency bound instead of firing all N at once.
523
+ */
524
+ async function mapWithConcurrency(items, limit, fn) {
525
+ const bound = Math.max(1, Math.floor(limit));
526
+ const results = new Array(items.length);
527
+ let next = 0;
528
+ let failed = false;
529
+ const worker = async () => {
530
+ while (!failed) {
531
+ const i = next;
532
+ next += 1;
533
+ if (i >= items.length) return;
534
+ try {
535
+ results[i] = await fn(items[i], i);
536
+ } catch (err) {
537
+ failed = true;
538
+ throw err;
539
+ }
540
+ }
541
+ };
542
+ const workerCount = Math.min(bound, items.length);
543
+ await Promise.all(Array.from({ length: workerCount }, () => worker()));
544
+ return results;
545
+ }
546
+ //#endregion
133
547
  //#region src/runtime/tangle-sandbox-exact-process-provider.ts
134
548
  const exactProcessProviderMarker = "agent-runtime.exact-process-provider";
135
549
  const exactProcessEgressMarker = "agent-runtime.exact-process-egress";
@@ -1764,6 +2178,6 @@ function hasExec(box) {
1764
2178
  return typeof box.exec === "function";
1765
2179
  }
1766
2180
  //#endregion
1767
- export { sandboxClientAsProvider as a, linkAbort as c, resolveAgentEnvironmentProvider as i, runAbortable as l, providerAsExecutor as n, createTangleSandboxExactProcessProvider as o, providerAsSandboxClient as r, abortError as s, createAgentEnvironmentProviderRegistry as t };
2181
+ export { runAbortable as A, throwIfAborted$1 as C, zeroTokenUsage as D, zeroSpend as E, abortError$1 as O, throwAbort as S, withTimeout as T, randomSuffix as _, sandboxClientAsProvider as a, sleep as b, addTokenUsage as c, cloneTokenUsage as d, deleteBoxSafe as f, promptCacheTokenClasses as g, mapWithConcurrency as h, resolveAgentEnvironmentProvider as i, linkAbort as k, chargedTokens as l, isAbortError as m, providerAsExecutor as n, createTangleSandboxExactProcessProvider as o, hasCompleteCacheBreakdown as p, providerAsSandboxClient as r, addSpend as s, createAgentEnvironmentProviderRegistry as t, cloneSpend as u, randomUuid as v, unmeteredSpend as w, stringifySafe as x, roundBoxMinutes as y };
1768
2182
 
1769
- //# sourceMappingURL=environment-provider-DEwsolvi.js.map
2183
+ //# sourceMappingURL=environment-provider-Dr-wfnHg.js.map