@tangle-network/agent-runtime 0.143.0 → 0.153.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -0
- package/dist/{activation-mi8TgSLM.js → activation-Bbic0THc.js} +3 -3
- package/dist/{activation-mi8TgSLM.js.map → activation-Bbic0THc.js.map} +1 -1
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +3 -3
- package/dist/{analyst-loop-CvkmfhUB.js → analyst-loop-Bouu53-l.js} +2 -2
- package/dist/{analyst-loop-CvkmfhUB.js.map → analyst-loop-Bouu53-l.js.map} +1 -1
- package/dist/analyst-loop.js +1 -1
- package/dist/{authoring-DuyShLdw.js → authoring-CcVhJ1lP.js} +2 -2
- package/dist/{authoring-DuyShLdw.js.map → authoring-CcVhJ1lP.js.map} +1 -1
- package/dist/candidate-execution/index.js +4 -4
- package/dist/{candidate-execution-CD5PoNmC.js → candidate-execution-DYOB1juU.js} +4 -4
- package/dist/{candidate-execution-CD5PoNmC.js.map → candidate-execution-DYOB1juU.js.map} +1 -1
- package/dist/{conversation-1hNtDeMM.js → conversation-BHMwAiMo.js} +28 -13
- package/dist/{conversation-1hNtDeMM.js.map → conversation-BHMwAiMo.js.map} +1 -1
- package/dist/conversation.d.ts +1 -1
- package/dist/conversation.js +1 -1
- package/dist/durable.d.ts +102 -4
- package/dist/durable.js +259 -13
- package/dist/durable.js.map +1 -1
- package/dist/{environment-provider-DCBJ13VP.js → environment-provider-3eCszBEm.js} +218 -34
- package/dist/environment-provider-3eCszBEm.js.map +1 -0
- package/dist/{environment-provider-B8eZ85Ga.d.ts → environment-provider-DJG0yIYl.d.ts} +2 -2
- package/dist/environment-provider.d.ts +1 -1
- package/dist/environment-provider.js +1 -1
- package/dist/executable-spec-BUcUcEPk.js +73 -0
- package/dist/executable-spec-BUcUcEPk.js.map +1 -0
- package/dist/{graph-De_XEsfH.js → graph-CIh2HDmH.js} +4 -4
- package/dist/{graph-De_XEsfH.js.map → graph-CIh2HDmH.js.map} +1 -1
- package/dist/{improvement-cycle-Bi-Tf4QF.js → improvement-cycle-GCDSsTN6.js} +7 -7
- package/dist/{improvement-cycle-Bi-Tf4QF.js.map → improvement-cycle-GCDSsTN6.js.map} +1 -1
- package/dist/{index-C2caGomG.d.ts → index-DLn9WI-f.d.ts} +342 -505
- package/dist/{index-B8rKtH3U.d.ts → index-lMADJLfq.d.ts} +4 -4
- package/dist/{index-D4sLkOPY.d.ts → index-rxVSm9-z.d.ts} +6 -4
- package/dist/index.d.ts +7 -7
- package/dist/index.js +13 -13
- package/dist/intelligence.d.ts +4 -4
- package/dist/intelligence.js +6 -6
- package/dist/jsonl-file-CDfsCI5s.js +59 -0
- package/dist/jsonl-file-CDfsCI5s.js.map +1 -0
- package/dist/kernel.d.ts +6 -6
- package/dist/kernel.js +13 -13
- package/dist/{knowledge-CVE6Wk1i.js → knowledge-CaY53BW2.js} +10 -7
- package/dist/{knowledge-CVE6Wk1i.js.map → knowledge-CaY53BW2.js.map} +1 -1
- package/dist/knowledge.d.ts +1 -1
- package/dist/knowledge.js +1 -1
- package/dist/{loop-runner-bin-BoHdQqLm.d.ts → loop-runner-bin-BwPqxKhR.d.ts} +3 -3
- package/dist/{loop-runner-bin-DdaI1nLL.js → loop-runner-bin-Dw43kB_-.js} +4 -4
- package/dist/{loop-runner-bin-DdaI1nLL.js.map → loop-runner-bin-Dw43kB_-.js.map} +1 -1
- package/dist/loop-runner-bin.d.ts +1 -1
- package/dist/loop-runner-bin.js +1 -1
- package/dist/{materialization-P86EciBw.js → materialization-Dl9J8ek4.js} +279 -58
- package/dist/materialization-Dl9J8ek4.js.map +1 -0
- package/dist/mcp/bin.js +3 -3
- package/dist/mcp/index.d.ts +3 -3
- package/dist/mcp/index.js +6 -6
- package/dist/{model-policy-DgRJIJse.js → model-policy-Sw4ywhtL.js} +68 -6
- package/dist/model-policy-Sw4ywhtL.js.map +1 -0
- package/dist/{openai-tools-BiAWKjh6.js → openai-tools-C4XKuK4t.js} +2 -2
- package/dist/{openai-tools-BiAWKjh6.js.map → openai-tools-C4XKuK4t.js.map} +1 -1
- package/dist/{prepare-D3n7cA39.js → prepare-C5tI-H4o.js} +2 -2
- package/dist/{prepare-D3n7cA39.js.map → prepare-C5tI-H4o.js.map} +1 -1
- package/dist/primeintellect/index.d.ts +1 -1
- package/dist/profiles.js +1 -1
- package/dist/{protected-model-port-bq6bD9YX.js → protected-model-port-DHDKNeY7.js} +2 -2
- package/dist/{protected-model-port-bq6bD9YX.js.map → protected-model-port-DHDKNeY7.js.map} +1 -1
- package/dist/{redact-DexTuAiX.d.ts → redact-NAptmqKw.d.ts} +3 -3
- package/dist/{researcher-CiSY6Wzb.js → researcher-BMFFPwKb.js} +2 -2
- package/dist/{researcher-CiSY6Wzb.js.map → researcher-BMFFPwKb.js.map} +1 -1
- package/dist/{run-layout-Be_Z0dF8.js → run-layout-C2jgwsCq.js} +111 -6
- package/dist/run-layout-C2jgwsCq.js.map +1 -0
- package/dist/{runtime-BnqjbOGX.js → runtime--Jsq8JCC.js} +118 -97
- package/dist/runtime--Jsq8JCC.js.map +1 -0
- package/dist/{runtime-J6Toky8K.d.ts → runtime-B-5dp5Iz.d.ts} +214 -14
- package/dist/{sandbox-events-COwCWUVB.js → sandbox-events-BVjstFgb.js} +70 -3
- package/dist/sandbox-events-BVjstFgb.js.map +1 -0
- package/dist/{spawn-journal-D2HKUImC.js → spawn-journal-BLnveCRS.js} +34 -104
- package/dist/spawn-journal-BLnveCRS.js.map +1 -0
- package/dist/{stream-agent-turn-C1Vs_3B9.d.ts → stream-agent-turn-BGyszuPH.d.ts} +2 -2
- package/dist/{stream-agent-turn-CXRugSGO.js → stream-agent-turn-DYi8ymsU.js} +91 -16
- package/dist/stream-agent-turn-DYi8ymsU.js.map +1 -0
- package/dist/{structural-rollout-CJgj9YXH.js → structural-rollout-D7V-HgXJ.js} +30 -13
- package/dist/structural-rollout-D7V-HgXJ.js.map +1 -0
- package/dist/{supervise-hCgG6ROJ.js → supervise-k_8VOASb.js} +2499 -2171
- package/dist/supervise-k_8VOASb.js.map +1 -0
- package/dist/{supervisor-s8SfZYbW.js → supervisor-CMZsJ7Wn.js} +673 -446
- package/dist/supervisor-CMZsJ7Wn.js.map +1 -0
- package/dist/testing.d.ts +2 -2
- package/dist/testing.js +12 -12
- package/dist/{top-app-BMOSKK06.js → top-app-3rYfFPTW.js} +192 -147
- package/dist/top-app-3rYfFPTW.js.map +1 -0
- package/dist/tui/bin.js +1 -1
- package/dist/tui/index.d.ts +32 -5
- package/dist/tui/index.js +1 -1
- package/dist/{types-Df9vulGc.d.ts → types-BPQhQRrC.d.ts} +507 -10
- package/dist/{util-C1bv6yog.js → util-D6ZEuBMi.js} +71 -2
- package/dist/util-D6ZEuBMi.js.map +1 -0
- package/dist/{workspace-archive-C52LjkeN.js → workspace-archive-B9ui4rrR.js} +2 -2
- package/dist/{workspace-archive-C52LjkeN.js.map → workspace-archive-B9ui4rrR.js.map} +1 -1
- package/package.json +7 -7
- package/dist/environment-provider-DCBJ13VP.js.map +0 -1
- package/dist/materialization-P86EciBw.js.map +0 -1
- package/dist/model-policy-DgRJIJse.js.map +0 -1
- package/dist/retained-run-binding-Dp2e8xne.js +0 -268
- package/dist/retained-run-binding-Dp2e8xne.js.map +0 -1
- package/dist/run-layout-Be_Z0dF8.js.map +0 -1
- package/dist/runtime-BnqjbOGX.js.map +0 -1
- package/dist/sandbox-events-COwCWUVB.js.map +0 -1
- package/dist/spawn-journal-D2HKUImC.js.map +0 -1
- package/dist/stream-agent-turn-CXRugSGO.js.map +0 -1
- package/dist/structural-rollout-CJgj9YXH.js.map +0 -1
- package/dist/supervise-hCgG6ROJ.js.map +0 -1
- package/dist/supervisor-s8SfZYbW.js.map +0 -1
- package/dist/top-app-BMOSKK06.js.map +0 -1
- package/dist/util-C1bv6yog.js.map +0 -1
package/dist/durable.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ao as SuperviseOptions, lo as supervise, wo as SupervisorProfile } from "./index-DLn9WI-f.js";
|
|
2
2
|
import { l as RuntimeHooks, o as RuntimeHookEvent, r as RuntimeDecisionPoint } from "./runtime-hooks-Bj6wJHlH.js";
|
|
3
|
-
import {
|
|
3
|
+
import { A as ProviderModelExecutionEvidence, O as ProfileMaterializationReceipt, T as NodeId, Y as SpendGap, ct as WorkerTraceEvidence, o as ExecutionBindingReceipt, q as Spend } from "./types-BPQhQRrC.js";
|
|
4
4
|
//#region src/durable/chat-engine.d.ts
|
|
5
5
|
/**
|
|
6
6
|
* `handleChatTurn` is a framework-neutral chat-turn HTTP orchestrator.
|
|
@@ -198,6 +198,66 @@ declare function createFileObserverHooks(path: string, pursuitId: string): {
|
|
|
198
198
|
//#endregion
|
|
199
199
|
//#region src/durable/observer-projection.d.ts
|
|
200
200
|
type PursuitRunStatus = 'running' | 'done' | 'failed';
|
|
201
|
+
/**
|
|
202
|
+
* Where a node's dollar figure came from. `reported` = a provider billed all of it; `estimated` =
|
|
203
|
+
* a model catalog priced all of it; `partial` = a provider billed part and a catalog priced the
|
|
204
|
+
* rest; `unknown` = nothing priced it, so `usd` is a floor and never the cost.
|
|
205
|
+
*/
|
|
206
|
+
type PursuitCostProvenance = 'reported' | 'estimated' | 'partial' | 'unknown';
|
|
207
|
+
/**
|
|
208
|
+
* One node's token usage by class. Cache and reasoning classes are absent when the provider did
|
|
209
|
+
* not report them — absence is not zero. `tokensKnown` is `false` when work happened whose token
|
|
210
|
+
* count no provider reported, which makes `input`/`output` a floor.
|
|
211
|
+
*/
|
|
212
|
+
interface PursuitNodeUsage {
|
|
213
|
+
readonly input: number;
|
|
214
|
+
readonly output: number;
|
|
215
|
+
readonly cacheRead?: number;
|
|
216
|
+
readonly cacheWrite?: number;
|
|
217
|
+
readonly reasoning?: number;
|
|
218
|
+
readonly tokensKnown: boolean;
|
|
219
|
+
}
|
|
220
|
+
/** One node's dollar cost with the provenance that decides whether it may be compared or summed. */
|
|
221
|
+
interface PursuitNodeCost {
|
|
222
|
+
readonly usd: number;
|
|
223
|
+
readonly usdKnown: boolean;
|
|
224
|
+
/** The part of `usd` a model catalog priced because no provider receipt covered it. */
|
|
225
|
+
readonly usdEstimated?: number;
|
|
226
|
+
readonly provenance: PursuitCostProvenance;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* One node's clock. `wallMs` is `settledAt - startedAt` and is deliberately distinct from the
|
|
230
|
+
* executor-reported `spent.ms` sums, which under-report and overlap across parallel children.
|
|
231
|
+
* `firstTokenAt` stays absent unless a provider reports that instant; it is never inferred from
|
|
232
|
+
* `firstOutputAt`, which is when the node first reported usage for a turn.
|
|
233
|
+
*/
|
|
234
|
+
interface PursuitNodeTiming {
|
|
235
|
+
readonly startedAt: number;
|
|
236
|
+
readonly firstOutputAt?: number;
|
|
237
|
+
readonly firstTokenAt?: number;
|
|
238
|
+
readonly settledAt?: number;
|
|
239
|
+
readonly wallMs?: number;
|
|
240
|
+
}
|
|
241
|
+
/** Where and how a node's execution was placed, read off its execution-binding receipt. */
|
|
242
|
+
type PursuitNodePlacement = Readonly<Record<string, string | number | boolean | null>>;
|
|
243
|
+
/**
|
|
244
|
+
* One run's spend counted once, and each node's own share of it. `inclusive` and the entries of
|
|
245
|
+
* `exclusiveByNode` are the two views a client needs to show a tree without double counting.
|
|
246
|
+
*/
|
|
247
|
+
interface PursuitRunTotals {
|
|
248
|
+
/**
|
|
249
|
+
* The whole run counted once. A node's settled `spent` already contains the child work its own
|
|
250
|
+
* nested tree reported, so summing only the run's top-level nodes plus every node's own
|
|
251
|
+
* inference counts each model call exactly once.
|
|
252
|
+
*/
|
|
253
|
+
readonly inclusive: Spend;
|
|
254
|
+
/**
|
|
255
|
+
* Each node's own share: its reported spend and own inference minus what its direct children
|
|
256
|
+
* reported. Keyed by node id, plus the run root when the root itself metered inference. The
|
|
257
|
+
* entries sum to `inclusive` by construction.
|
|
258
|
+
*/
|
|
259
|
+
readonly exclusiveByNode: Readonly<Record<string, Spend>>;
|
|
260
|
+
}
|
|
201
261
|
interface PursuitRunProjection {
|
|
202
262
|
readonly runId: string;
|
|
203
263
|
readonly status: PursuitRunStatus;
|
|
@@ -211,6 +271,9 @@ interface PursuitRunProjection {
|
|
|
211
271
|
readonly decisionCount: number;
|
|
212
272
|
readonly targets: Readonly<Record<string, number>>;
|
|
213
273
|
readonly decisions: Readonly<Record<string, number>>;
|
|
274
|
+
readonly totals: PursuitRunTotals;
|
|
275
|
+
/** The nodes whose accounting is incomplete. Present exactly when non-empty. */
|
|
276
|
+
readonly spendGaps?: ReadonlyArray<SpendGap>;
|
|
214
277
|
}
|
|
215
278
|
type PursuitNodeStatus = 'running' | 'done' | 'down';
|
|
216
279
|
interface PursuitNodeProjection {
|
|
@@ -219,6 +282,7 @@ interface PursuitNodeProjection {
|
|
|
219
282
|
/** Node ids are scoped to this concrete Runtime tree; `(runId,id)` is identity. */
|
|
220
283
|
readonly runId: string;
|
|
221
284
|
readonly label?: string;
|
|
285
|
+
/** The runner that executed this node — the executor's own name, not a harness guess. */
|
|
222
286
|
readonly runtime?: string;
|
|
223
287
|
readonly depth?: number;
|
|
224
288
|
readonly assignmentId?: string;
|
|
@@ -226,18 +290,48 @@ interface PursuitNodeProjection {
|
|
|
226
290
|
readonly budget?: unknown;
|
|
227
291
|
readonly status: PursuitNodeStatus;
|
|
228
292
|
readonly settledAt?: number;
|
|
229
|
-
|
|
293
|
+
/** The child work this node reported at settlement. Absent until a terminal record lands. */
|
|
294
|
+
readonly spent?: Spend;
|
|
295
|
+
/** This node's OWN inference, re-homed from its nested tree. Absent when it drove no turns. */
|
|
296
|
+
readonly ownInference?: Spend;
|
|
297
|
+
/** Absent until a spend record lands; the run's `spendGaps` then names the node. */
|
|
298
|
+
readonly usage?: PursuitNodeUsage;
|
|
299
|
+
/** Absent until a spend record lands; the run's `spendGaps` then names the node. */
|
|
300
|
+
readonly cost?: PursuitNodeCost;
|
|
301
|
+
readonly timing?: PursuitNodeTiming;
|
|
302
|
+
/** The kernel-minted attempt this node's execution binding is keyed on. */
|
|
303
|
+
readonly attemptId?: string;
|
|
304
|
+
/** The runner-native execution the node bound to: a request, session, run, process, or tree. */
|
|
305
|
+
readonly execution?: {
|
|
306
|
+
readonly kind: string;
|
|
307
|
+
readonly id: string;
|
|
308
|
+
};
|
|
309
|
+
/** The model the materialization receipt names, when the runner reported one. */
|
|
310
|
+
readonly model?: string;
|
|
311
|
+
/** The concrete backend the profile materialized onto. */
|
|
312
|
+
readonly backend?: string;
|
|
313
|
+
readonly placement?: PursuitNodePlacement;
|
|
314
|
+
/** Model-call identifiers this node's own turns reported, in order, deduplicated. */
|
|
315
|
+
readonly modelCalls?: ReadonlyArray<string>;
|
|
316
|
+
readonly materialization?: ProfileMaterializationReceipt;
|
|
317
|
+
readonly executionBindings?: ReadonlyArray<ExecutionBindingReceipt>;
|
|
318
|
+
/** What the provider itself reported serving, and why it is unknown when it is. */
|
|
319
|
+
readonly providerModel?: ProviderModelExecutionEvidence;
|
|
320
|
+
/** Content-addressed pointer to this node's persisted tool trace, or why there is none. */
|
|
321
|
+
readonly trace?: WorkerTraceEvidence;
|
|
230
322
|
readonly outRef?: string;
|
|
231
323
|
readonly score?: number;
|
|
232
324
|
readonly valid?: boolean;
|
|
233
325
|
readonly reason?: string;
|
|
234
326
|
readonly infra?: boolean;
|
|
327
|
+
readonly restartCount?: number;
|
|
235
328
|
readonly wait?: unknown;
|
|
236
329
|
readonly firstSequence: number;
|
|
237
330
|
readonly lastSequence: number;
|
|
238
331
|
readonly firstObservedAt: number;
|
|
239
332
|
readonly lastObservedAt: number;
|
|
240
333
|
readonly eventCount: number;
|
|
334
|
+
readonly turnCount: number;
|
|
241
335
|
}
|
|
242
336
|
interface PursuitProjection {
|
|
243
337
|
readonly pursuitId: string;
|
|
@@ -264,6 +358,10 @@ interface PursuitProjection {
|
|
|
264
358
|
* state comes only from `agent.child`; concrete run state comes only from the root
|
|
265
359
|
* `agent.run` lifecycle emitted by `supervisePursuit`. Node identity is scoped to the
|
|
266
360
|
* concrete Runtime run so independent trees may both contain `root:s0` without aliasing.
|
|
361
|
+
*
|
|
362
|
+
* Usage, cost and timing are reported at the class the runtime measured them at. A missing
|
|
363
|
+
* class stays ABSENT and the run names the node in `spendGaps`; nothing here converts an
|
|
364
|
+
* unmeasured channel into a zero, because a fabricated zero is indistinguishable from free work.
|
|
267
365
|
*/
|
|
268
366
|
declare function projectPursuit(records: readonly ObserverRecord[]): PursuitProjection;
|
|
269
367
|
//#endregion
|
|
@@ -335,5 +433,5 @@ interface DurableSupervisionDiscovery {
|
|
|
335
433
|
*/
|
|
336
434
|
declare function discoverDurableSupervisionRun(runDir: string): Promise<DurableSupervisionDiscovery>;
|
|
337
435
|
//#endregion
|
|
338
|
-
export { type ChatStreamEvent, type ChatTurnHooks, type ChatTurnIdentity, type ChatTurnProducer, type ChatTurnResult, type DurableCoordinationStreamIdentity, type DurableSupervisionDiscovery, FileObserverJournal, type ObserverJournal, type ObserverRecord, type ObserverRecordKind, type PursuitNodeProjection, type PursuitNodeStatus, type PursuitProjection, type PursuitRunProjection, type PursuitRunStatus, type RunChatTurnInput, SupervisePursuitError, type SupervisePursuitOptions, type SupervisedPursuitResult, createFileObserverHooks, deriveExecutionId, discoverDurableSupervisionRun, handleChatTurn, observerRecordDigest, projectPursuit, supervisePursuit, verifyObserverRecords };
|
|
436
|
+
export { type ChatStreamEvent, type ChatTurnHooks, type ChatTurnIdentity, type ChatTurnProducer, type ChatTurnResult, type DurableCoordinationStreamIdentity, type DurableSupervisionDiscovery, FileObserverJournal, type ObserverJournal, type ObserverRecord, type ObserverRecordKind, type PursuitCostProvenance, type PursuitNodeCost, type PursuitNodePlacement, type PursuitNodeProjection, type PursuitNodeStatus, type PursuitNodeTiming, type PursuitNodeUsage, type PursuitProjection, type PursuitRunProjection, type PursuitRunStatus, type PursuitRunTotals, type RunChatTurnInput, SupervisePursuitError, type SupervisePursuitOptions, type SupervisedPursuitResult, createFileObserverHooks, deriveExecutionId, discoverDurableSupervisionRun, handleChatTurn, observerRecordDigest, projectPursuit, supervisePursuit, verifyObserverRecords };
|
|
339
437
|
//# sourceMappingURL=durable.d.ts.map
|
package/dist/durable.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as cloneSpend, t as addSpend, y as zeroSpend } from "./util-D6ZEuBMi.js";
|
|
2
|
+
import { i as writeAllBytes, n as parseCommittedJsonLines, r as prepareJsonlAppend, t as isNoEntError } from "./jsonl-file-CDfsCI5s.js";
|
|
2
3
|
import { a as withPursuitContext, t as composeRuntimeHooks } from "./runtime-hooks-tXpAarhW.js";
|
|
3
|
-
import { n as supervise } from "./supervise-
|
|
4
|
+
import { n as supervise } from "./supervise-k_8VOASb.js";
|
|
4
5
|
import { createHash } from "node:crypto";
|
|
5
6
|
import { resolve } from "node:path";
|
|
6
7
|
import { readFile } from "node:fs/promises";
|
|
@@ -301,6 +302,10 @@ function toError(error) {
|
|
|
301
302
|
* state comes only from `agent.child`; concrete run state comes only from the root
|
|
302
303
|
* `agent.run` lifecycle emitted by `supervisePursuit`. Node identity is scoped to the
|
|
303
304
|
* concrete Runtime run so independent trees may both contain `root:s0` without aliasing.
|
|
305
|
+
*
|
|
306
|
+
* Usage, cost and timing are reported at the class the runtime measured them at. A missing
|
|
307
|
+
* class stays ABSENT and the run names the node in `spendGaps`; nothing here converts an
|
|
308
|
+
* unmeasured channel into a zero, because a fabricated zero is indistinguishable from free work.
|
|
304
309
|
*/
|
|
305
310
|
function projectPursuit(records) {
|
|
306
311
|
if (records.length === 0) throw new TypeError("projectPursuit: at least one observer record is required");
|
|
@@ -323,12 +328,19 @@ function projectPursuit(records) {
|
|
|
323
328
|
projectRunActivity(run, record);
|
|
324
329
|
projectSpawnNode(nodes, record);
|
|
325
330
|
projectNodeActivity(nodes, record);
|
|
331
|
+
projectTurn(runs, nodes, record);
|
|
326
332
|
} else if (record.decision) {
|
|
327
333
|
decisionCount += 1;
|
|
328
334
|
run.decisionCount += 1;
|
|
329
335
|
increment(run.decisions, record.decision.kind);
|
|
330
336
|
}
|
|
331
337
|
}
|
|
338
|
+
const byRun = /* @__PURE__ */ new Map();
|
|
339
|
+
for (const node of nodes.values()) {
|
|
340
|
+
const list = byRun.get(node.runId);
|
|
341
|
+
if (list) list.push(node);
|
|
342
|
+
else byRun.set(node.runId, [node]);
|
|
343
|
+
}
|
|
332
344
|
const first = verified[0];
|
|
333
345
|
const last = verified.at(-1);
|
|
334
346
|
return Object.freeze({
|
|
@@ -337,7 +349,7 @@ function projectPursuit(records) {
|
|
|
337
349
|
chainTip: last.digest,
|
|
338
350
|
firstObservedAt: first.observedAt,
|
|
339
351
|
lastObservedAt: last.observedAt,
|
|
340
|
-
runs: Object.freeze([...runs.values()].sort((a, b) => a.firstSequence - b.firstSequence || a.runId.localeCompare(b.runId)).map(freezeRun)),
|
|
352
|
+
runs: Object.freeze([...runs.values()].sort((a, b) => a.firstSequence - b.firstSequence || a.runId.localeCompare(b.runId)).map((run) => freezeRun(run, byRun.get(run.runId) ?? []))),
|
|
341
353
|
nodes: Object.freeze([...nodes.values()].sort((a, b) => a.firstSequence - b.firstSequence || a.runId.localeCompare(b.runId) || a.id.localeCompare(b.id)).map(freezeNode)),
|
|
342
354
|
eventCount,
|
|
343
355
|
decisionCount
|
|
@@ -398,6 +410,8 @@ function projectSpawnNode(nodes, record) {
|
|
|
398
410
|
const runtime = stringField(payload, "runtime");
|
|
399
411
|
const depth = numberField(payload, "depth");
|
|
400
412
|
const assignmentId = stringField(payload, "assignmentId");
|
|
413
|
+
const attemptId = stringField(payload, "attemptId");
|
|
414
|
+
const startedAt = numberField(payload, "startedAt");
|
|
401
415
|
nodes.set(key, {
|
|
402
416
|
id: childId,
|
|
403
417
|
...event.parentId ? { parentId: event.parentId } : {},
|
|
@@ -406,14 +420,18 @@ function projectSpawnNode(nodes, record) {
|
|
|
406
420
|
...runtime ? { runtime } : {},
|
|
407
421
|
...depth !== void 0 ? { depth } : {},
|
|
408
422
|
...assignmentId ? { assignmentId } : {},
|
|
423
|
+
...attemptId ? { attemptId } : {},
|
|
424
|
+
startedAt: startedAt ?? record.observedAt,
|
|
409
425
|
...payload && Object.hasOwn(payload, "identity") ? { identity: payload.identity } : {},
|
|
410
426
|
...payload && Object.hasOwn(payload, "budget") ? { budget: payload.budget } : {},
|
|
411
427
|
status: "running",
|
|
428
|
+
modelCalls: [],
|
|
412
429
|
firstSequence: record.sequence,
|
|
413
430
|
lastSequence: record.sequence,
|
|
414
431
|
firstObservedAt: record.observedAt,
|
|
415
432
|
lastObservedAt: record.observedAt,
|
|
416
|
-
eventCount: 1
|
|
433
|
+
eventCount: 1,
|
|
434
|
+
turnCount: 0
|
|
417
435
|
});
|
|
418
436
|
}
|
|
419
437
|
function projectNodeActivity(nodes, record) {
|
|
@@ -432,8 +450,14 @@ function projectNodeActivity(nodes, record) {
|
|
|
432
450
|
const status = stringField(payload, "status");
|
|
433
451
|
if (status !== "done" && status !== "down") return;
|
|
434
452
|
node.status = status;
|
|
435
|
-
node.settledAt = record.observedAt;
|
|
436
|
-
|
|
453
|
+
node.settledAt = numberField(payload, "settledAt") ?? record.observedAt;
|
|
454
|
+
const startedAt = numberField(payload, "startedAt");
|
|
455
|
+
if (startedAt !== void 0) node.startedAt = startedAt;
|
|
456
|
+
if (payload && Object.hasOwn(payload, "spent")) node.spent = spendField(payload, "spent");
|
|
457
|
+
const metered = spendField(payload, "metered");
|
|
458
|
+
if (metered) node.ownInference = node.ownInference ? addSpend(node.ownInference, metered) : metered;
|
|
459
|
+
const runtime = stringField(payload, "runtime");
|
|
460
|
+
if (runtime) node.runtime = runtime;
|
|
437
461
|
const outRef = stringField(payload, "outRef");
|
|
438
462
|
if (outRef) node.outRef = outRef;
|
|
439
463
|
const score = numberField(payload, "score");
|
|
@@ -444,17 +468,232 @@ function projectNodeActivity(nodes, record) {
|
|
|
444
468
|
if (reason) node.reason = reason;
|
|
445
469
|
const infra = booleanField(payload, "infra");
|
|
446
470
|
if (infra !== void 0) node.infra = infra;
|
|
471
|
+
const restartCount = numberField(payload, "restartCount");
|
|
472
|
+
if (restartCount !== void 0) node.restartCount = restartCount;
|
|
447
473
|
if (payload && Object.hasOwn(payload, "wait")) node.wait = payload.wait;
|
|
474
|
+
attachSettlementEvidence(node, payload);
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* Read the receipts a settlement carries. Each is taken as reported: an `unknown` receipt keeps
|
|
478
|
+
* its `status` and `reason` so a client can show WHY a model or backend is missing instead of
|
|
479
|
+
* showing nothing, and a receipt that never landed leaves every derived field absent.
|
|
480
|
+
*/
|
|
481
|
+
function attachSettlementEvidence(node, payload) {
|
|
482
|
+
const providerModel = payload?.providerModel;
|
|
483
|
+
if (providerModel && typeof providerModel === "object") node.providerModel = providerModel;
|
|
484
|
+
const trace = payload?.trace;
|
|
485
|
+
if (trace && typeof trace === "object") node.trace = trace;
|
|
486
|
+
const bindings = payload?.executionBindings;
|
|
487
|
+
if (Array.isArray(bindings) && bindings.length > 0) {
|
|
488
|
+
node.executionBindings = bindings;
|
|
489
|
+
const known = bindings.find((binding) => objectRecord(binding)?.status === "known");
|
|
490
|
+
if (known) {
|
|
491
|
+
node.placement = known.descriptor;
|
|
492
|
+
node.attemptId ??= known.attemptId;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
const receipt = payload?.materialization;
|
|
496
|
+
if (!receipt || typeof receipt !== "object") return;
|
|
497
|
+
node.materialization = receipt;
|
|
498
|
+
if (receipt.status !== "known") return;
|
|
499
|
+
node.backend = receipt.backend;
|
|
500
|
+
if (receipt.model.status === "known") node.model = receipt.model.id;
|
|
501
|
+
node.execution = {
|
|
502
|
+
kind: receipt.execution.kind,
|
|
503
|
+
id: receipt.execution.id
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Fold one metered turn onto whoever drove it. `agent.turn` names its subject in `parentId` — the
|
|
508
|
+
* node making the call — not in the payload, because the caller IS the subject. A turn the run
|
|
509
|
+
* root drove belongs to no spawned node and lands on the run instead, so the run's totals stay
|
|
510
|
+
* complete without inventing a node for the root.
|
|
511
|
+
*/
|
|
512
|
+
function projectTurn(runs, nodes, record) {
|
|
513
|
+
const event = record.event;
|
|
514
|
+
if (event?.target !== "agent.turn") return;
|
|
515
|
+
const payload = objectRecord(event.payload);
|
|
516
|
+
const spend = spendField(payload, "spend");
|
|
517
|
+
const subject = event.parentId;
|
|
518
|
+
if (subject === void 0) return;
|
|
519
|
+
const node = nodes.get(nodeKey(event.runId, subject));
|
|
520
|
+
if (!node) {
|
|
521
|
+
if (!spend) return;
|
|
522
|
+
const run = runs.get(event.runId);
|
|
523
|
+
if (!run) return;
|
|
524
|
+
run.rootInference = run.rootInference ? addSpend(run.rootInference, spend) : spend;
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
node.turnCount += 1;
|
|
528
|
+
node.lastSequence = record.sequence;
|
|
529
|
+
node.lastObservedAt = record.observedAt;
|
|
530
|
+
if (spend) {
|
|
531
|
+
node.ownInference = node.ownInference ? addSpend(node.ownInference, spend) : spend;
|
|
532
|
+
node.firstOutputAt ??= record.observedAt;
|
|
533
|
+
}
|
|
534
|
+
const reasoning = numberField(payload, "reasoningTokens");
|
|
535
|
+
if (reasoning !== void 0) node.reasoningTokens = (node.reasoningTokens ?? 0) + reasoning;
|
|
536
|
+
const firstTokenAt = numberField(payload, "firstTokenAt");
|
|
537
|
+
if (firstTokenAt !== void 0) node.firstTokenAt ??= firstTokenAt;
|
|
538
|
+
const model = stringField(payload, "model");
|
|
539
|
+
if (model) node.model ??= model;
|
|
540
|
+
const callId = stringField(payload, "callId");
|
|
541
|
+
if (callId && !node.modelCalls.includes(callId)) node.modelCalls.push(callId);
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* A node's whole reported cost: the child work its settlement reported plus the inference it drove
|
|
545
|
+
* itself. `undefined` when neither landed — the run's `spendGaps` then names the node, so an
|
|
546
|
+
* unaccounted node is visible instead of reading as free.
|
|
547
|
+
*/
|
|
548
|
+
function nodeTotal(node) {
|
|
549
|
+
if (node.spent && node.ownInference) return addSpend(node.spent, node.ownInference);
|
|
550
|
+
if (node.spent) return cloneSpend(node.spent);
|
|
551
|
+
if (node.ownInference) return cloneSpend(node.ownInference);
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* The run counted once, and each node's own share of it.
|
|
555
|
+
*
|
|
556
|
+
* A settled node's `spent` already contains the child work its nested tree reported, so summing
|
|
557
|
+
* every node would count a driver's descendants twice. Inclusive therefore sums only the run's
|
|
558
|
+
* TOP-LEVEL nodes — those whose parent is not another node of this run — plus the root's own
|
|
559
|
+
* turns. Exclusive subtracts each node's direct children from its own total, which telescopes:
|
|
560
|
+
* the exclusive entries sum back to `inclusive` exactly.
|
|
561
|
+
*/
|
|
562
|
+
function runTotals(run, nodes) {
|
|
563
|
+
const present = new Set(nodes.map((node) => node.id));
|
|
564
|
+
const children = /* @__PURE__ */ new Map();
|
|
565
|
+
for (const node of nodes) {
|
|
566
|
+
if (node.parentId === void 0 || !present.has(node.parentId)) continue;
|
|
567
|
+
const list = children.get(node.parentId);
|
|
568
|
+
if (list) list.push(node);
|
|
569
|
+
else children.set(node.parentId, [node]);
|
|
570
|
+
}
|
|
571
|
+
const exclusiveByNode = {};
|
|
572
|
+
let inclusive = run.rootInference ? cloneSpend(run.rootInference) : zeroSpend();
|
|
573
|
+
if (run.rootInference) exclusiveByNode[run.runId] = cloneSpend(run.rootInference);
|
|
574
|
+
for (const node of nodes) {
|
|
575
|
+
const total = nodeTotal(node);
|
|
576
|
+
if (total === void 0) continue;
|
|
577
|
+
if (node.parentId === void 0 || !present.has(node.parentId)) inclusive = addSpend(inclusive, total);
|
|
578
|
+
let exclusive = total;
|
|
579
|
+
for (const child of children.get(node.id) ?? []) {
|
|
580
|
+
const childTotal = nodeTotal(child);
|
|
581
|
+
if (childTotal !== void 0) exclusive = subtractSpend(exclusive, childTotal);
|
|
582
|
+
}
|
|
583
|
+
exclusiveByNode[node.id] = exclusive;
|
|
584
|
+
}
|
|
585
|
+
return Object.freeze({
|
|
586
|
+
inclusive: Object.freeze(inclusive),
|
|
587
|
+
exclusiveByNode: Object.freeze(exclusiveByNode)
|
|
588
|
+
});
|
|
589
|
+
}
|
|
590
|
+
/**
|
|
591
|
+
* Remove a child's reported total from its parent's. Per channel, never below zero: a parent whose
|
|
592
|
+
* executor reported less than its children did is a reporting gap, and a negative exclusive share
|
|
593
|
+
* would be a fabricated number rather than a measurement.
|
|
594
|
+
*/
|
|
595
|
+
function subtractSpend(a, b) {
|
|
596
|
+
const tokens = { ...a.tokens };
|
|
597
|
+
tokens.input = Math.max(0, tokens.input - b.tokens.input);
|
|
598
|
+
tokens.output = Math.max(0, tokens.output - b.tokens.output);
|
|
599
|
+
if (a.tokens.cacheRead !== void 0) tokens.cacheRead = Math.max(0, a.tokens.cacheRead - (b.tokens.cacheRead ?? 0));
|
|
600
|
+
if (a.tokens.cacheWrite !== void 0) tokens.cacheWrite = Math.max(0, a.tokens.cacheWrite - (b.tokens.cacheWrite ?? 0));
|
|
601
|
+
if (a.tokens.freshInput !== void 0) tokens.freshInput = Math.max(0, a.tokens.freshInput - (b.tokens.freshInput ?? 0));
|
|
602
|
+
return {
|
|
603
|
+
iterations: Math.max(0, a.iterations - b.iterations),
|
|
604
|
+
tokens,
|
|
605
|
+
...a.tokensKnown === false || b.tokensKnown === false ? { tokensKnown: false } : {},
|
|
606
|
+
usd: Math.max(0, a.usd - b.usd),
|
|
607
|
+
...a.usdKnown === false || b.usdKnown === false ? { usdKnown: false } : {},
|
|
608
|
+
...a.usdEstimated !== void 0 ? { usdEstimated: Math.max(0, a.usdEstimated - (b.usdEstimated ?? 0)) } : {},
|
|
609
|
+
ms: Math.max(0, a.ms - b.ms)
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
/** The nodes of one run whose accounting is incomplete, in the vocabulary the supervisor already
|
|
613
|
+
* uses: `never-settled` = no terminal record, so every channel is unaccounted; `unreported` = a
|
|
614
|
+
* record landed with a channel the provider did not report, so that channel is a floor. */
|
|
615
|
+
function runSpendGaps(nodes) {
|
|
616
|
+
const gaps = [];
|
|
617
|
+
for (const node of nodes) {
|
|
618
|
+
const label = node.label;
|
|
619
|
+
if (node.status === "running") {
|
|
620
|
+
gaps.push({
|
|
621
|
+
id: node.id,
|
|
622
|
+
...label !== void 0 ? { label } : {},
|
|
623
|
+
kind: "never-settled",
|
|
624
|
+
channels: ["tokens", "usd"]
|
|
625
|
+
});
|
|
626
|
+
continue;
|
|
627
|
+
}
|
|
628
|
+
const total = nodeTotal(node);
|
|
629
|
+
const channels = [];
|
|
630
|
+
if (total === void 0 || total.tokensKnown === false) channels.push("tokens");
|
|
631
|
+
if (total === void 0 || total.usdKnown === false) channels.push("usd");
|
|
632
|
+
if (channels.length === 0) continue;
|
|
633
|
+
gaps.push({
|
|
634
|
+
id: node.id,
|
|
635
|
+
...label !== void 0 ? { label } : {},
|
|
636
|
+
kind: "unreported",
|
|
637
|
+
channels
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
return gaps;
|
|
448
641
|
}
|
|
449
|
-
function
|
|
642
|
+
function usageOf(total, reasoning) {
|
|
643
|
+
return {
|
|
644
|
+
input: total.tokens.input,
|
|
645
|
+
output: total.tokens.output,
|
|
646
|
+
...total.tokens.cacheRead !== void 0 ? { cacheRead: total.tokens.cacheRead } : {},
|
|
647
|
+
...total.tokens.cacheWrite !== void 0 ? { cacheWrite: total.tokens.cacheWrite } : {},
|
|
648
|
+
...reasoning !== void 0 ? { reasoning } : {},
|
|
649
|
+
tokensKnown: total.tokensKnown !== false && total.tokens.tokensKnown !== false
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
function costOf(total) {
|
|
653
|
+
const usdKnown = total.usdKnown !== false;
|
|
654
|
+
const estimated = total.usdEstimated;
|
|
655
|
+
const provenance = usdKnown ? estimated === void 0 || estimated === 0 ? "reported" : "partial" : estimated === void 0 ? "unknown" : estimated >= total.usd ? "estimated" : "partial";
|
|
656
|
+
return {
|
|
657
|
+
usd: total.usd,
|
|
658
|
+
usdKnown,
|
|
659
|
+
...estimated !== void 0 ? { usdEstimated: estimated } : {},
|
|
660
|
+
provenance
|
|
661
|
+
};
|
|
662
|
+
}
|
|
663
|
+
function timingOf(node) {
|
|
664
|
+
if (node.startedAt === void 0) return void 0;
|
|
665
|
+
return {
|
|
666
|
+
startedAt: node.startedAt,
|
|
667
|
+
...node.firstOutputAt !== void 0 ? { firstOutputAt: node.firstOutputAt } : {},
|
|
668
|
+
...node.firstTokenAt !== void 0 ? { firstTokenAt: node.firstTokenAt } : {},
|
|
669
|
+
...node.settledAt !== void 0 ? { settledAt: node.settledAt } : {},
|
|
670
|
+
...node.settledAt !== void 0 ? { wallMs: Math.max(0, node.settledAt - node.startedAt) } : {}
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
function freezeRun(run, nodes) {
|
|
674
|
+
const gaps = runSpendGaps(nodes);
|
|
675
|
+
const { rootInference: _rootInference, ...rest } = run;
|
|
450
676
|
return Object.freeze({
|
|
451
|
-
...
|
|
677
|
+
...rest,
|
|
452
678
|
targets: Object.freeze({ ...run.targets }),
|
|
453
|
-
decisions: Object.freeze({ ...run.decisions })
|
|
679
|
+
decisions: Object.freeze({ ...run.decisions }),
|
|
680
|
+
totals: runTotals(run, nodes),
|
|
681
|
+
...gaps.length > 0 ? { spendGaps: Object.freeze(gaps) } : {}
|
|
454
682
|
});
|
|
455
683
|
}
|
|
456
684
|
function freezeNode(node) {
|
|
457
|
-
|
|
685
|
+
const { modelCalls, reasoningTokens, startedAt: _startedAt, ...rest } = node;
|
|
686
|
+
const total = nodeTotal(node);
|
|
687
|
+
const timing = timingOf(node);
|
|
688
|
+
return Object.freeze({
|
|
689
|
+
...rest,
|
|
690
|
+
...modelCalls.length > 0 ? { modelCalls: Object.freeze([...modelCalls]) } : {},
|
|
691
|
+
...total !== void 0 ? {
|
|
692
|
+
usage: usageOf(total, reasoningTokens),
|
|
693
|
+
cost: costOf(total)
|
|
694
|
+
} : {},
|
|
695
|
+
...timing !== void 0 ? { timing } : {}
|
|
696
|
+
});
|
|
458
697
|
}
|
|
459
698
|
function increment(target, key) {
|
|
460
699
|
target[key] = (target[key] ?? 0) + 1;
|
|
@@ -462,6 +701,16 @@ function increment(target, key) {
|
|
|
462
701
|
function objectRecord(value) {
|
|
463
702
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
464
703
|
}
|
|
704
|
+
/** Read a journaled `Spend` without trusting the wire: a record missing the conserved channels is
|
|
705
|
+
* not a zero-cost turn, it is an unparseable one, and it must not enter a total. */
|
|
706
|
+
function spendField(value, key) {
|
|
707
|
+
const field = objectRecord(value?.[key]);
|
|
708
|
+
if (!field) return void 0;
|
|
709
|
+
const tokens = objectRecord(field.tokens);
|
|
710
|
+
if (typeof field.usd !== "number" || !Number.isFinite(field.usd)) return void 0;
|
|
711
|
+
if (!tokens || typeof tokens.input !== "number" || typeof tokens.output !== "number") return;
|
|
712
|
+
return cloneSpend(field);
|
|
713
|
+
}
|
|
465
714
|
function stringField(value, key) {
|
|
466
715
|
const field = value?.[key];
|
|
467
716
|
return typeof field === "string" && field.length > 0 ? field : void 0;
|
|
@@ -627,9 +876,6 @@ function isRecord(value) {
|
|
|
627
876
|
function compareText(left, right) {
|
|
628
877
|
return left < right ? -1 : left > right ? 1 : 0;
|
|
629
878
|
}
|
|
630
|
-
function isNoEntError(error) {
|
|
631
|
-
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
632
|
-
}
|
|
633
879
|
//#endregion
|
|
634
880
|
export { FileObserverJournal, SupervisePursuitError, createFileObserverHooks, deriveExecutionId, discoverDurableSupervisionRun, handleChatTurn, observerRecordDigest, projectPursuit, supervisePursuit, verifyObserverRecords };
|
|
635
881
|
|