@tangle-network/agent-runtime 0.197.1 → 0.198.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/README.md +1 -2
  2. package/dist/{activation-BxMZybuo.js → activation-CwdO0ml2.js} +2 -2
  3. package/dist/{activation-BxMZybuo.js.map → activation-CwdO0ml2.js.map} +1 -1
  4. package/dist/{improve-DZs0KXhK.d.ts → activation-DFRTurvU.d.ts} +99 -5
  5. package/dist/agent.d.ts +1 -1
  6. package/dist/agent.js +2 -2
  7. package/dist/candidate-execution/index.d.ts +370 -2
  8. package/dist/candidate-execution/index.js +828 -4
  9. package/dist/candidate-execution/index.js.map +1 -0
  10. package/dist/{coordination-driver-zkCrfEbS.js → coordination-driver-Cf638-6q.js} +2 -5
  11. package/dist/{coordination-driver-zkCrfEbS.js.map → coordination-driver-Cf638-6q.js.map} +1 -1
  12. package/dist/{delegate-DHeUYU5E.js → delegate-Bez07Dlh.js} +2 -2
  13. package/dist/{delegate-DHeUYU5E.js.map → delegate-Bez07Dlh.js.map} +1 -1
  14. package/dist/durable.d.ts +2 -2
  15. package/dist/durable.js +4 -5
  16. package/dist/durable.js.map +1 -1
  17. package/dist/{graph-51SJOEcw.js → graph-DBk3Unto.js} +3 -3
  18. package/dist/{graph-51SJOEcw.js.map → graph-DBk3Unto.js.map} +1 -1
  19. package/dist/{improvement-cycle-Tw5nYT5R.js → improvement-cycle-Bma8TJs-.js} +8 -10
  20. package/dist/{improvement-cycle-Tw5nYT5R.js.map → improvement-cycle-Bma8TJs-.js.map} +1 -1
  21. package/dist/{index-CYOJsxSg.d.ts → index-D8LWK3Ha.d.ts} +6 -7
  22. package/dist/index.d.ts +694 -16
  23. package/dist/index.js +1780 -17
  24. package/dist/index.js.map +1 -1
  25. package/dist/intelligence.d.ts +3 -7
  26. package/dist/intelligence.js +5 -6
  27. package/dist/intelligence.js.map +1 -1
  28. package/dist/kernel.d.ts +2 -5
  29. package/dist/kernel.js +8 -10
  30. package/dist/{loop-runner-bin-2LQSjRTB.js → loop-runner-bin-Bd3dHQuw.js} +3 -3
  31. package/dist/{loop-runner-bin-2LQSjRTB.js.map → loop-runner-bin-Bd3dHQuw.js.map} +1 -1
  32. package/dist/{loop-runner-bin-DwrSB04m.d.ts → loop-runner-bin-Bn-0o_4k.d.ts} +3 -3
  33. package/dist/loop-runner-bin.d.ts +1 -1
  34. package/dist/loop-runner-bin.js +1 -1
  35. package/dist/mcp/bin.js +3 -3
  36. package/dist/mcp/index.d.ts +2 -3
  37. package/dist/mcp/index.js +4 -5
  38. package/dist/mcp/index.js.map +1 -1
  39. package/dist/{prepare-DDGp0-rW.js → prepare-CAO1yXov.js} +2407 -2407
  40. package/dist/prepare-CAO1yXov.js.map +1 -0
  41. package/dist/{protected-model-port-DxFN8DLS.js → protected-model-port-B5avcRiQ.js} +2 -2
  42. package/dist/{protected-model-port-DxFN8DLS.js.map → protected-model-port-B5avcRiQ.js.map} +1 -1
  43. package/dist/{provision-supervisor-CpMMShE_.js → provision-supervisor-C97q5NN_.js} +3 -6
  44. package/dist/{provision-supervisor-CpMMShE_.js.map → provision-supervisor-C97q5NN_.js.map} +1 -1
  45. package/dist/{redact-Cbl2O-4N.js → redact-CVyxp2AU.js} +5232 -2525
  46. package/dist/redact-CVyxp2AU.js.map +1 -0
  47. package/dist/{runtime-BSFz2z7h.js → runtime-BrTBBSfC.js} +427 -23
  48. package/dist/runtime-BrTBBSfC.js.map +1 -0
  49. package/dist/{server-COXa19sp.js → server-CO4bvAwe.js} +4 -4
  50. package/dist/{server-COXa19sp.js.map → server-CO4bvAwe.js.map} +1 -1
  51. package/dist/{types-DFLZMaeh.d.ts → stream-agent-turn-CLOQr497.d.ts} +1986 -6
  52. package/dist/{structural-rollout-DPbZWgEm.js → structural-rollout-D__lmWXe.js} +1101 -8
  53. package/dist/structural-rollout-D__lmWXe.js.map +1 -0
  54. package/dist/{supervise-b93YUaka.js → supervise-KSe4JEcg.js} +3 -5
  55. package/dist/{supervise-b93YUaka.js.map → supervise-KSe4JEcg.js.map} +1 -1
  56. package/dist/testing.d.ts +2 -2
  57. package/dist/testing.js +13 -13
  58. package/dist/tui/index.d.ts +1 -1
  59. package/dist/tui/index.js +1 -1
  60. package/dist/{workspace-archive-Ybomp7AN.js → workspace-archive-BMOnloFf.js} +3 -3
  61. package/dist/{workspace-archive-Ybomp7AN.js.map → workspace-archive-BMOnloFf.js.map} +1 -1
  62. package/package.json +1 -28
  63. package/dist/activation-DyWB0K6E.d.ts +0 -98
  64. package/dist/authored-code-URmkdgjv.js +0 -37
  65. package/dist/authored-code-URmkdgjv.js.map +0 -1
  66. package/dist/candidate-execution-nvqVIMyS.js +0 -829
  67. package/dist/candidate-execution-nvqVIMyS.js.map +0 -1
  68. package/dist/conversation-BxJ0SIBM.js +0 -1363
  69. package/dist/conversation-BxJ0SIBM.js.map +0 -1
  70. package/dist/conversation.d.ts +0 -2
  71. package/dist/conversation.js +0 -2
  72. package/dist/environment-provider-1fKZh2zl.js +0 -2281
  73. package/dist/environment-provider-1fKZh2zl.js.map +0 -1
  74. package/dist/environment-provider-B-I2jlQy.d.ts +0 -143
  75. package/dist/environment-provider.d.ts +0 -2
  76. package/dist/environment-provider.js +0 -2
  77. package/dist/graph.d.ts +0 -753
  78. package/dist/graph.js +0 -2111
  79. package/dist/graph.js.map +0 -1
  80. package/dist/index-CUosKU4N.d.ts +0 -372
  81. package/dist/index-D9mb6fn2.d.ts +0 -691
  82. package/dist/index-ZnxSe6iK.d.ts +0 -138
  83. package/dist/jsonl-file-BEpaEYjT.js +0 -141
  84. package/dist/jsonl-file-BEpaEYjT.js.map +0 -1
  85. package/dist/knowledge-B_MsOtDG.js +0 -428
  86. package/dist/knowledge-B_MsOtDG.js.map +0 -1
  87. package/dist/knowledge.d.ts +0 -2
  88. package/dist/knowledge.js +0 -2
  89. package/dist/materialization-Cy0oM8tb.js +0 -672
  90. package/dist/materialization-Cy0oM8tb.js.map +0 -1
  91. package/dist/prepare-DDGp0-rW.js.map +0 -1
  92. package/dist/primeintellect/index.d.ts +0 -218
  93. package/dist/primeintellect/index.js +0 -739
  94. package/dist/primeintellect/index.js.map +0 -1
  95. package/dist/redact-Cbl2O-4N.js.map +0 -1
  96. package/dist/runtime-0xNaV6TJ.d.ts +0 -1699
  97. package/dist/runtime-BSFz2z7h.js.map +0 -1
  98. package/dist/stream-agent-turn-Dt5mZpc3.js +0 -1103
  99. package/dist/stream-agent-turn-Dt5mZpc3.js.map +0 -1
  100. package/dist/stream-agent-turn-urHpmO_Z.d.ts +0 -160
  101. package/dist/structural-rollout-DPbZWgEm.js.map +0 -1
@@ -1,11 +1,1104 @@
1
- import { n as streamAgentTurn, t as collectAgentTurn } from "./stream-agent-turn-Dt5mZpc3.js";
2
- import { a as executableAgentProfileSnapshot } from "./jsonl-file-BEpaEYjT.js";
3
- import { c as profileModelExecutionSettings, i as concreteModelId, o as enforceTokenLimits, t as assertExecutableAgentProfile } from "./model-policy-DKDyr-fc.js";
4
- import { Ht as InMemorySpawnJournal, Vt as InMemoryResultBlobStore, a as createSupervisor, h as withDriverExecutor, lt as createExecutor, mn as observedModelMatchesDeclared, ot as captureReusableExecutorConfig, ut as createExecutorRegistry } from "./redact-Cbl2O-4N.js";
5
- import { agentProfileSchema, canonicalAgentProfileDigest, canonicalCandidateDigest } from "@tangle-network/agent-interface";
6
- import { costForTokenPricing, makeProposalFinding } from "@tangle-network/agent-eval";
1
+ import { $r as executableAgentProfileSnapshot, Br as knownExecutionBindingReceipt, Kr as runtimeOwnedExecutorExecutionBinding, Lr as authoredProfileDigest, Qr as unknownMaterializationReceipt, Rt as InMemoryResultBlobStore, Vr as knownMaterializationReceipt, Yr as runtimeOwnedPendingExecutorMaterialization, Zr as unknownExecutionBindingReceipt, a as createSupervisor, ci as promptOptionsFromAgentTurnInput, f as withDriverExecutor, ii as readSandboxOutcome, li as providerMessageText, oi as awaitAbortable, ot as createExecutor, qr as runtimeOwnedExecutorMaterialization, ri as projectSandboxOutcome, rt as captureReusableExecutorConfig, si as promptFromAgentTurnInput, st as createExecutorRegistry, un as observedModelMatchesDeclared, zt as InMemorySpawnJournal } from "./redact-CVyxp2AU.js";
2
+ import { m as ValidationError, p as SessionMismatchError, r as BackendTransportError } from "./errors-DodWX-cb.js";
3
+ import { c as mapSandboxToolEvent, i as createSandboxUsageLedger, n as canonicalStreamEventFromSandboxEvent, o as isSandboxTerminalEvent, r as createSandboxToolPartState, s as mapSandboxEvent } from "./sandbox-events-DbC2WKKS.js";
4
+ import { c as profileModelExecutionSettings, i as concreteModelId, l as profileProviderModel, o as enforceTokenLimits, s as profileBridgeWireModel, t as assertExecutableAgentProfile } from "./model-policy-DKDyr-fc.js";
5
+ import { agentProfileSchema, canonicalAgentProfileDigest, canonicalCandidateDigest, renderInputPartsAsText } from "@tangle-network/agent-interface";
6
+ import { costForTokenPricing, makeProposalFinding, scoreKnowledgeReadiness } from "@tangle-network/agent-eval";
7
+ import { createAgentRunOutcomeTracker } from "@tangle-network/sandbox/runtime";
7
8
  import { randomBytes } from "node:crypto";
8
9
  import { assertProposalFindings } from "@tangle-network/agent-eval/analyst";
10
+ //#region src/sessions.ts
11
+ /**
12
+ *
13
+ * Session helpers + an in-memory `RuntimeSessionStore` implementation suitable
14
+ * for tests, scratch processes, and per-request scratch storage in serverless
15
+ * runtimes. Durable stores (D1, postgres, Durable Objects) implement the same
16
+ * interface from `./types`.
17
+ *
18
+ * @stable
19
+ */
20
+ /** @internal */
21
+ function newRuntimeSession(backend, requestedId, metadata) {
22
+ const now = nowIso();
23
+ return {
24
+ id: requestedId || crypto.randomUUID(),
25
+ backend,
26
+ status: "active",
27
+ createdAt: now,
28
+ updatedAt: now,
29
+ metadata
30
+ };
31
+ }
32
+ /** @internal */
33
+ function touchSession(session) {
34
+ return {
35
+ ...session,
36
+ updatedAt: nowIso()
37
+ };
38
+ }
39
+ /** @internal */
40
+ function nowIso() {
41
+ return (/* @__PURE__ */ new Date()).toISOString();
42
+ }
43
+ /** Start or resume one backend session and persist its current identity. @internal */
44
+ async function startOrResumeRuntimeSession(options) {
45
+ const existing = options.resume && options.sessionId ? await options.store?.get(options.sessionId) : void 0;
46
+ if (!existing) {
47
+ const input = resolveSessionInput(options.input);
48
+ const session = options.backend.start ? await options.backend.start(input, {
49
+ ...options.context,
50
+ requestedSessionId: options.sessionId
51
+ }) : newRuntimeSession(options.backend.kind, options.sessionId);
52
+ assertSessionBackend(session, options.backend.kind);
53
+ options.validateSession?.(session);
54
+ await options.store?.put(session);
55
+ return {
56
+ session,
57
+ input,
58
+ resumed: false
59
+ };
60
+ }
61
+ assertSessionBackend(existing, options.backend.kind);
62
+ const input = resolveSessionInput(options.backend.resume !== void 0 ? options.continuationInput ?? options.input : options.input);
63
+ const session = options.backend.resume ? await options.backend.resume(existing, input, options.context) : touchSession({
64
+ ...existing,
65
+ status: "active"
66
+ });
67
+ assertSessionBackend(session, options.backend.kind);
68
+ options.validateSession?.(session);
69
+ await options.store?.put(session);
70
+ return {
71
+ session,
72
+ input,
73
+ resumed: true
74
+ };
75
+ }
76
+ function resolveSessionInput(input) {
77
+ return typeof input === "function" ? input() : input;
78
+ }
79
+ function assertSessionBackend(session, backend) {
80
+ if (session.backend !== backend) throw new SessionMismatchError(session.backend, backend);
81
+ }
82
+ /** In-memory `RuntimeSessionStore` for single-process use and tests. @stable */
83
+ var InMemoryRuntimeSessionStore = class {
84
+ sessions = /* @__PURE__ */ new Map();
85
+ events = /* @__PURE__ */ new Map();
86
+ get(sessionId) {
87
+ return this.sessions.get(sessionId);
88
+ }
89
+ put(session) {
90
+ this.sessions.set(session.id, session);
91
+ }
92
+ appendEvent(sessionId, event) {
93
+ const existing = this.events.get(sessionId) ?? [];
94
+ existing.push(event);
95
+ this.events.set(sessionId, existing);
96
+ }
97
+ listEvents(sessionId) {
98
+ return [...this.events.get(sessionId) ?? []];
99
+ }
100
+ };
101
+ //#endregion
102
+ //#region src/backends.ts
103
+ /**
104
+ * Provider-neutral backend adapters for `runAgentTaskStream`.
105
+ *
106
+ * Model inference is deliberately absent. Paid model work enters the Runtime executor with an
107
+ * exact `AgentProfile`; these adapters only normalize a caller-owned iterable or sandbox stream.
108
+ *
109
+ * @stable
110
+ */
111
+ /** Wrap any custom async-iterable stream into a typed `AgentExecutionBackend`. @stable */
112
+ function createIterableBackend(options) {
113
+ return options;
114
+ }
115
+ /** Build an `AgentExecutionBackend` backed by a sandbox/sidecar `streamPrompt` call. @stable */
116
+ function createSandboxPromptBackend(options) {
117
+ const kind = options.kind ?? "sandbox";
118
+ return {
119
+ kind,
120
+ async start(input, context) {
121
+ const box = await options.getBox(input, context);
122
+ return newRuntimeSession(kind, options.getSessionId?.(box, input) ?? context.requestedSessionId, { resumable: true });
123
+ },
124
+ resume(session) {
125
+ return touchSession({
126
+ ...session,
127
+ status: "active"
128
+ });
129
+ },
130
+ async *stream(input, context) {
131
+ const box = await options.getBox(input, context);
132
+ const message = input.message ?? input.messages?.at(-1)?.content ?? providerMessageText(input.providerOptions) ?? context.task.intent;
133
+ for await (const event of options.streamPrompt(box, message, context)) {
134
+ const mapped = options.mapEvent?.(event, context) ?? mapCommonBackendEvent(event, context);
135
+ if (mapped) yield mapped;
136
+ }
137
+ }
138
+ };
139
+ }
140
+ /** @internal */
141
+ function normalizeBackendStreamEvent(event, task, session) {
142
+ if ("task" in event && event.task && "session" in event && event.session && "timestamp" in event && event.timestamp) return event;
143
+ return {
144
+ ...event,
145
+ task: "task" in event && event.task ? event.task : task,
146
+ session: "session" in event && event.session ? event.session : session,
147
+ timestamp: "timestamp" in event && event.timestamp ? event.timestamp : nowIso()
148
+ };
149
+ }
150
+ function mapCommonBackendEvent(event, context) {
151
+ if (!event || typeof event !== "object") return void 0;
152
+ const record = event;
153
+ const type = String(record.type ?? "");
154
+ const data = record.data && typeof record.data === "object" ? record.data : record;
155
+ if (type === "message.part.updated" || type === "text_delta" || type === "delta") {
156
+ const part = data.part;
157
+ const partText = part !== void 0 && typeof part === "object" && (part.type === "text" || part.type === void 0) ? stringValue(part.text) : void 0;
158
+ const text = stringValue(data.text) ?? stringValue(data.delta) ?? stringValue(record.text) ?? partText;
159
+ return text ? {
160
+ type: "text_delta",
161
+ task: context.task,
162
+ session: context.session,
163
+ text,
164
+ timestamp: nowIso()
165
+ } : void 0;
166
+ }
167
+ if (type === "reasoning_delta") {
168
+ const text = stringValue(data.text) ?? stringValue(record.text);
169
+ return text ? {
170
+ type: "reasoning_delta",
171
+ task: context.task,
172
+ session: context.session,
173
+ text,
174
+ timestamp: nowIso()
175
+ } : void 0;
176
+ }
177
+ if (type === "tool_call") return {
178
+ type: "tool_call",
179
+ task: context.task,
180
+ session: context.session,
181
+ toolName: stringValue(data.name) ?? stringValue(record.toolName) ?? "tool",
182
+ toolCallId: stringValue(data.id) ?? stringValue(record.toolCallId),
183
+ args: data.args ?? data.input ?? record.args,
184
+ timestamp: nowIso()
185
+ };
186
+ if (type === "tool_result") return {
187
+ type: "tool_result",
188
+ task: context.task,
189
+ session: context.session,
190
+ toolName: stringValue(data.name) ?? stringValue(record.toolName) ?? "tool",
191
+ toolCallId: stringValue(data.id) ?? stringValue(record.toolCallId),
192
+ result: data.result ?? data.output ?? record.result,
193
+ timestamp: nowIso()
194
+ };
195
+ if (type === "artifact") {
196
+ const artifactId = stringValue(data.artifactId) ?? stringValue(data.id) ?? stringValue(record.artifactId);
197
+ if (!artifactId) return void 0;
198
+ return {
199
+ type: "artifact",
200
+ task: context.task,
201
+ session: context.session,
202
+ artifactId,
203
+ name: stringValue(data.name) ?? stringValue(record.name),
204
+ mimeType: stringValue(data.mimeType) ?? stringValue(record.mimeType),
205
+ uri: stringValue(data.uri) ?? stringValue(record.uri),
206
+ content: stringValue(data.content) ?? stringValue(data.body) ?? stringValue(record.content),
207
+ metadata: data.metadata && typeof data.metadata === "object" ? data.metadata : void 0,
208
+ timestamp: nowIso()
209
+ };
210
+ }
211
+ if (type === "proposal_created" || type === "proposal" || type === "filing") {
212
+ const proposalId = stringValue(data.proposalId) ?? stringValue(data.id) ?? stringValue(record.proposalId);
213
+ if (!proposalId) return void 0;
214
+ const status = stringValue(data.status) ?? stringValue(record.status);
215
+ return {
216
+ type: "proposal_created",
217
+ task: context.task,
218
+ session: context.session,
219
+ proposalId,
220
+ title: stringValue(data.title) ?? stringValue(record.title) ?? proposalId,
221
+ status: status === "pending" || status === "approved" || status === "rejected" ? status : void 0,
222
+ content: stringValue(data.content) ?? stringValue(data.body) ?? stringValue(record.content),
223
+ timestamp: nowIso()
224
+ };
225
+ }
226
+ if (type === "result" || type === "final") {
227
+ const text = stringValue(data.finalText) ?? stringValue(data.text) ?? stringValue(record.text);
228
+ return text ? {
229
+ type: "text_delta",
230
+ task: context.task,
231
+ session: context.session,
232
+ text,
233
+ timestamp: nowIso()
234
+ } : void 0;
235
+ }
236
+ }
237
+ function stringValue(value) {
238
+ return typeof value === "string" && value.length > 0 ? value : void 0;
239
+ }
240
+ //#endregion
241
+ //#region src/runtime/stream-agent-turn.ts
242
+ /**
243
+ * `streamAgentTurn` — the ONE run-a-turn event-stream contract over every
244
+ * execution substrate: a sandbox box (`SandboxInstance.streamPrompt`), a
245
+ * one-shot Runtime-owned `Executor` (cli-bridge / router / sandbox, via
246
+ * `ExecutorFactory`), and an in-process `AgentExecutionBackend`.
247
+ *
248
+ * One function, one vocabulary: every backend kind yields the existing
249
+ * `RuntimeStreamEvent` union incrementally and ALWAYS terminates with a
250
+ * `final` event whose `text` is the turn's final text and whose
251
+ * `metadata.tokenUsage` / `metadata.costUsd` / `metadata.model` carry the
252
+ * turn's metered usage. `collectAgentTurn` drains a stream into that terminal
253
+ * summary plus the full event list.
254
+ *
255
+ * This is a UNIFICATION seam, not a new stream parser — each kind is a thin
256
+ * adapter over code that already exists and is already hardened:
257
+ * - `box` — `mapSandboxEvent` projects the sandbox event stream and one
258
+ * `SandboxUsageLedger` (sandbox-events.ts) meters it, so a harness
259
+ * that reports usage only in its own event is counted once per turn;
260
+ * its requested profile is explicitly recorded as unverified because
261
+ * the box already exists.
262
+ * - `executor` — Runtime materializes the exact `AgentProfile`, records its
263
+ * identity receipts, drives the executor once, and tears it
264
+ * down after capturing the terminal artifact.
265
+ * - `chat` — the backend's own `stream()` surface, normalized by
266
+ * `normalizeBackendStreamEvent`; its requested profile is likewise
267
+ * unverified because an arbitrary backend cannot attest its setup.
268
+ *
269
+ * Distinct from `openSandboxRun` (box-only, session resume over one persistent
270
+ * artifact, raw `SandboxEvent` deliverables) and from `runAgentTaskStream`
271
+ * (full task lifecycle: knowledge preflight, session store, resume). This is
272
+ * the minimal turn primitive underneath both worlds: prompt in, one normalized
273
+ * event stream out, terminal result+usage guaranteed on every non-thrown path.
274
+ *
275
+ * Stream envelope: `backend_start` → incremental events → (`backend_error` on
276
+ * failure) → `final`. A caller-initiated abort terminates with
277
+ * `final.status: 'aborted'`; an expired `timeoutMs` deadline with
278
+ * `final.status: 'failed'` — so cancellation stays distinguishable from a
279
+ * blown deadline.
280
+ *
281
+ * Mid-stream lifecycle work needs NO extra API: the generator is pull-based,
282
+ * so the producer is suspended between yields and resumes only when the caller
283
+ * pulls again. A consumer can therefore run arbitrary async work between
284
+ * events — sync state on each `tool_result`, decide a no-op retry after
285
+ * draining, run a pre-`done` flush when it receives `final` and BEFORE it
286
+ * forwards its own terminal event downstream. The interleaving is guaranteed
287
+ * (and locked by test): nothing is produced past the event the caller is
288
+ * holding.
289
+ *
290
+ * @stable
291
+ */
292
+ function turnIntent(input) {
293
+ if (input.prompt !== void 0) return input.prompt;
294
+ if (input.parts !== void 0) return renderInputPartsAsText(input.parts);
295
+ return providerMessageText(input.providerOptions) ?? "structured agent turn";
296
+ }
297
+ function turnBackendInput(task, input) {
298
+ return {
299
+ task,
300
+ ...input.prompt === void 0 ? {} : { message: input.prompt },
301
+ ...input.parts === void 0 ? {} : { parts: structuredClone(input.parts) },
302
+ ...input.interactions === void 0 ? {} : { interactions: input.interactions },
303
+ ...input.providerOptions === void 0 ? {} : { providerOptions: structuredClone(input.providerOptions) }
304
+ };
305
+ }
306
+ function executorEvidence(executor, profile, attemptId) {
307
+ const profileDigest = authoredProfileDigest(profile);
308
+ const declaration = runtimeOwnedExecutorMaterialization(executor);
309
+ if (!profileDigest || !declaration) {
310
+ const materialization = unknownMaterializationReceipt({
311
+ ...profileDigest ? { authoredProfileDigest: profileDigest } : {},
312
+ runtime: executor.runtime,
313
+ reason: declaration ? "invalid-executor-report" : "executor-did-not-report"
314
+ });
315
+ return {
316
+ materialization,
317
+ executionBinding: unknownExecutionBindingReceipt(materialization, attemptId, declaration ? "invalid-executor-report" : "executor-did-not-report")
318
+ };
319
+ }
320
+ try {
321
+ const materialization = knownMaterializationReceipt({
322
+ authoredProfileDigest: profileDigest,
323
+ runtime: executor.runtime,
324
+ declaration
325
+ });
326
+ const binding = runtimeOwnedExecutorExecutionBinding(executor);
327
+ if (!binding || binding.attemptId !== attemptId) throw new Error("executor attempt id mismatch");
328
+ return {
329
+ materialization,
330
+ executionBinding: knownExecutionBindingReceipt(materialization, binding)
331
+ };
332
+ } catch {
333
+ const materialization = unknownMaterializationReceipt({
334
+ authoredProfileDigest: profileDigest,
335
+ runtime: executor.runtime,
336
+ reason: "invalid-executor-report"
337
+ });
338
+ return {
339
+ materialization,
340
+ executionBinding: unknownExecutionBindingReceipt(materialization, attemptId, "invalid-executor-report")
341
+ };
342
+ }
343
+ }
344
+ /** Exact turns require the model-bearing profile to be the sole behavioral authority. Runtime
345
+ * checks the trusted declaration before execution so a seam fallback cannot hide behind the same
346
+ * profile digest. */
347
+ function assertExactExecutorDeclaration(executor, profile) {
348
+ const profileModel = profileProviderModel(profile);
349
+ if (!profileModel) throw new ValidationError("streamAgentTurn: exact AgentProfile.model.default must name the concrete model");
350
+ const declaration = runtimeOwnedExecutorMaterialization(executor) ?? runtimeOwnedPendingExecutorMaterialization(executor)?.declaration;
351
+ if (!declaration) return;
352
+ if (declaration.model.status !== "known") throw new ValidationError("streamAgentTurn: exact executor did not materialize a known model identity");
353
+ if (declaration.backend === "router" || declaration.backend === "router-tools") {
354
+ const plan = declaration.plan;
355
+ if (declaration.model.id !== profileModel) throw new ValidationError("streamAgentTurn: Router executor model differs from AgentProfile.model.default");
356
+ if (plan.configuredModel !== null && plan.configuredModel !== void 0 && concreteModelId(String(plan.configuredModel)) !== profileModel) throw new ValidationError("streamAgentTurn: configured Router model conflicts with AgentProfile.model.default");
357
+ const expectedEffort = profile.model?.reasoningEffort ?? null;
358
+ if (plan.configuredReasoningEffort !== null && plan.configuredReasoningEffort !== void 0 && plan.configuredReasoningEffort !== expectedEffort) throw new ValidationError("streamAgentTurn: configured Router reasoning conflicts with AgentProfile.model.reasoningEffort");
359
+ if ((plan.reasoningEffort ?? null) !== expectedEffort) throw new ValidationError("streamAgentTurn: Router reasoning effort must come from AgentProfile.model.reasoningEffort");
360
+ }
361
+ if (declaration.backend === "bridge" || declaration.backend === "bridge-worktree") {
362
+ const expectedWireModel = profileBridgeWireModel(profile);
363
+ if (!expectedWireModel || declaration.model.id !== expectedWireModel) throw new ValidationError("streamAgentTurn: bridge executor model differs from the AgentProfile harness/provider/model wire id");
364
+ const plan = declaration.plan;
365
+ if (plan.configuredModel !== null && plan.configuredModel !== void 0 && concreteModelId(String(plan.configuredModel)) !== expectedWireModel) throw new ValidationError("streamAgentTurn: configured bridge model conflicts with the AgentProfile harness/provider/model wire id");
366
+ }
367
+ }
368
+ function turnProvenance(startedAt, timeoutMs, profileDigest, taskDigest, materialization, executionBinding, correlation) {
369
+ const endedAt = Date.now();
370
+ return {
371
+ ...profileDigest ? { identity: {
372
+ profileDigest,
373
+ taskDigest,
374
+ ...Object.keys(correlation).length > 0 ? { correlation } : {}
375
+ } } : { taskDigest },
376
+ ...materialization ? { materialization } : {},
377
+ ...executionBinding ? { executionBindings: [executionBinding] } : {},
378
+ budget: { timeoutMs: timeoutMs ?? null },
379
+ timing: {
380
+ startedAt: new Date(startedAt).toISOString(),
381
+ endedAt: new Date(endedAt).toISOString(),
382
+ durationMs: endedAt - startedAt
383
+ }
384
+ };
385
+ }
386
+ /**
387
+ * Run ONE agent turn on any backend kind and stream its events. Yields the
388
+ * `RuntimeStreamEvent` vocabulary incrementally and always ends with a `final`
389
+ * event carrying the turn's text and usage (`metadata.tokenUsage`,
390
+ * `metadata.costUsd?`, `metadata.model?`) — on success, failure, abort, and
391
+ * timeout alike. The generator never throws; failures surface in-band as
392
+ * `backend_error` + `final` with a typed `error` detail.
393
+ *
394
+ * @stable
395
+ */
396
+ async function* streamAgentTurn(backend, input, opts = {}) {
397
+ assertTurnTimeout(opts.timeoutMs);
398
+ if (backend.kind !== "executor") throw new ValidationError("streamAgentTurn: exact execution accepts only kind 'executor'; use Runtime-owned creation");
399
+ yield* streamAgentTurnInternal(backend, input, opts);
400
+ }
401
+ function assertTurnTimeout(timeoutMs) {
402
+ if (timeoutMs === void 0) return;
403
+ if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 2147483647) throw new ValidationError("streamAgentTurn: timeoutMs must be an integer from 1 to 2147483647");
404
+ }
405
+ function assertTurnIdentity(value, field) {
406
+ if (value !== void 0 && (typeof value !== "string" || value.trim().length === 0)) throw new ValidationError(`streamAgentTurn: ${field} must be a non-empty string`);
407
+ }
408
+ async function* streamAgentTurnInternal(backend, input, opts) {
409
+ const label = backend.kind === "chat" ? backend.backend.kind : backend.kind;
410
+ const profile = backend.kind === "executor" ? executableAgentProfileSnapshot(backend.profile, "streamAgentTurn") : void 0;
411
+ const profileDigest = profile ? authoredProfileDigest(profile) : void 0;
412
+ assertTurnIdentity(opts.callId, "callId");
413
+ assertTurnIdentity(opts.correlationId, "correlationId");
414
+ const correlation = {
415
+ ...opts.callId ? { callId: opts.callId } : {},
416
+ ...opts.correlationId ? { correlationId: opts.correlationId } : {}
417
+ };
418
+ const taskDigest = canonicalCandidateDigest(input);
419
+ const task = {
420
+ id: `turn-${crypto.randomUUID()}`,
421
+ intent: turnIntent(input),
422
+ ...profileDigest ? { metadata: { identity: {
423
+ profileDigest,
424
+ taskDigest,
425
+ ...Object.keys(correlation).length > 0 ? { correlation } : {}
426
+ } } } : {}
427
+ };
428
+ const acc = {
429
+ deltaText: "",
430
+ input: 0,
431
+ output: 0,
432
+ costUsd: 0,
433
+ estimatedCostUsd: 0,
434
+ sawEstimatedCost: false,
435
+ promptCache: {},
436
+ tokensKnown: false,
437
+ usdKnown: false,
438
+ sawLlmCall: false,
439
+ sawTokenUsage: false,
440
+ sawCostUsage: false
441
+ };
442
+ const deadline = deriveTurnSignal(opts.signal, opts.timeoutMs ?? 0);
443
+ const startedAt = Date.now();
444
+ let session;
445
+ let executor;
446
+ let materialization;
447
+ let executionBinding;
448
+ try {
449
+ const nodeId = task.id;
450
+ const attemptId = `${nodeId}:attempt:${crypto.randomUUID()}`;
451
+ if (backend.kind === "executor") {
452
+ executor = backend.factory({
453
+ profile,
454
+ harness: null
455
+ }, {
456
+ signal: deadline.signal,
457
+ seams: {},
458
+ node: {
459
+ rootId: nodeId,
460
+ parentId: nodeId,
461
+ nodeId,
462
+ attemptId,
463
+ identity: {
464
+ profileDigest,
465
+ taskDigest,
466
+ ...Object.keys(correlation).length > 0 ? { correlation } : {}
467
+ }
468
+ }
469
+ });
470
+ assertExactExecutorDeclaration(executor, profile);
471
+ const pending = runtimeOwnedPendingExecutorMaterialization(executor);
472
+ if (pending !== void 0) {
473
+ if (pending.runtime !== executor.runtime || pending.binding.attemptId !== attemptId) throw new ValidationError("streamAgentTurn: pending executor did not bind the kernel-minted attempt");
474
+ if (authoredProfileDigest(pending.declaration.effectiveProfile) !== profileDigest) throw new ValidationError("streamAgentTurn: pending executor changed the authored AgentProfile before execution");
475
+ materialization = unknownMaterializationReceipt({
476
+ authoredProfileDigest: profileDigest,
477
+ runtime: executor.runtime,
478
+ reason: "executor-receipt-pending"
479
+ });
480
+ executionBinding = unknownExecutionBindingReceipt(materialization, attemptId, "executor-receipt-pending");
481
+ } else {
482
+ ({materialization, executionBinding} = executorEvidence(executor, profile, attemptId));
483
+ assertExactExecutorEvidence(materialization, executionBinding);
484
+ }
485
+ } else {
486
+ materialization = unknownMaterializationReceipt({
487
+ runtime: backend.kind === "box" ? "sandbox" : label,
488
+ reason: "executor-did-not-report"
489
+ });
490
+ executionBinding = unknownExecutionBindingReceipt(materialization, attemptId, "executor-did-not-report");
491
+ }
492
+ const startedSession = await awaitAbortable(Promise.resolve().then(() => startTurnSession(backend, task, input, deadline.signal, label)), deadline.signal);
493
+ session = startedSession;
494
+ yield {
495
+ type: "backend_start",
496
+ task,
497
+ session: startedSession,
498
+ backend: executor?.runtime ?? label,
499
+ metadata: {
500
+ ...profileDigest ? { identity: {
501
+ profileDigest,
502
+ taskDigest,
503
+ ...Object.keys(correlation).length > 0 ? { correlation } : {}
504
+ } } : { taskDigest },
505
+ ...materialization ? { materialization } : {},
506
+ ...executionBinding ? { executionBindings: [executionBinding] } : {},
507
+ budget: { timeoutMs: opts.timeoutMs ?? null },
508
+ timing: { startedAt: new Date(startedAt).toISOString() }
509
+ },
510
+ timestamp: nowIso()
511
+ };
512
+ const inner = backend.kind === "chat" ? driveChatTurn(backend.backend, task, startedSession, input, deadline.signal, acc) : backend.kind === "executor" ? driveExecutorTurn(executor, task, startedSession, input, deadline.signal, acc, materializedModel(materialization, profile)) : driveBoxTurn(backend.box, input, deadline.signal, backend.agentRunName ?? "agent", acc, {
513
+ ...backend.options ? { options: backend.options } : {},
514
+ preserveToolParts: opts.preserveToolParts === true,
515
+ ...opts.onRawEvent ? { onRawEvent: opts.onRawEvent } : {},
516
+ ...profile?.harness ? { harness: profile.harness } : {}
517
+ });
518
+ const seenChildTaskUpdates = /* @__PURE__ */ new Set();
519
+ for await (const event of abortableValues(inner, deadline.signal)) {
520
+ if (childTaskAlreadySeen(event, seenChildTaskUpdates)) {
521
+ throwIfAborted(deadline.signal);
522
+ continue;
523
+ }
524
+ yield event;
525
+ throwIfAborted(deadline.signal);
526
+ }
527
+ throwIfAborted(deadline.signal);
528
+ if (backend.kind === "executor") {
529
+ ({materialization, executionBinding} = executorEvidence(executor, profile, attemptId));
530
+ assertExactExecutorEvidence(materialization, executionBinding);
531
+ }
532
+ const terminalOutcome = acc.sandboxOutcome ? projectSandboxOutcome(acc.sandboxOutcome) : {
533
+ status: "completed",
534
+ reason: "turn completed"
535
+ };
536
+ yield buildFinalEvent(task, session, acc, terminalOutcome, turnProvenance(startedAt, opts.timeoutMs, profileDigest, taskDigest, materialization, executionBinding, correlation));
537
+ } catch (err) {
538
+ if (materialization?.status === "unknown" && materialization.reason === "executor-receipt-pending" && executionBinding?.status === "unknown") {
539
+ const terminal = unknownMaterializationReceipt({
540
+ ...materialization.authoredProfileDigest === void 0 ? {} : { authoredProfileDigest: materialization.authoredProfileDigest },
541
+ runtime: materialization.runtime,
542
+ reason: "executor-failed-before-receipt"
543
+ });
544
+ executionBinding = unknownExecutionBindingReceipt(terminal, executionBinding.attemptId, "executor-failed-before-receipt");
545
+ materialization = terminal;
546
+ }
547
+ const callerAborted = opts.signal?.aborted === true;
548
+ const sandboxProjection = acc.sandboxOutcome ? projectSandboxOutcome(acc.sandboxOutcome) : void 0;
549
+ const status = callerAborted ? "aborted" : sandboxProjection?.status ?? "failed";
550
+ const message = sandboxProjection?.reason ?? (err instanceof Error ? err.message : String(err));
551
+ const error = sandboxProjection?.error ?? (err instanceof BackendTransportError ? {
552
+ kind: "transport",
553
+ message,
554
+ status: err.status,
555
+ body: err.body
556
+ } : {
557
+ kind: "backend",
558
+ message
559
+ });
560
+ yield {
561
+ type: "backend_error",
562
+ task,
563
+ ...session ? { session } : {},
564
+ backend: label,
565
+ message,
566
+ recoverable: !callerAborted,
567
+ error,
568
+ timestamp: nowIso()
569
+ };
570
+ yield buildFinalEvent(task, session, acc, {
571
+ status,
572
+ reason: message,
573
+ error
574
+ }, turnProvenance(startedAt, opts.timeoutMs, profileDigest, taskDigest, materialization, executionBinding, correlation));
575
+ } finally {
576
+ if (executor) await awaitAbortable(Promise.resolve().then(() => executor.teardown("brutalKill")), deadline.signal).catch(() => void 0);
577
+ deadline.dispose();
578
+ }
579
+ }
580
+ function assertExactExecutorEvidence(materialization, executionBinding) {
581
+ if (materialization.status !== "known" || executionBinding.status !== "known") throw new ValidationError("streamAgentTurn: exact profile execution requires terminally validated Runtime materialization and execution binding evidence");
582
+ if (materialization.effectiveProfileDigest !== materialization.authoredProfileDigest) throw new ValidationError("streamAgentTurn: executor changed the authored AgentProfile; exact turn execution refuses profile overlays");
583
+ }
584
+ /**
585
+ * Drain a `streamAgentTurn` stream (or any `RuntimeStreamEvent` stream that
586
+ * honors its terminal contract) into the turn summary plus the full event
587
+ * list. Fail-loud: throws when the stream ends without a terminal `final`
588
+ * event — a stream that violates the contract must not read as an empty turn.
589
+ *
590
+ * @stable
591
+ */
592
+ async function collectAgentTurn(stream) {
593
+ const events = [];
594
+ for await (const event of stream) events.push(event);
595
+ const final = events.at(-1);
596
+ if (final?.type !== "final") throw new Error(`collectAgentTurn: stream ended without a terminal 'final' event (last: ${final ? final.type : "none"})`);
597
+ const metadata = final.metadata ?? {};
598
+ const resultMetadata = metadata.result && typeof metadata.result === "object" ? metadata.result : void 0;
599
+ const sandboxOutcome = metadata.sandboxOutcome && typeof metadata.sandboxOutcome === "object" ? metadata.sandboxOutcome : void 0;
600
+ const tokenUsage = metadata.tokenUsage && typeof metadata.tokenUsage === "object" ? metadata.tokenUsage : {};
601
+ const usage = {
602
+ input: finiteNumber(tokenUsage.input) ?? 0,
603
+ output: finiteNumber(tokenUsage.output) ?? 0,
604
+ ...metadata.tokensKnown === false ? { tokensKnown: false } : {}
605
+ };
606
+ const costUsd = finiteNumber(metadata.costUsd);
607
+ if (costUsd !== void 0) usage.costUsd = costUsd;
608
+ if (metadata.usdKnown === false) usage.usdKnown = false;
609
+ const estimatedCostUsd = finiteNumber(metadata.estimatedCostUsd);
610
+ if (estimatedCostUsd !== void 0) usage.estimatedCostUsd = estimatedCostUsd;
611
+ if (metadata.promptCache && typeof metadata.promptCache === "object") usage.promptCache = metadata.promptCache;
612
+ const reasoningTokens = finiteNumber(metadata.reasoningTokens);
613
+ if (reasoningTokens !== void 0) usage.reasoningTokens = reasoningTokens;
614
+ if (typeof metadata.model === "string" && metadata.model.length > 0) usage.model = metadata.model;
615
+ const transportAttempts = finiteNumber(metadata.transportAttempts);
616
+ const toolCalls = events.filter((event) => event.type === "tool_call").map((event) => ({
617
+ ...event.toolCallId ? { id: event.toolCallId } : {},
618
+ name: event.toolName,
619
+ arguments: typeof event.args === "string" ? event.args : JSON.stringify(event.args ?? {})
620
+ }));
621
+ return {
622
+ finalText: final.text ?? "",
623
+ ...resultMetadata && "output" in resultMetadata ? { output: resultMetadata.output } : {},
624
+ usage,
625
+ ...transportAttempts !== void 0 ? { transportAttempts } : {},
626
+ toolCalls,
627
+ events,
628
+ status: final.status,
629
+ ...final.error ? { error: final.error } : {},
630
+ ...sandboxOutcome ? { sandboxOutcome } : {}
631
+ };
632
+ }
633
+ /** Start the backend's session when it owns one (`chat` kind); mint a local
634
+ * correlation session otherwise. Box/executor turns carry no server session
635
+ * here — resume lives in `openSandboxRun`/`SandboxLineage`, not this primitive. */
636
+ async function startTurnSession(backend, task, input, signal, label) {
637
+ if (backend.kind === "chat" && backend.backend.start) return backend.backend.start(turnBackendInput(task, input), {
638
+ task,
639
+ knowledge: emptyReadiness(task),
640
+ signal
641
+ });
642
+ return newRuntimeSession(label);
643
+ }
644
+ /**
645
+ * One turn over a box: `box.streamPrompt` projected through the existing
646
+ * `mapSandboxEvent` (text/reasoning deltas +
647
+ * cost-bearing `llm_call`s), plus the opt-in `mapSandboxToolEvent` tool-part
648
+ * projection. Final text prefers the terminal
649
+ * `result`/`done`/`final` payload over concatenated deltas, because the
650
+ * sandbox `message.part.updated` fallback may carry running accumulations.
651
+ *
652
+ * Usage rides ONE {@link SandboxUsageLedger} for the turn — the same accounting the leaf kernel,
653
+ * the steerable session, and `sumSandboxUsage` use — so a harness that reports its tokens only
654
+ * inside its own event is metered here too, and a turn reporting both sources is charged once.
655
+ * The ledger settles when the stream ends AND on the error path, because a turn that failed
656
+ * mid-stream still spent what the harness already reported.
657
+ */
658
+ async function* driveBoxTurn(box, input, signal, agentRunName, acc, cfg) {
659
+ const callOptions = {
660
+ ...cfg.options ?? {},
661
+ signal
662
+ };
663
+ const stream = box.streamPrompt(promptFromAgentTurnInput(input), {
664
+ ...callOptions,
665
+ ...promptOptionsFromAgentTurnInput(input),
666
+ signal
667
+ });
668
+ const toolParts = cfg.preserveToolParts ? createSandboxToolPartState() : void 0;
669
+ const outcomeTracker = createAgentRunOutcomeTracker();
670
+ const usageLedger = createSandboxUsageLedger(cfg.harness);
671
+ try {
672
+ for await (const event of abortableValues(stream, signal)) {
673
+ outcomeTracker.observe(event);
674
+ if (cfg.onRawEvent) await awaitAbortable(Promise.resolve().then(() => cfg.onRawEvent(event)), signal);
675
+ const terminalText = terminalTextFromSandboxEvent(event);
676
+ if (terminalText !== void 0) acc.terminalText = terminalText;
677
+ const call = usageLedger.observe(event, agentRunName);
678
+ if (call) foldEvent(call, acc, agentRunName);
679
+ const canonical = canonicalStreamEventFromSandboxEvent(event);
680
+ if (canonical) {
681
+ yield canonical;
682
+ continue;
683
+ }
684
+ if (toolParts) for (const toolEvent of mapSandboxToolEvent(event, toolParts)) yield toolEvent;
685
+ const mapped = mapSandboxEvent(event, { agentRunName });
686
+ if (mapped) {
687
+ if (mapped.type !== "llm_call") foldEvent(mapped, acc, agentRunName);
688
+ yield mapped;
689
+ }
690
+ }
691
+ } catch (err) {
692
+ const aborted = usageLedger.settleTurn(agentRunName);
693
+ if (aborted) {
694
+ foldEvent(aborted, acc, agentRunName);
695
+ yield aborted;
696
+ }
697
+ throw err;
698
+ }
699
+ const settled = usageLedger.settleTurn(agentRunName);
700
+ if (settled) {
701
+ foldEvent(settled, acc, agentRunName);
702
+ yield settled;
703
+ }
704
+ acc.sandboxOutcome = outcomeTracker.finish();
705
+ const projection = projectSandboxOutcome(acc.sandboxOutcome);
706
+ if (projection.status === "failed") throw new Error(projection.reason);
707
+ }
708
+ /** One turn over an in-process backend: its own `stream()` surface, projected
709
+ * through the same `normalizeBackendStreamEvent` the task lifecycle applies. */
710
+ async function* driveChatTurn(backend, task, session, input, signal, acc) {
711
+ const backendInput = turnBackendInput(task, input);
712
+ const context = {
713
+ task,
714
+ knowledge: emptyReadiness(task),
715
+ session,
716
+ signal
717
+ };
718
+ for await (const raw of abortableValues(backend.stream(backendInput, context), signal)) {
719
+ const event = normalizeBackendStreamEvent(raw, task, session);
720
+ foldEvent(event, acc);
721
+ yield event;
722
+ }
723
+ }
724
+ async function* driveExecutorTurn(executor, task, session, input, signal, acc, declaredModel) {
725
+ const taskValue = executorTaskValue(input);
726
+ const run = executor.execute(taskValue, signal);
727
+ let result;
728
+ if (isAsyncIterable(run)) {
729
+ for await (const usage of abortableValues(run, signal)) {
730
+ if (usage.kind === "progress") {
731
+ const projected = executorProgressStreamEvent(usage.progress, task, session);
732
+ foldEvent(projected, acc);
733
+ yield projected;
734
+ throwIfAborted(signal);
735
+ continue;
736
+ }
737
+ foldUsageEvent(usage, acc);
738
+ throwIfAborted(signal);
739
+ }
740
+ result = executor.resultArtifact();
741
+ } else result = await awaitAbortable(run, signal);
742
+ acc.result = result;
743
+ acc.sandboxOutcome = readSandboxOutcome(result.out);
744
+ acc.terminalText = executorResultText(result.out);
745
+ acc.input = result.spent.tokens.input;
746
+ acc.output = result.spent.tokens.output;
747
+ acc.costUsd = result.spent.usd;
748
+ const estimatedCostUsd = executorResultEstimatedCost(result.out);
749
+ if (estimatedCostUsd !== void 0) {
750
+ acc.estimatedCostUsd = estimatedCostUsd;
751
+ acc.sawEstimatedCost = true;
752
+ }
753
+ Object.assign(acc.promptCache, executorResultPromptCache(result.out));
754
+ acc.reasoningTokens = executorResultReasoningTokens(result.out);
755
+ acc.tokensKnown = result.spent.tokensKnown !== false;
756
+ acc.usdKnown = result.spent.usdKnown !== false;
757
+ acc.sawLlmCall = true;
758
+ const model = executorResultModel(result.out);
759
+ if (model) acc.model = model;
760
+ acc.stopReason = executorResultStopReason(result.out);
761
+ acc.transportAttempts = executorResultTransportAttempts(result.out);
762
+ const latencyMs = result.spent.ms;
763
+ yield {
764
+ type: "llm_call",
765
+ task,
766
+ session,
767
+ model: model ?? declaredModel ?? executor.runtime,
768
+ ...acc.tokensKnown ? {
769
+ tokensIn: acc.input,
770
+ tokensOut: acc.output
771
+ } : {},
772
+ ...acc.usdKnown ? { costUsd: acc.costUsd } : {},
773
+ ...acc.tokensKnown ? {} : { tokensKnown: false },
774
+ ...acc.usdKnown ? {} : { usdKnown: false },
775
+ ...acc.sawEstimatedCost ? { estimatedCostUsd: acc.estimatedCostUsd } : {},
776
+ ...Object.keys(acc.promptCache).length > 0 ? { promptCache: acc.promptCache } : {},
777
+ latencyMs,
778
+ timestamp: nowIso()
779
+ };
780
+ for (const call of executorResultToolCalls(result.out)) yield {
781
+ type: "tool_call",
782
+ task,
783
+ session,
784
+ toolName: call.name,
785
+ ...call.id ? { toolCallId: call.id } : {},
786
+ args: call.arguments,
787
+ timestamp: nowIso()
788
+ };
789
+ yield {
790
+ type: "artifact",
791
+ task,
792
+ session,
793
+ artifactId: result.outRef,
794
+ name: "agent-turn-result",
795
+ metadata: {
796
+ spend: result.spent,
797
+ ...result.verdict ? { verdict: result.verdict } : {}
798
+ },
799
+ timestamp: nowIso()
800
+ };
801
+ if (acc.sandboxOutcome && projectSandboxOutcome(acc.sandboxOutcome).status === "failed") throw new Error(projectSandboxOutcome(acc.sandboxOutcome).reason);
802
+ }
803
+ function executorTaskValue(input) {
804
+ const messages = input.providerOptions?.messages;
805
+ if (Array.isArray(messages)) return { messages: structuredClone(messages) };
806
+ return {
807
+ ...input.prompt === void 0 ? {} : { prompt: input.prompt },
808
+ ...input.parts === void 0 ? {} : { parts: structuredClone(input.parts) },
809
+ ...input.interactions === void 0 ? {} : { interactions: input.interactions }
810
+ };
811
+ }
812
+ function isAsyncIterable(value) {
813
+ return typeof value === "object" && value !== null && Symbol.asyncIterator in value;
814
+ }
815
+ /**
816
+ * Pull one provider iterator under Runtime's deadline.
817
+ *
818
+ * Providers still receive the signal for native cancellation, but correctness
819
+ * does not depend on them observing it. A losing iterator is asked to close;
820
+ * its late rejection is observed and cannot delay the terminal Runtime event.
821
+ */
822
+ async function* abortableValues(source, signal) {
823
+ const iterator = source[Symbol.asyncIterator]();
824
+ let completed = false;
825
+ try {
826
+ for (;;) {
827
+ const next = await awaitAbortable(Promise.resolve().then(() => iterator.next()), signal);
828
+ if (next.done) {
829
+ completed = true;
830
+ return;
831
+ }
832
+ yield next.value;
833
+ }
834
+ } finally {
835
+ if (!completed) try {
836
+ Promise.resolve(iterator.return?.()).catch(() => void 0);
837
+ } catch {}
838
+ }
839
+ }
840
+ function executorResultText(value) {
841
+ if (typeof value === "string") return value;
842
+ if (!value || typeof value !== "object") return "";
843
+ const content = value.content;
844
+ return typeof content === "string" ? content : "";
845
+ }
846
+ function executorResultModel(value) {
847
+ if (!value || typeof value !== "object") return void 0;
848
+ const model = value.model;
849
+ return typeof model === "string" && model.length > 0 ? model : void 0;
850
+ }
851
+ function executorResultStopReason(value) {
852
+ if (!value || typeof value !== "object") return void 0;
853
+ const reason = value.finishReason;
854
+ return typeof reason === "string" && reason.length > 0 ? reason : void 0;
855
+ }
856
+ function executorResultTransportAttempts(value) {
857
+ if (!value || typeof value !== "object") return void 0;
858
+ const attempts = value.transportAttempts;
859
+ return typeof attempts === "number" && Number.isSafeInteger(attempts) && attempts > 0 ? attempts : void 0;
860
+ }
861
+ function executorResultEstimatedCost(value) {
862
+ if (!value || typeof value !== "object") return void 0;
863
+ return finiteNumber(value.estimatedCostUsd);
864
+ }
865
+ function executorResultPromptCache(value) {
866
+ if (!value || typeof value !== "object") return {};
867
+ const raw = value.promptCache;
868
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return {};
869
+ const cache = {};
870
+ for (const [key, entry] of Object.entries(raw)) if (typeof entry === "number" && Number.isFinite(entry) || typeof entry === "string") cache[key] = entry;
871
+ return cache;
872
+ }
873
+ function executorResultReasoningTokens(value) {
874
+ if (!value || typeof value !== "object") return void 0;
875
+ const count = value.reasoningTokens;
876
+ return Number.isSafeInteger(count) && count >= 0 ? count : void 0;
877
+ }
878
+ /**
879
+ * Read the terminal tool calls an executor artifact published. Every Runtime-owned executor
880
+ * reports `ExecutorToolCall[]`, so an artifact carrying any other shape is a defect in that
881
+ * executor rather than a turn without tool calls: refuse it instead of dropping the calls.
882
+ */
883
+ function executorResultToolCalls(value) {
884
+ if (!value || typeof value !== "object") return [];
885
+ const raw = value.toolCalls;
886
+ if (raw === void 0) return [];
887
+ if (!Array.isArray(raw)) throw new ValidationError(`streamAgentTurn: executor artifact toolCalls must be an ExecutorToolCall array, received ${typeof raw}`);
888
+ return raw.map((entry) => {
889
+ const call = entry && typeof entry === "object" ? entry : void 0;
890
+ if (!call || typeof call.name !== "string" || call.name.length === 0) throw new ValidationError("streamAgentTurn: executor artifact toolCalls entries require a non-empty name");
891
+ return {
892
+ ...typeof call.id === "string" ? { id: call.id } : {},
893
+ name: call.name,
894
+ arguments: typeof call.arguments === "string" ? call.arguments : JSON.stringify(call.arguments ?? {})
895
+ };
896
+ });
897
+ }
898
+ /** Project one executor progress event onto the public turn vocabulary. */
899
+ function executorProgressStreamEvent(progress, task, session) {
900
+ const timestamp = nowIso();
901
+ if (progress.kind === "text_delta") return {
902
+ type: "text_delta",
903
+ task,
904
+ session,
905
+ text: progress.text,
906
+ timestamp
907
+ };
908
+ if (progress.kind === "reasoning_delta") return {
909
+ type: "reasoning_delta",
910
+ task,
911
+ session,
912
+ text: progress.text,
913
+ timestamp
914
+ };
915
+ if (progress.kind === "tool_call") return {
916
+ type: "tool_call",
917
+ task,
918
+ session,
919
+ toolName: progress.toolName,
920
+ ...progress.toolCallId === void 0 ? {} : { toolCallId: progress.toolCallId },
921
+ ...progress.args === void 0 ? {} : { args: progress.args },
922
+ timestamp
923
+ };
924
+ if (progress.kind === "tool_result") return {
925
+ type: "tool_result",
926
+ task,
927
+ session,
928
+ toolName: progress.toolName,
929
+ ...progress.toolCallId === void 0 ? {} : { toolCallId: progress.toolCallId },
930
+ ...progress.result === void 0 ? {} : { result: progress.result },
931
+ timestamp
932
+ };
933
+ if (progress.kind === "child_task") return {
934
+ ...progress.event,
935
+ task,
936
+ session,
937
+ timestamp
938
+ };
939
+ return {
940
+ type: "interaction",
941
+ request: progress.request,
942
+ task,
943
+ session,
944
+ timestamp
945
+ };
946
+ }
947
+ /**
948
+ * Drop a child-task update this turn already published. The provider's `sourceEventId` names one
949
+ * exact update, so a reconnect or replay that repeats it must not add a second child.
950
+ */
951
+ function childTaskAlreadySeen(event, seen) {
952
+ if (event.type !== "child-task") return false;
953
+ if (seen.has(event.sourceEventId)) return true;
954
+ seen.add(event.sourceEventId);
955
+ return false;
956
+ }
957
+ /** Fold one normalized executor usage event into the turn accumulator. */
958
+ function foldUsageEvent(event, acc) {
959
+ if (event.kind === "tokens") {
960
+ const known = event.tokensKnown !== false;
961
+ acc.tokensKnown = acc.sawTokenUsage ? acc.tokensKnown && known : known;
962
+ acc.sawTokenUsage = true;
963
+ acc.input += event.input;
964
+ acc.output += event.output;
965
+ } else if (event.kind === "cost") {
966
+ const known = event.usdKnown;
967
+ acc.usdKnown = acc.sawCostUsage ? acc.usdKnown && known : known;
968
+ acc.sawCostUsage = true;
969
+ acc.costUsd += event.usd;
970
+ if (event.usdKnown === false && event.usdEstimated !== void 0) {
971
+ acc.estimatedCostUsd += event.usdEstimated;
972
+ acc.sawEstimatedCost = true;
973
+ }
974
+ }
975
+ if (event.kind === "tokens" || event.kind === "cost") acc.sawLlmCall = true;
976
+ }
977
+ /** Fold one normalized event into the turn accumulator (text + usage).
978
+ * `fallbackModelLabel` — a mapper-stamped run label to exclude from
979
+ * `usage.model` (it is not a backend-reported model). */
980
+ function foldEvent(event, acc, fallbackModelLabel) {
981
+ if (event.type === "text_delta") {
982
+ acc.deltaText += event.text;
983
+ return;
984
+ }
985
+ if (event.type === "llm_call") {
986
+ const tokensReported = event.tokensKnown !== false && event.tokensIn !== void 0 && event.tokensOut !== void 0;
987
+ const usdReported = event.usdKnown !== false && event.costUsd !== void 0;
988
+ if (!acc.sawLlmCall) {
989
+ acc.tokensKnown = tokensReported;
990
+ acc.usdKnown = usdReported;
991
+ acc.sawLlmCall = true;
992
+ } else {
993
+ acc.tokensKnown &&= tokensReported;
994
+ acc.usdKnown &&= usdReported;
995
+ }
996
+ acc.input += event.tokensIn ?? 0;
997
+ acc.output += event.tokensOut ?? 0;
998
+ acc.costUsd += event.costUsd ?? 0;
999
+ if (event.estimatedCostUsd !== void 0) {
1000
+ acc.estimatedCostUsd += event.estimatedCostUsd;
1001
+ acc.sawEstimatedCost = true;
1002
+ }
1003
+ if (event.promptCache) Object.assign(acc.promptCache, event.promptCache);
1004
+ if (event.model && event.model !== fallbackModelLabel) acc.model = event.model;
1005
+ }
1006
+ }
1007
+ /** Read the final text off a terminal sandbox event, when present. */
1008
+ function terminalTextFromSandboxEvent(event) {
1009
+ if (!event || typeof event !== "object") return void 0;
1010
+ if (!isSandboxTerminalEvent(String(event.type ?? ""))) return void 0;
1011
+ const data = event.data && typeof event.data === "object" ? event.data : {};
1012
+ for (const key of [
1013
+ "finalText",
1014
+ "text",
1015
+ "response",
1016
+ "content"
1017
+ ]) {
1018
+ const value = data[key];
1019
+ if (typeof value === "string") return value;
1020
+ }
1021
+ }
1022
+ function buildFinalEvent(task, session, acc, outcome, provenance) {
1023
+ const finalText = acc.terminalText ?? acc.deltaText;
1024
+ return {
1025
+ type: "final",
1026
+ task,
1027
+ ...session ? { session } : {},
1028
+ status: outcome.status,
1029
+ reason: outcome.status === "completed" ? acc.stopReason ?? outcome.reason : outcome.reason,
1030
+ ...finalText ? { text: finalText } : {},
1031
+ metadata: {
1032
+ tokenUsage: {
1033
+ input: acc.input,
1034
+ output: acc.output
1035
+ },
1036
+ ...acc.tokensKnown ? {} : { tokensKnown: false },
1037
+ ...acc.usdKnown ? { costUsd: acc.costUsd } : { usdKnown: false },
1038
+ ...acc.sawEstimatedCost ? { estimatedCostUsd: acc.estimatedCostUsd } : {},
1039
+ ...Object.keys(acc.promptCache).length > 0 ? { promptCache: acc.promptCache } : {},
1040
+ ...acc.reasoningTokens !== void 0 ? { reasoningTokens: acc.reasoningTokens } : {},
1041
+ ...acc.model ? { model: acc.model } : {},
1042
+ ...acc.stopReason ? { stopReason: acc.stopReason } : {},
1043
+ ...acc.transportAttempts !== void 0 ? { transportAttempts: acc.transportAttempts } : {},
1044
+ ...acc.sandboxOutcome ? {
1045
+ sandboxOutcome: acc.sandboxOutcome,
1046
+ verdict: projectSandboxOutcome(acc.sandboxOutcome).verdict
1047
+ } : {},
1048
+ ...acc.result ? { result: {
1049
+ outRef: acc.result.outRef,
1050
+ output: acc.result.out,
1051
+ ...acc.sandboxOutcome ? { verdict: projectSandboxOutcome(acc.sandboxOutcome).verdict } : acc.result.verdict ? { verdict: acc.result.verdict } : {},
1052
+ spent: acc.result.spent
1053
+ } } : acc.sandboxOutcome ? { result: { verdict: projectSandboxOutcome(acc.sandboxOutcome).verdict } } : {},
1054
+ ...provenance
1055
+ },
1056
+ ...outcome.error ? { error: outcome.error } : {},
1057
+ timestamp: nowIso()
1058
+ };
1059
+ }
1060
+ function materializedModel(receipt, profile) {
1061
+ if (receipt?.status === "known" && receipt.model.status === "known") return receipt.model.id;
1062
+ const fallback = profile.model?.default;
1063
+ return typeof fallback === "string" && fallback.length > 0 ? fallback : void 0;
1064
+ }
1065
+ /** Minimal ready-by-construction readiness report for a requirement-free turn. */
1066
+ function emptyReadiness(task) {
1067
+ return scoreKnowledgeReadiness({
1068
+ taskId: task.id,
1069
+ requirements: []
1070
+ });
1071
+ }
1072
+ function finiteNumber(value) {
1073
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
1074
+ }
1075
+ function throwIfAborted(signal) {
1076
+ if (!signal.aborted) return;
1077
+ throw signal.reason instanceof Error ? signal.reason : new Error(String(signal.reason));
1078
+ }
1079
+ /**
1080
+ * Derive the turn's effective abort signal: fires when EITHER the caller's
1081
+ * signal aborts OR the `timeoutMs` deadline elapses. `dispose()` clears the
1082
+ * timer so a finished turn never leaks a pending timeout. `timeoutMs <= 0`
1083
+ * disables the deadline. Node-portable (no `AbortSignal.any`, which needs
1084
+ * >=20.3 — the package floor is >=20).
1085
+ */
1086
+ function deriveTurnSignal(callerSignal, timeoutMs) {
1087
+ const controller = new AbortController();
1088
+ const timer = timeoutMs > 0 ? setTimeout(() => controller.abort(/* @__PURE__ */ new Error(`agent turn timed out after ${timeoutMs}ms`)), timeoutMs) : void 0;
1089
+ if (timer && typeof timer.unref === "function") timer.unref();
1090
+ const onCallerAbort = () => controller.abort(callerSignal?.reason ?? /* @__PURE__ */ new Error("agent turn aborted"));
1091
+ if (callerSignal) if (callerSignal.aborted) onCallerAbort();
1092
+ else callerSignal.addEventListener("abort", onCallerAbort, { once: true });
1093
+ return {
1094
+ signal: controller.signal,
1095
+ dispose: () => {
1096
+ if (timer) clearTimeout(timer);
1097
+ callerSignal?.removeEventListener("abort", onCallerAbort);
1098
+ }
1099
+ };
1100
+ }
1101
+ //#endregion
9
1102
  //#region src/improvement/optimizer-prompt.ts
10
1103
  /**
11
1104
  * The senior scientific-method optimizer doctrine — the ONE substantial prompt
@@ -1711,6 +2804,6 @@ function structuralRollout(config = {}) {
1711
2804
  });
1712
2805
  }
1713
2806
  //#endregion
1714
- export { observe as C, optimizerMethod as D, profileOptimizerModelCall as E, strategyAuthorMethod as O, defaultAnalystInstruction as S, profileChatClient as T, depthStrategy as _, defaultStructuralRolloutPolicy as a, sample as b, officialChecksFromMeta as c, selectBestIndex as d, structuralRollout as f, defineStrategy as g, breadthStrategy as h, defaultExtractCandidate as i, resolveEntrySymbol as l, adaptiveRefine as m, compareCheckOutcomes as n, filterAuthoredAsserts as o, visibleCheckScore as p, composeCheckSources as r, modelAuthoredChecks as s, canDisplace as t, sandboxCheckRunner as u, refine as v, renderReport as w, sampleThenRefine as x, runAgentic as y };
2807
+ export { streamAgentTurn as A, observe as C, optimizerMethod as D, profileOptimizerModelCall as E, newRuntimeSession as F, nowIso as I, startOrResumeRuntimeSession as L, createSandboxPromptBackend as M, normalizeBackendStreamEvent as N, strategyAuthorMethod as O, InMemoryRuntimeSessionStore as P, touchSession as R, defaultAnalystInstruction as S, profileChatClient as T, depthStrategy as _, defaultStructuralRolloutPolicy as a, sample as b, officialChecksFromMeta as c, selectBestIndex as d, structuralRollout as f, defineStrategy as g, breadthStrategy as h, defaultExtractCandidate as i, createIterableBackend as j, collectAgentTurn as k, resolveEntrySymbol as l, adaptiveRefine as m, compareCheckOutcomes as n, filterAuthoredAsserts as o, visibleCheckScore as p, composeCheckSources as r, modelAuthoredChecks as s, canDisplace as t, sandboxCheckRunner as u, refine as v, renderReport as w, sampleThenRefine as x, runAgentic as y };
1715
2808
 
1716
- //# sourceMappingURL=structural-rollout-DPbZWgEm.js.map
2809
+ //# sourceMappingURL=structural-rollout-D__lmWXe.js.map