@rulvar/core 1.5.2 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/index.d.ts +182 -22
- package/dist/index.js +651 -247
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -5484,6 +5484,7 @@ var Replayer = class {
|
|
|
5484
5484
|
if (patch.usageApprox !== void 0) entry.usageApprox = patch.usageApprox;
|
|
5485
5485
|
if (patch.servedBy !== void 0) entry.servedBy = patch.servedBy;
|
|
5486
5486
|
if (patch.usageByModel !== void 0) entry.usageByModel = patch.usageByModel;
|
|
5487
|
+
if (patch.costAttribution !== void 0) entry.costAttribution = patch.costAttribution;
|
|
5487
5488
|
if (patch.transcriptRef !== void 0) entry.transcriptRef = patch.transcriptRef;
|
|
5488
5489
|
if (patch.checkpointRef !== void 0) entry.checkpointRef = patch.checkpointRef;
|
|
5489
5490
|
if (patch.artifacts !== void 0) entry.artifacts = toJournalValue(patch.artifacts, "terminal artifacts");
|
|
@@ -6147,19 +6148,28 @@ var FileTranscriptStore = class {
|
|
|
6147
6148
|
//#endregion
|
|
6148
6149
|
//#region src/engine/cost-report.ts
|
|
6149
6150
|
/**
|
|
6150
|
-
* CostReport builders (M5-T03).
|
|
6151
|
-
* sources, one shape:
|
|
6151
|
+
* CostReport builders (M5-T03; follow-up: one pure fold).
|
|
6152
6152
|
*
|
|
6153
|
-
*
|
|
6154
|
-
*
|
|
6155
|
-
*
|
|
6156
|
-
*
|
|
6157
|
-
*
|
|
6158
|
-
*
|
|
6159
|
-
*
|
|
6160
|
-
*
|
|
6161
|
-
*
|
|
6162
|
-
*
|
|
6153
|
+
* `costReportFromJournal` is THE report: a pure fold over terminal
|
|
6154
|
+
* entries that both the engine's settle path and stored-run inspection
|
|
6155
|
+
* (shells, `rulvar inspect`) use, so a replayed run reports the same
|
|
6156
|
+
* numbers byte for byte. Terminal entries carry their attribution facts
|
|
6157
|
+
* (`costAttribution`: phase, agent type, primary role, budget account,
|
|
6158
|
+
* finalize-reserve flag) exactly so this fold can reproduce every
|
|
6159
|
+
* breakdown without live state; entries written before the facts
|
|
6160
|
+
* shipped fold under the documented fallbacks (empty phase, 'unknown'
|
|
6161
|
+
* agent type, role 'loop').
|
|
6162
|
+
*
|
|
6163
|
+
* Inclusion policy, applied to the total and EVERY breakdown alike:
|
|
6164
|
+
* terminal usage exactly once, priced per serving slice, entries under
|
|
6165
|
+
* abandoned subtrees contribute zero (their spend is tracked separately
|
|
6166
|
+
* in the abandoned-spend ledger the orchestrator sees). Attempts that
|
|
6167
|
+
* were paid but never abandoned (a cancelled root attempt, a dangling
|
|
6168
|
+
* child) are real spend and stay included everywhere.
|
|
6169
|
+
*
|
|
6170
|
+
* `buildCostReport` folds the LIVE per-run attribution buckets around
|
|
6171
|
+
* the ledger total; it remains for hosts that accumulated their own
|
|
6172
|
+
* `CostAttribution`, but the engine no longer builds outcomes from it.
|
|
6163
6173
|
*
|
|
6164
6174
|
* Unpriced models surface in `unpriced`, never as a silent zero.
|
|
6165
6175
|
*/
|
|
@@ -6174,14 +6184,9 @@ const ROLES = [
|
|
|
6174
6184
|
function emptyByRole() {
|
|
6175
6185
|
return Object.fromEntries(ROLES.map((role) => [role, 0]));
|
|
6176
6186
|
}
|
|
6177
|
-
|
|
6178
|
-
|
|
6179
|
-
|
|
6180
|
-
share: 0,
|
|
6181
|
-
wakes: 0,
|
|
6182
|
-
forcedFinish: false,
|
|
6183
|
-
reserveUsedUsd: 0
|
|
6184
|
-
};
|
|
6187
|
+
/** The orchestrator sub-account naming rule of makeOrchestratorWorkflow. */
|
|
6188
|
+
function isOrchestratorAccount(scope) {
|
|
6189
|
+
return scope === "orchestrator" || scope.endsWith("/orchestrator");
|
|
6185
6190
|
}
|
|
6186
6191
|
/** Folds the per-run attribution buckets into the normative CostReport. */
|
|
6187
6192
|
function buildCostReport(attribution, totalUsd) {
|
|
@@ -6207,16 +6212,30 @@ function buildCostReport(attribution, totalUsd) {
|
|
|
6207
6212
|
};
|
|
6208
6213
|
}
|
|
6209
6214
|
/**
|
|
6210
|
-
* The pure journal fold:
|
|
6211
|
-
* same summation the kernel ledger uses (terminal usage exactly
|
|
6212
|
-
* priced per servedBy, abandoned subtrees contribute zero).
|
|
6215
|
+
* The pure journal fold: the complete CostReport from terminal entries,
|
|
6216
|
+
* the same summation the kernel ledger uses (terminal usage exactly
|
|
6217
|
+
* once, priced per servedBy slice, abandoned subtrees contribute zero).
|
|
6218
|
+
* The orchestrator block folds too: spend attributed to the
|
|
6219
|
+
* orchestrator sub-account, the reserve-funded share of it, the armed
|
|
6220
|
+
* wake count, and the at-cap freeze flag from the journaled cap
|
|
6221
|
+
* decision, so a replay-only resume reproduces the block instead of
|
|
6222
|
+
* reading this process's live accounts (which a replay never charges).
|
|
6213
6223
|
*/
|
|
6214
6224
|
function costReportFromJournal(entries, priceUsd) {
|
|
6215
6225
|
const abandonFold = buildAbandonFold(entries);
|
|
6216
6226
|
const byModel = {};
|
|
6227
|
+
const byPhase = {};
|
|
6228
|
+
const byAgentType = {};
|
|
6229
|
+
const byRole = emptyByRole();
|
|
6217
6230
|
const unpriced = [];
|
|
6218
6231
|
let totalUsd = 0;
|
|
6232
|
+
let orchestratorSpentUsd = 0;
|
|
6233
|
+
let reserveUsedUsd = 0;
|
|
6234
|
+
let wakes = 0;
|
|
6235
|
+
let forcedFinish = false;
|
|
6219
6236
|
for (const entry of entries) {
|
|
6237
|
+
if (entry.kind === "decision" && entry.value?.decisionType === "orchestrator_budget_cap") forcedFinish = true;
|
|
6238
|
+
if (entry.kind === "external" && entry.status === "suspended" && typeof entry.value?.key === "string" && (entry.value.key.startsWith("wake:") || entry.value.key.includes(":wake:"))) wakes += 1;
|
|
6220
6239
|
if (entry.kind !== "resolution" && entry.kind !== "abandon" && abandonFold.isAbandoned(entry.ref ?? entry.seq)) continue;
|
|
6221
6240
|
if (entry.status === "running" || entry.usage === void 0) continue;
|
|
6222
6241
|
const priced = priceEntryUsage(entry, priceUsd);
|
|
@@ -6226,14 +6245,30 @@ function costReportFromJournal(entries, priceUsd) {
|
|
|
6226
6245
|
});
|
|
6227
6246
|
for (const slice of priced.priced) byModel[slice.servedBy] = (byModel[slice.servedBy] ?? 0) + slice.usd;
|
|
6228
6247
|
totalUsd += priced.usd;
|
|
6248
|
+
const facts = entry.costAttribution;
|
|
6249
|
+
const phase = facts?.phase ?? "";
|
|
6250
|
+
byPhase[phase] = (byPhase[phase] ?? 0) + priced.usd;
|
|
6251
|
+
const agentType = facts?.agentType ?? "unknown";
|
|
6252
|
+
byAgentType[agentType] = (byAgentType[agentType] ?? 0) + priced.usd;
|
|
6253
|
+
byRole[facts?.role ?? "loop"] += priced.usd;
|
|
6254
|
+
if (facts?.budgetAccount !== void 0 && isOrchestratorAccount(facts.budgetAccount)) {
|
|
6255
|
+
orchestratorSpentUsd += priced.usd;
|
|
6256
|
+
if (facts.finalizeReserve === true) reserveUsedUsd += priced.usd;
|
|
6257
|
+
}
|
|
6229
6258
|
}
|
|
6230
6259
|
return {
|
|
6231
6260
|
totalUsd,
|
|
6232
6261
|
byModel,
|
|
6233
|
-
byPhase
|
|
6234
|
-
byAgentType
|
|
6235
|
-
byRole
|
|
6236
|
-
orchestrator:
|
|
6262
|
+
byPhase,
|
|
6263
|
+
byAgentType,
|
|
6264
|
+
byRole,
|
|
6265
|
+
orchestrator: {
|
|
6266
|
+
spentUsd: orchestratorSpentUsd,
|
|
6267
|
+
share: orchestratorSpentUsd / Math.max(totalUsd, .01),
|
|
6268
|
+
wakes,
|
|
6269
|
+
forcedFinish,
|
|
6270
|
+
reserveUsedUsd
|
|
6271
|
+
},
|
|
6237
6272
|
unpriced
|
|
6238
6273
|
};
|
|
6239
6274
|
}
|
|
@@ -6495,15 +6530,51 @@ function fallbackTriggerOf(outcome) {
|
|
|
6495
6530
|
function resolvePricing(ref, table, capsPricing) {
|
|
6496
6531
|
return table?.models[ref] ?? capsPricing;
|
|
6497
6532
|
}
|
|
6498
|
-
/**
|
|
6499
|
-
|
|
6500
|
-
|
|
6501
|
-
|
|
6502
|
-
|
|
6533
|
+
/** The tier a full prompt lands in: the highest threshold strictly below it. */
|
|
6534
|
+
function tierFor(pricing, inputTokens) {
|
|
6535
|
+
let tier;
|
|
6536
|
+
for (const candidate of pricing.tiers ?? []) if (inputTokens > candidate.aboveInputTokens && (tier === void 0 || candidate.aboveInputTokens > tier.aboveInputTokens)) tier = candidate;
|
|
6537
|
+
return tier;
|
|
6538
|
+
}
|
|
6539
|
+
/**
|
|
6540
|
+
* Dollars from normalized usage against one pricing row. Under the Usage
|
|
6541
|
+
* invariant inputTokens is the FULL prompt including cache reads and
|
|
6542
|
+
* writes, so the input rate bills only the uncached remainder and cache
|
|
6543
|
+
* tokens bill at their own rates, never twice; a row that omits a cache
|
|
6544
|
+
* rate bills those tokens at the plain input rate rather than silently
|
|
6545
|
+
* for free. A row may carry long-context tiers: the highest threshold
|
|
6546
|
+
* strictly below the full prompt re-prices the ENTIRE request
|
|
6547
|
+
* (input-side rates scale by inputMultiplier, the output rate by
|
|
6548
|
+
* outputMultiplier). Cache writes price at the 5m premium rate; the 1h
|
|
6549
|
+
* rate applies where a provider distinguishes it in usage, which the
|
|
6503
6550
|
* canonical Usage does not yet carry.
|
|
6504
6551
|
*/
|
|
6505
6552
|
function priceUsdOf(pricing, usage) {
|
|
6506
|
-
|
|
6553
|
+
const tier = tierFor(pricing, usage.inputTokens);
|
|
6554
|
+
const inputMul = tier?.inputMultiplier ?? 1;
|
|
6555
|
+
const outputMul = tier?.outputMultiplier ?? 1;
|
|
6556
|
+
return Math.max(0, usage.inputTokens - usage.cacheReadTokens - usage.cacheWriteTokens) / 1e6 * pricing.inputUsdPerMTok * inputMul + usage.outputTokens / 1e6 * pricing.outputUsdPerMTok * outputMul + usage.cacheReadTokens / 1e6 * (pricing.cacheReadUsdPerMTok ?? pricing.inputUsdPerMTok) * inputMul + usage.cacheWriteTokens / 1e6 * (pricing.cacheWriteUsdPerMTok ?? pricing.inputUsdPerMTok) * inputMul;
|
|
6557
|
+
}
|
|
6558
|
+
/**
|
|
6559
|
+
* The output tokens `remainingUsd` still buys from one pricing row after
|
|
6560
|
+
* paying for an estimated prompt of `estimatedInputTokens`, priced with
|
|
6561
|
+
* the same tier rules as settlement (the tier is selected by the
|
|
6562
|
+
* estimated prompt). Floored to whole tokens; zero or negative means not
|
|
6563
|
+
* even one output token fits, so the turn must not be dispatched.
|
|
6564
|
+
* Undefined when the row prices output at zero (a free model needs no
|
|
6565
|
+
* output bound).
|
|
6566
|
+
*/
|
|
6567
|
+
function affordableOutputTokens(pricing, remainingUsd, estimatedInputTokens) {
|
|
6568
|
+
const tier = tierFor(pricing, estimatedInputTokens);
|
|
6569
|
+
const outputRate = pricing.outputUsdPerMTok * (tier?.outputMultiplier ?? 1);
|
|
6570
|
+
if (outputRate <= 0) return;
|
|
6571
|
+
const inputUsd = priceUsdOf(pricing, {
|
|
6572
|
+
inputTokens: estimatedInputTokens,
|
|
6573
|
+
outputTokens: 0,
|
|
6574
|
+
cacheReadTokens: 0,
|
|
6575
|
+
cacheWriteTokens: 0
|
|
6576
|
+
});
|
|
6577
|
+
return Math.floor((remainingUsd - inputUsd) / outputRate * 1e6);
|
|
6507
6578
|
}
|
|
6508
6579
|
//#endregion
|
|
6509
6580
|
//#region src/model/profile-card.ts
|
|
@@ -7681,6 +7752,50 @@ function buildRequest(resolved, messages, limits, tools) {
|
|
|
7681
7752
|
return req;
|
|
7682
7753
|
}
|
|
7683
7754
|
/**
|
|
7755
|
+
* Cheap deterministic prompt-size estimate (about four serialized
|
|
7756
|
+
* characters per token) for the layer-2b output bound. Never used for
|
|
7757
|
+
* identity, accounting, or anything the journal records.
|
|
7758
|
+
*/
|
|
7759
|
+
function estimateInputTokens(messages) {
|
|
7760
|
+
let chars = 0;
|
|
7761
|
+
for (const msg of messages) chars += JSON.stringify(msg.parts).length;
|
|
7762
|
+
return Math.ceil(chars / 4);
|
|
7763
|
+
}
|
|
7764
|
+
/**
|
|
7765
|
+
* Layer 2b at the wire boundary: clamps the outgoing request's
|
|
7766
|
+
* maxOutputTokens to what the remaining budget affords from the serving
|
|
7767
|
+
* model. The clamp uses the heuristic prompt estimate; the DENIAL does
|
|
7768
|
+
* not: a turn is refused (BudgetExhaustedError, never dispatched) only
|
|
7769
|
+
* when the remainder cannot buy even ONE output token at zero input,
|
|
7770
|
+
* which is exact. Denying on the estimate would kill turns the budget
|
|
7771
|
+
* still funds, including the DEF-7 forced finish paid from the released
|
|
7772
|
+
* finalize reserve; when the estimate says the prompt alone spends the
|
|
7773
|
+
* remainder, the turn dispatches with a one-token output floor and the
|
|
7774
|
+
* exact layers (2 and 3) settle the difference. A no-op without a hook
|
|
7775
|
+
* or when the hook reports no bound. The clamp touches only the wire
|
|
7776
|
+
* request, exactly like limits.maxOutputTokensPerTurn above it; identity
|
|
7777
|
+
* is computed at the ctx layer and never sees it.
|
|
7778
|
+
*/
|
|
7779
|
+
function applyOutputBudget(req, target, budget) {
|
|
7780
|
+
const hook = budget?.maxAffordableOutputTokens;
|
|
7781
|
+
if (hook === void 0) return req;
|
|
7782
|
+
const affordable = hook(target.resolved.ref, estimateInputTokens(req.messages));
|
|
7783
|
+
if (affordable === void 0) return req;
|
|
7784
|
+
if (affordable < 1) {
|
|
7785
|
+
const zeroInputAffordable = hook(target.resolved.ref, 0);
|
|
7786
|
+
if (zeroInputAffordable !== void 0 && zeroInputAffordable < 1) throw new BudgetExhaustedError(`the remaining budget cannot afford one output token from ${target.resolved.ref}; the turn was not dispatched`);
|
|
7787
|
+
return {
|
|
7788
|
+
...req,
|
|
7789
|
+
maxOutputTokens: 1
|
|
7790
|
+
};
|
|
7791
|
+
}
|
|
7792
|
+
if (req.maxOutputTokens === void 0 || affordable < req.maxOutputTokens) return {
|
|
7793
|
+
...req,
|
|
7794
|
+
maxOutputTokens: affordable
|
|
7795
|
+
};
|
|
7796
|
+
return req;
|
|
7797
|
+
}
|
|
7798
|
+
/**
|
|
7684
7799
|
* Builds the turn's canonical assistant message. Retained provider-raw
|
|
7685
7800
|
* parts go at the HEAD: on both first-class providers the retained
|
|
7686
7801
|
* blocks (thinking blocks, reasoning items) precede the turn's text and
|
|
@@ -8168,28 +8283,41 @@ async function runAgent(options) {
|
|
|
8168
8283
|
turns += 1;
|
|
8169
8284
|
const signals = [];
|
|
8170
8285
|
if (options.signal !== void 0) signals.push(options.signal);
|
|
8171
|
-
|
|
8172
|
-
|
|
8173
|
-
|
|
8174
|
-
|
|
8175
|
-
|
|
8176
|
-
|
|
8177
|
-
|
|
8178
|
-
|
|
8179
|
-
|
|
8180
|
-
|
|
8181
|
-
|
|
8182
|
-
|
|
8183
|
-
|
|
8184
|
-
|
|
8185
|
-
|
|
8186
|
-
|
|
8187
|
-
|
|
8188
|
-
delta
|
|
8189
|
-
|
|
8190
|
-
|
|
8191
|
-
|
|
8192
|
-
|
|
8286
|
+
let loopDispatch;
|
|
8287
|
+
try {
|
|
8288
|
+
loopDispatch = await dispatchPhase({
|
|
8289
|
+
chain: loopChain,
|
|
8290
|
+
cursor: loopCursor,
|
|
8291
|
+
requestFor: (target) => {
|
|
8292
|
+
let req = buildRequest(target.resolved, projectHistory(messages, providerOf(target.adapter)), limits, options.tools?.contracts);
|
|
8293
|
+
if (options.schema !== void 0 && options.canonicalSchema !== void 0 && !separateExtract) req = applyStructuredOutputTier(req, rideTierFor(target), options.canonicalSchema);
|
|
8294
|
+
return applyOutputBudget(req, target, options.budget);
|
|
8295
|
+
},
|
|
8296
|
+
streamOptionsFor: (target) => {
|
|
8297
|
+
const streamTurnOptions = {
|
|
8298
|
+
idleTimeoutMs: limits.streamIdleTimeoutMs,
|
|
8299
|
+
signals,
|
|
8300
|
+
onUsage: (delta) => options.budget?.onUsage(delta, target.resolved.ref)
|
|
8301
|
+
};
|
|
8302
|
+
if (options.budget?.signal !== void 0) streamTurnOptions.budgetSignal = options.budget.signal;
|
|
8303
|
+
if (options.stream === true) streamTurnOptions.onDelta = (delta) => events?.emit({
|
|
8304
|
+
type: "agent:stream",
|
|
8305
|
+
delta
|
|
8306
|
+
});
|
|
8307
|
+
return streamTurnOptions;
|
|
8308
|
+
}
|
|
8309
|
+
});
|
|
8310
|
+
} catch (thrown) {
|
|
8311
|
+
if (!(thrown instanceof BudgetExhaustedError)) throw thrown;
|
|
8312
|
+
status = "error";
|
|
8313
|
+
agentError = {
|
|
8314
|
+
kind: "budget",
|
|
8315
|
+
retryable: false
|
|
8316
|
+
};
|
|
8317
|
+
errorMessage = thrown.message;
|
|
8318
|
+
break;
|
|
8319
|
+
}
|
|
8320
|
+
const { outcome, target: servedTarget } = loopDispatch;
|
|
8193
8321
|
servedBy = servedTarget.resolved.ref;
|
|
8194
8322
|
usageApprox = usageApprox || outcome.usageApprox;
|
|
8195
8323
|
lastTurnUsage = {
|
|
@@ -8346,30 +8474,43 @@ async function runAgent(options) {
|
|
|
8346
8474
|
break;
|
|
8347
8475
|
}
|
|
8348
8476
|
turns += 1;
|
|
8349
|
-
|
|
8350
|
-
|
|
8351
|
-
|
|
8352
|
-
|
|
8353
|
-
|
|
8354
|
-
|
|
8355
|
-
|
|
8356
|
-
|
|
8357
|
-
|
|
8358
|
-
|
|
8359
|
-
|
|
8360
|
-
|
|
8361
|
-
|
|
8362
|
-
|
|
8363
|
-
|
|
8364
|
-
|
|
8365
|
-
|
|
8366
|
-
|
|
8367
|
-
|
|
8368
|
-
|
|
8369
|
-
|
|
8370
|
-
|
|
8371
|
-
|
|
8372
|
-
|
|
8477
|
+
let summaryDispatch;
|
|
8478
|
+
try {
|
|
8479
|
+
summaryDispatch = await dispatchPhase({
|
|
8480
|
+
chain: [{
|
|
8481
|
+
adapter: options.summarize.adapter,
|
|
8482
|
+
resolved: options.summarize.resolved
|
|
8483
|
+
}, ...options.summarize.fallbacks ?? []],
|
|
8484
|
+
cursor: { index: 0 },
|
|
8485
|
+
requestFor: (target) => {
|
|
8486
|
+
let req = buildRequest(target.resolved, [...projectHistory(messages, providerOf(target.adapter)), summarizeInstruction()], limits, options.tools?.contracts);
|
|
8487
|
+
if (req.tools !== void 0) req = {
|
|
8488
|
+
...req,
|
|
8489
|
+
toolChoice: "none"
|
|
8490
|
+
};
|
|
8491
|
+
return applyOutputBudget(req, target, options.budget);
|
|
8492
|
+
},
|
|
8493
|
+
streamOptionsFor: (target) => {
|
|
8494
|
+
const summarizeStreamOptions = {
|
|
8495
|
+
idleTimeoutMs: limits.streamIdleTimeoutMs,
|
|
8496
|
+
signals: options.signal === void 0 ? [] : [options.signal],
|
|
8497
|
+
onUsage: (delta) => options.budget?.onUsage(delta, target.resolved.ref)
|
|
8498
|
+
};
|
|
8499
|
+
if (options.budget?.signal !== void 0) summarizeStreamOptions.budgetSignal = options.budget.signal;
|
|
8500
|
+
return summarizeStreamOptions;
|
|
8501
|
+
}
|
|
8502
|
+
});
|
|
8503
|
+
} catch (thrown) {
|
|
8504
|
+
if (!(thrown instanceof BudgetExhaustedError)) throw thrown;
|
|
8505
|
+
status = "error";
|
|
8506
|
+
agentError = {
|
|
8507
|
+
kind: "budget",
|
|
8508
|
+
retryable: false
|
|
8509
|
+
};
|
|
8510
|
+
errorMessage = thrown.message;
|
|
8511
|
+
break;
|
|
8512
|
+
}
|
|
8513
|
+
const { outcome: summary } = summaryDispatch;
|
|
8373
8514
|
usageApprox = usageApprox || summary.usageApprox;
|
|
8374
8515
|
if (summary.aborted === "budget") {
|
|
8375
8516
|
status = "cancelled";
|
|
@@ -8404,6 +8545,28 @@ async function runAgent(options) {
|
|
|
8404
8545
|
await saveBoundary();
|
|
8405
8546
|
continue loop;
|
|
8406
8547
|
}
|
|
8548
|
+
if (options.terminalTool !== void 0) {
|
|
8549
|
+
noProgress.recordTurn({ toolCalls: 0 });
|
|
8550
|
+
if (noProgress.tripped) {
|
|
8551
|
+
status = "limit";
|
|
8552
|
+
abortClass = "no-progress";
|
|
8553
|
+
agentError = {
|
|
8554
|
+
kind: "terminal",
|
|
8555
|
+
retryable: false
|
|
8556
|
+
};
|
|
8557
|
+
errorMessage = noProgress.describe();
|
|
8558
|
+
break;
|
|
8559
|
+
}
|
|
8560
|
+
messages.push({
|
|
8561
|
+
role: "user",
|
|
8562
|
+
parts: [{
|
|
8563
|
+
type: "text",
|
|
8564
|
+
text: outcome.finish?.reason === "max-tokens" ? `The turn was cut at the output token limit before any tool call. Be brief and call the '${options.terminalTool.name}' tool now; plain text is not a valid completion.` : `The turn ended without a tool call. Call the '${options.terminalTool.name}' tool to complete; plain text is not a valid completion.`
|
|
8565
|
+
}]
|
|
8566
|
+
});
|
|
8567
|
+
await saveBoundary();
|
|
8568
|
+
continue loop;
|
|
8569
|
+
}
|
|
8407
8570
|
if (options.schema === void 0) {
|
|
8408
8571
|
output = outcome.turn.text;
|
|
8409
8572
|
break;
|
|
@@ -8473,66 +8636,80 @@ async function runAgent(options) {
|
|
|
8473
8636
|
}
|
|
8474
8637
|
if (proceed) {
|
|
8475
8638
|
turns += 1;
|
|
8476
|
-
|
|
8477
|
-
|
|
8478
|
-
|
|
8479
|
-
|
|
8480
|
-
|
|
8481
|
-
|
|
8482
|
-
|
|
8483
|
-
|
|
8484
|
-
|
|
8485
|
-
|
|
8486
|
-
|
|
8487
|
-
|
|
8488
|
-
|
|
8489
|
-
|
|
8490
|
-
|
|
8491
|
-
|
|
8492
|
-
|
|
8493
|
-
|
|
8494
|
-
|
|
8495
|
-
delta
|
|
8496
|
-
|
|
8497
|
-
|
|
8498
|
-
|
|
8499
|
-
|
|
8500
|
-
|
|
8501
|
-
|
|
8502
|
-
|
|
8639
|
+
let finalizeDispatch;
|
|
8640
|
+
try {
|
|
8641
|
+
finalizeDispatch = await dispatchPhase({
|
|
8642
|
+
chain: [{
|
|
8643
|
+
adapter: options.finalize.adapter,
|
|
8644
|
+
resolved: options.finalize.resolved
|
|
8645
|
+
}, ...options.finalize.fallbacks ?? []],
|
|
8646
|
+
cursor: { index: 0 },
|
|
8647
|
+
requestFor: (target) => applyOutputBudget({
|
|
8648
|
+
...buildRequest(target.resolved, projectHistory(messages, providerOf(target.adapter)), limits, options.tools?.contracts),
|
|
8649
|
+
toolChoice: "none"
|
|
8650
|
+
}, target, options.budget),
|
|
8651
|
+
streamOptionsFor: (target) => {
|
|
8652
|
+
const finalizeStreamOptions = {
|
|
8653
|
+
idleTimeoutMs: limits.streamIdleTimeoutMs,
|
|
8654
|
+
signals: options.signal === void 0 ? [] : [options.signal],
|
|
8655
|
+
onUsage: (delta) => options.budget?.onUsage(delta, target.resolved.ref)
|
|
8656
|
+
};
|
|
8657
|
+
if (options.budget?.signal !== void 0) finalizeStreamOptions.budgetSignal = options.budget.signal;
|
|
8658
|
+
if (options.stream === true) finalizeStreamOptions.onDelta = (delta) => events?.emit({
|
|
8659
|
+
type: "agent:stream",
|
|
8660
|
+
delta
|
|
8661
|
+
});
|
|
8662
|
+
return finalizeStreamOptions;
|
|
8663
|
+
}
|
|
8664
|
+
});
|
|
8665
|
+
} catch (thrown) {
|
|
8666
|
+
if (!(thrown instanceof BudgetExhaustedError)) throw thrown;
|
|
8503
8667
|
status = "error";
|
|
8504
8668
|
agentError = {
|
|
8505
|
-
kind: "
|
|
8669
|
+
kind: "budget",
|
|
8506
8670
|
retryable: false
|
|
8507
8671
|
};
|
|
8508
|
-
errorMessage =
|
|
8509
|
-
}
|
|
8510
|
-
|
|
8511
|
-
|
|
8512
|
-
|
|
8513
|
-
|
|
8514
|
-
|
|
8515
|
-
status = "
|
|
8672
|
+
errorMessage = thrown.message;
|
|
8673
|
+
}
|
|
8674
|
+
if (finalizeDispatch !== void 0) {
|
|
8675
|
+
const { outcome, target: finalizeTarget } = finalizeDispatch;
|
|
8676
|
+
usageApprox = usageApprox || outcome.usageApprox;
|
|
8677
|
+
messages.push(assistantMsg(outcome.turn, liftRetainedParts(outcome.providerMetadata, finalizeTarget.adapter)));
|
|
8678
|
+
if (invariantViolation !== void 0) {
|
|
8679
|
+
status = "error";
|
|
8516
8680
|
agentError = {
|
|
8517
|
-
kind: "
|
|
8681
|
+
kind: "transport",
|
|
8518
8682
|
retryable: false
|
|
8519
8683
|
};
|
|
8520
|
-
|
|
8684
|
+
errorMessage = invariantViolation;
|
|
8685
|
+
} else if (outcome.aborted !== void 0 || outcome.wireError !== void 0) {
|
|
8686
|
+
status = outcome.aborted === "external" ? "cancelled" : "error";
|
|
8687
|
+
if (outcome.wireError !== void 0) {
|
|
8688
|
+
agentError = classifyWireError(outcome.wireError);
|
|
8689
|
+
errorMessage = outcome.wireError.message;
|
|
8690
|
+
} else if (outcome.aborted === "budget") {
|
|
8691
|
+
status = "cancelled";
|
|
8692
|
+
agentError = {
|
|
8693
|
+
kind: "budget",
|
|
8694
|
+
retryable: false
|
|
8695
|
+
};
|
|
8696
|
+
} else if (outcome.aborted === "idle") {
|
|
8697
|
+
status = "error";
|
|
8698
|
+
agentError = {
|
|
8699
|
+
kind: "transport",
|
|
8700
|
+
retryable: true
|
|
8701
|
+
};
|
|
8702
|
+
errorMessage = `stream idle for ${limits.streamIdleTimeoutMs}ms`;
|
|
8703
|
+
}
|
|
8704
|
+
} else if (outcome.finish?.reason === "refusal" || outcome.finish?.reason === "context-window-exceeded") {
|
|
8521
8705
|
status = "error";
|
|
8522
8706
|
agentError = {
|
|
8523
|
-
kind: "
|
|
8524
|
-
retryable:
|
|
8707
|
+
kind: "terminal",
|
|
8708
|
+
retryable: false
|
|
8525
8709
|
};
|
|
8526
|
-
errorMessage = `
|
|
8527
|
-
}
|
|
8528
|
-
}
|
|
8529
|
-
status = "error";
|
|
8530
|
-
agentError = {
|
|
8531
|
-
kind: "terminal",
|
|
8532
|
-
retryable: false
|
|
8533
|
-
};
|
|
8534
|
-
if (outcome.finish.reason === "refusal") errorMessage = `model refusal (${outcome.finish.refusal.provider})`;
|
|
8535
|
-
} else if (options.schema === void 0) output = outcome.turn.text;
|
|
8710
|
+
if (outcome.finish.reason === "refusal") errorMessage = `model refusal (${outcome.finish.refusal.provider})`;
|
|
8711
|
+
} else if (options.schema === void 0) output = outcome.turn.text;
|
|
8712
|
+
}
|
|
8536
8713
|
}
|
|
8537
8714
|
}
|
|
8538
8715
|
if (status === "ok" && !finishedViaTool && separateExtract && options.extract !== void 0 && options.schema !== void 0) {
|
|
@@ -8570,28 +8747,42 @@ async function runAgent(options) {
|
|
|
8570
8747
|
break;
|
|
8571
8748
|
}
|
|
8572
8749
|
turns += 1;
|
|
8573
|
-
|
|
8574
|
-
|
|
8575
|
-
|
|
8576
|
-
|
|
8577
|
-
|
|
8578
|
-
|
|
8579
|
-
|
|
8580
|
-
|
|
8581
|
-
|
|
8582
|
-
|
|
8583
|
-
|
|
8584
|
-
|
|
8585
|
-
|
|
8586
|
-
|
|
8587
|
-
|
|
8588
|
-
|
|
8589
|
-
|
|
8590
|
-
|
|
8591
|
-
|
|
8592
|
-
|
|
8593
|
-
|
|
8594
|
-
|
|
8750
|
+
let extractDispatch;
|
|
8751
|
+
try {
|
|
8752
|
+
extractDispatch = await dispatchPhase({
|
|
8753
|
+
chain: extractChain,
|
|
8754
|
+
cursor: extractCursor,
|
|
8755
|
+
requestFor: (target) => {
|
|
8756
|
+
const targetTier = extractTierFor(target);
|
|
8757
|
+
let req = buildRequest(target.resolved, projectHistory(extractMessages, providerOf(target.adapter)), limits, options.tools?.contracts);
|
|
8758
|
+
if (req.tools !== void 0 && targetTier !== "forced-tool") req = {
|
|
8759
|
+
...req,
|
|
8760
|
+
toolChoice: "none"
|
|
8761
|
+
};
|
|
8762
|
+
req = applyStructuredOutputTier(req, targetTier, options.canonicalSchema ?? {});
|
|
8763
|
+
return applyOutputBudget(req, target, options.budget);
|
|
8764
|
+
},
|
|
8765
|
+
streamOptionsFor: (target) => {
|
|
8766
|
+
const extractStreamOptions = {
|
|
8767
|
+
idleTimeoutMs: limits.streamIdleTimeoutMs,
|
|
8768
|
+
signals: options.signal === void 0 ? [] : [options.signal],
|
|
8769
|
+
onUsage: (delta) => options.budget?.onUsage(delta, target.resolved.ref)
|
|
8770
|
+
};
|
|
8771
|
+
if (options.budget?.signal !== void 0) extractStreamOptions.budgetSignal = options.budget.signal;
|
|
8772
|
+
return extractStreamOptions;
|
|
8773
|
+
}
|
|
8774
|
+
});
|
|
8775
|
+
} catch (thrown) {
|
|
8776
|
+
if (!(thrown instanceof BudgetExhaustedError)) throw thrown;
|
|
8777
|
+
status = "error";
|
|
8778
|
+
agentError = {
|
|
8779
|
+
kind: "budget",
|
|
8780
|
+
retryable: false
|
|
8781
|
+
};
|
|
8782
|
+
errorMessage = thrown.message;
|
|
8783
|
+
break;
|
|
8784
|
+
}
|
|
8785
|
+
const { outcome, target: extractTarget } = extractDispatch;
|
|
8595
8786
|
usageApprox = usageApprox || outcome.usageApprox;
|
|
8596
8787
|
if (invariantViolation !== void 0) {
|
|
8597
8788
|
status = "error";
|
|
@@ -8674,10 +8865,16 @@ async function runAgent(options) {
|
|
|
8674
8865
|
//#region src/engine/budget.ts
|
|
8675
8866
|
/**
|
|
8676
8867
|
* Three-layer budget (M1-T09, hierarchical sub-accounts M6-T06;
|
|
8677
|
-
* invariant I4). Layer 1: admission before spawn
|
|
8678
|
-
*
|
|
8679
|
-
*
|
|
8680
|
-
*
|
|
8868
|
+
* invariant I4). Layer 1: PROJECTED admission before spawn: a spawn is
|
|
8869
|
+
* admitted only when spent + committedReserve + finalizeReserve + the
|
|
8870
|
+
* PROPOSED reserve fits the ceiling of EVERY account in the ancestor
|
|
8871
|
+
* chain (exact fill allowed), checked atomically before any commit.
|
|
8872
|
+
* Layer 2: the per-turn guard against the spawn's own chain, plus the
|
|
8873
|
+
* pre-dispatch output bound (layer 2b): every turn's maxOutputTokens is
|
|
8874
|
+
* clamped to what the remaining chain budget affords from the serving
|
|
8875
|
+
* model, and a turn that cannot afford one output token is denied before
|
|
8876
|
+
* dispatch. Layer 3: the AbortSignal ceiling severing live streams, with
|
|
8877
|
+
* partial usage written usageApprox.
|
|
8681
8878
|
* B0 is immutable after start: no API tops it up.
|
|
8682
8879
|
*
|
|
8683
8880
|
* The account tree: the run root plus one
|
|
@@ -8702,15 +8899,27 @@ const ZERO_USAGE = {
|
|
|
8702
8899
|
cacheWriteTokens: 0
|
|
8703
8900
|
};
|
|
8704
8901
|
/**
|
|
8705
|
-
* The admission reserve for a spawn: opts.estCost, else profile.estCost,
|
|
8706
|
-
* price(countTokens(input) +
|
|
8707
|
-
* default.
|
|
8902
|
+
* The admission reserve for a spawn: opts.estCost, else profile.estCost,
|
|
8903
|
+
* else price(countTokens(input) + one turn's worth of output), else the
|
|
8904
|
+
* engine flat default. The output term is caps.maxOutputTokens clamped to
|
|
8905
|
+
* limits.maxOutputTokensPerTurn when the spawn carries one, so a host can
|
|
8906
|
+
* bound reserves without hand-written estimates. The priced path uses the
|
|
8907
|
+
* SAME price function as settlement (priceUsdOf), so long-context tiers
|
|
8908
|
+
* apply to estimates too.
|
|
8708
8909
|
*/
|
|
8709
8910
|
function admissionReserveUsd(options) {
|
|
8710
8911
|
if (options.estCost !== void 0) return options.estCost;
|
|
8711
8912
|
if (options.profileEstCost !== void 0) return options.profileEstCost;
|
|
8712
8913
|
const pricing = options.caps?.pricing;
|
|
8713
|
-
if (options.inputTokens !== void 0 && pricing !== void 0 && options.caps !== void 0)
|
|
8914
|
+
if (options.inputTokens !== void 0 && pricing !== void 0 && options.caps !== void 0) {
|
|
8915
|
+
const outputTokens = options.maxOutputTokensPerTurn === void 0 ? options.caps.maxOutputTokens : Math.min(options.caps.maxOutputTokens, options.maxOutputTokensPerTurn);
|
|
8916
|
+
return priceUsdOf(pricing, {
|
|
8917
|
+
inputTokens: options.inputTokens,
|
|
8918
|
+
outputTokens,
|
|
8919
|
+
cacheReadTokens: 0,
|
|
8920
|
+
cacheWriteTokens: 0
|
|
8921
|
+
});
|
|
8922
|
+
}
|
|
8714
8923
|
return options.flatReserveUsd ?? .5;
|
|
8715
8924
|
}
|
|
8716
8925
|
/**
|
|
@@ -8725,6 +8934,7 @@ var RunBudget = class {
|
|
|
8725
8934
|
lifetimeSpawnCap;
|
|
8726
8935
|
events;
|
|
8727
8936
|
priceUsd;
|
|
8937
|
+
pricingOf;
|
|
8728
8938
|
accounts = /* @__PURE__ */ new Map();
|
|
8729
8939
|
usageInternal = { ...ZERO_USAGE };
|
|
8730
8940
|
agentsSpawnedInternal = 0;
|
|
@@ -8736,6 +8946,7 @@ var RunBudget = class {
|
|
|
8736
8946
|
this.lifetimeSpawnCap = options.lifetimeSpawnCap ?? 500;
|
|
8737
8947
|
if (options.events !== void 0) this.events = options.events;
|
|
8738
8948
|
if (options.priceUsd !== void 0) this.priceUsd = options.priceUsd;
|
|
8949
|
+
if (options.pricingOf !== void 0) this.pricingOf = options.pricingOf;
|
|
8739
8950
|
const root = {
|
|
8740
8951
|
scope: "run",
|
|
8741
8952
|
spentUsd: 0,
|
|
@@ -8788,8 +8999,43 @@ var RunBudget = class {
|
|
|
8788
8999
|
controller: new AbortController()
|
|
8789
9000
|
};
|
|
8790
9001
|
if (options.ceilingUsd !== void 0) account.ceilingUsd = options.ceilingUsd;
|
|
9002
|
+
if (options.kind !== void 0) account.kind = options.kind;
|
|
8791
9003
|
this.accounts.set(scope, account);
|
|
8792
9004
|
}
|
|
9005
|
+
/**
|
|
9006
|
+
* The diagnostic projection behind a ceiling error: the first CLOSED
|
|
9007
|
+
* account (projected commitments included, exactly the layer-1
|
|
9008
|
+
* closure test) walking from `scope` toward the root, plus the root
|
|
9009
|
+
* state. 'run budget ceiling reached' under a healthy root misled the
|
|
9010
|
+
* v1.6.0 follow-up review's live probe when only a 0.18 USD
|
|
9011
|
+
* orchestrator cap had crossed under a 0.90 USD root; the message can
|
|
9012
|
+
* now name the account that actually ended the work. An unknown scope
|
|
9013
|
+
* degrades to root-only diagnostics instead of throwing: this runs on
|
|
9014
|
+
* the error path.
|
|
9015
|
+
*/
|
|
9016
|
+
exhaustionDiagnostics(scope) {
|
|
9017
|
+
let chain;
|
|
9018
|
+
try {
|
|
9019
|
+
chain = this.chainOf(scope);
|
|
9020
|
+
} catch {
|
|
9021
|
+
chain = [this.root];
|
|
9022
|
+
}
|
|
9023
|
+
const crossed = chain.find((account) => account.ceilingUsd !== void 0 && account.spentUsd + account.committedReserveUsd + account.finalizeReserveUsd >= account.ceilingUsd);
|
|
9024
|
+
const root = this.root;
|
|
9025
|
+
const diagnostics = { root: {
|
|
9026
|
+
spentUsd: root.spentUsd,
|
|
9027
|
+
...root.ceilingUsd === void 0 ? {} : { ceilingUsd: root.ceilingUsd }
|
|
9028
|
+
} };
|
|
9029
|
+
if (crossed?.ceilingUsd !== void 0) diagnostics.crossed = {
|
|
9030
|
+
scope: crossed.scope,
|
|
9031
|
+
source: crossed.scope === "run" ? "root" : crossed.kind === "orchestrator-cap" ? "orchestrator-cap" : "child-account",
|
|
9032
|
+
ceilingUsd: crossed.ceilingUsd,
|
|
9033
|
+
spentUsd: crossed.spentUsd,
|
|
9034
|
+
committedReserveUsd: crossed.committedReserveUsd,
|
|
9035
|
+
finalizeReserveUsd: crossed.finalizeReserveUsd
|
|
9036
|
+
};
|
|
9037
|
+
return diagnostics;
|
|
9038
|
+
}
|
|
8793
9039
|
accountView(scope) {
|
|
8794
9040
|
const account = this.accounts.get(scope);
|
|
8795
9041
|
if (account === void 0) return;
|
|
@@ -8841,9 +9087,15 @@ var RunBudget = class {
|
|
|
8841
9087
|
return Math.max(0, this.lifetimeSpawnCap - this.agentsSpawnedInternal);
|
|
8842
9088
|
}
|
|
8843
9089
|
/**
|
|
8844
|
-
* Layer 1: admission before spawn.
|
|
8845
|
-
*
|
|
8846
|
-
*
|
|
9090
|
+
* Layer 1: PROJECTED admission before spawn. A spawn is admitted only
|
|
9091
|
+
* when every account in the ancestor chain of `accountScope` still has
|
|
9092
|
+
* admission headroom AND fits the PROPOSED reserve on top of spent +
|
|
9093
|
+
* committedReserve + finalizeReserve (the finalize reserve is
|
|
9094
|
+
* untouchable by admission, DEF-7). An exact fill is allowed; one
|
|
9095
|
+
* dollar past the ceiling is not: a spawn is never admitted on the
|
|
9096
|
+
* argument that the money it needs is merely not committed yet. The
|
|
9097
|
+
* whole chain is checked before anything commits, so a rejection
|
|
9098
|
+
* mutates no account, increments no counter, and journals nothing.
|
|
8847
9099
|
* Also enforces the engine lifetime spawn cap.
|
|
8848
9100
|
*/
|
|
8849
9101
|
admitSpawn(reserveUsd, accountScope = "run") {
|
|
@@ -8852,14 +9104,19 @@ var RunBudget = class {
|
|
|
8852
9104
|
throw new BudgetExhaustedError(`engine lifetime spawn cap reached (${this.lifetimeSpawnCap} spawns per run; budgetDefaults.lifetimeSpawnCap)`, { data: { cap: this.lifetimeSpawnCap } });
|
|
8853
9105
|
}
|
|
8854
9106
|
const chain = this.chainOf(accountScope);
|
|
8855
|
-
for (const account of chain)
|
|
8856
|
-
if (account.
|
|
8857
|
-
|
|
8858
|
-
|
|
8859
|
-
|
|
8860
|
-
|
|
8861
|
-
|
|
8862
|
-
|
|
9107
|
+
for (const account of chain) {
|
|
9108
|
+
if (account.ceilingUsd === void 0) continue;
|
|
9109
|
+
const committed = account.spentUsd + account.committedReserveUsd + account.finalizeReserveUsd;
|
|
9110
|
+
if (committed >= account.ceilingUsd || committed + reserveUsd > account.ceilingUsd) {
|
|
9111
|
+
if (account.scope === "run") this.exhaustedInternal = true;
|
|
9112
|
+
throw new BudgetExhaustedError(`budget ceiling reached on account '${account.scope}': spent ${account.spentUsd.toFixed(4)} USD plus committed reserves ${(account.committedReserveUsd + account.finalizeReserveUsd).toFixed(4)} USD plus the proposed reserve ${reserveUsd.toFixed(4)} USD does not fit the ceiling ${account.ceilingUsd.toFixed(4)} USD`, { data: {
|
|
9113
|
+
account: account.scope,
|
|
9114
|
+
spentUsd: account.spentUsd,
|
|
9115
|
+
committedReserveUsd: account.committedReserveUsd,
|
|
9116
|
+
proposedReserveUsd: reserveUsd,
|
|
9117
|
+
ceilingUsd: account.ceilingUsd
|
|
9118
|
+
} });
|
|
9119
|
+
}
|
|
8863
9120
|
}
|
|
8864
9121
|
this.agentsSpawnedInternal += 1;
|
|
8865
9122
|
for (const account of chain) account.committedReserveUsd += reserveUsd;
|
|
@@ -8921,6 +9178,28 @@ var RunBudget = class {
|
|
|
8921
9178
|
}
|
|
8922
9179
|
}
|
|
8923
9180
|
/**
|
|
9181
|
+
* Layer 2b, the pre-dispatch output bound: the output tokens the
|
|
9182
|
+
* remaining chain budget (min over capped ancestors of ceiling minus
|
|
9183
|
+
* spend) still affords from `servedBy` for an estimated prompt, priced
|
|
9184
|
+
* by the same function as settlement, long-context tiers included.
|
|
9185
|
+
* Undefined when no account in the chain carries a USD ceiling, when
|
|
9186
|
+
* the model has no price row (the once-per-model unpriced warning in
|
|
9187
|
+
* onUsage covers that hole), or when output is free. Zero or negative
|
|
9188
|
+
* means the turn cannot be dispatched within the budget.
|
|
9189
|
+
*/
|
|
9190
|
+
maxAffordableOutputTokens(servedBy, estimatedInputTokens, accountScope = "run") {
|
|
9191
|
+
const pricing = this.pricingOf?.(servedBy);
|
|
9192
|
+
if (pricing === void 0) return;
|
|
9193
|
+
let remainingUsd;
|
|
9194
|
+
for (const account of this.chainOf(accountScope)) {
|
|
9195
|
+
if (account.ceilingUsd === void 0) continue;
|
|
9196
|
+
const headroom = account.ceilingUsd - account.spentUsd;
|
|
9197
|
+
remainingUsd = remainingUsd === void 0 ? headroom : Math.min(remainingUsd, headroom);
|
|
9198
|
+
}
|
|
9199
|
+
if (remainingUsd === void 0) return;
|
|
9200
|
+
return affordableOutputTokens(pricing, Math.max(0, remainingUsd), estimatedInputTokens);
|
|
9201
|
+
}
|
|
9202
|
+
/**
|
|
8924
9203
|
* Live accounting; spend propagates from `accountScope` to every
|
|
8925
9204
|
* ancestor. Crossing a ceiling severs the crossing account's subtree
|
|
8926
9205
|
* via its layer-3 AbortSignal (overshoot bounded by one turn per
|
|
@@ -9193,13 +9472,16 @@ var AdmissionController = class {
|
|
|
9193
9472
|
},
|
|
9194
9473
|
statsBefore
|
|
9195
9474
|
};
|
|
9196
|
-
|
|
9197
|
-
const reserve = { reserveUsd };
|
|
9475
|
+
let childCeilingUsd;
|
|
9198
9476
|
const parentRemainder = this.budget.remainderOf(spec.parentAccountScope);
|
|
9199
9477
|
if (parentRemainder !== void 0) {
|
|
9200
9478
|
const fractionCap = this.childBudgetFraction * parentRemainder;
|
|
9201
|
-
|
|
9202
|
-
} else if (spec.budgetUsd !== void 0)
|
|
9479
|
+
childCeilingUsd = spec.budgetUsd === void 0 ? fractionCap : Math.min(spec.budgetUsd, fractionCap);
|
|
9480
|
+
} else if (spec.budgetUsd !== void 0) childCeilingUsd = spec.budgetUsd;
|
|
9481
|
+
let reserveUsd = spec.estCostUsd ?? this.flatReserveUsd;
|
|
9482
|
+
if (childCeilingUsd !== void 0) reserveUsd = Math.min(reserveUsd, childCeilingUsd);
|
|
9483
|
+
const reserve = { reserveUsd };
|
|
9484
|
+
if (childCeilingUsd !== void 0) reserve.childCeilingUsd = childCeilingUsd;
|
|
9203
9485
|
if (this.budget.spawnHeadroom <= 0) return {
|
|
9204
9486
|
verdict: {
|
|
9205
9487
|
kind: "reject",
|
|
@@ -9601,6 +9883,13 @@ const kTerminalTool = Symbol("rulvar.terminalTool");
|
|
|
9601
9883
|
* graft boot). Dangling redispatch checkpoints take precedence.
|
|
9602
9884
|
*/
|
|
9603
9885
|
const kBootCheckpoint = Symbol("rulvar.bootCheckpoint");
|
|
9886
|
+
/**
|
|
9887
|
+
* Internal AgentOpts channel: marks the orchestrator forced-finish
|
|
9888
|
+
* dispatch, whose spend draws from the released finalize reserve
|
|
9889
|
+
* (DEF-7). Settlement stamps the flag into the terminal's cost
|
|
9890
|
+
* attribution so the journal fold reproduces reserveUsedUsd.
|
|
9891
|
+
*/
|
|
9892
|
+
const kFinalizeReserve = Symbol("rulvar.finalizeReserve");
|
|
9604
9893
|
/** Typed accessor used by the in-package consumers. */
|
|
9605
9894
|
function runtimeOf(ctx) {
|
|
9606
9895
|
const runtime = ctxRuntimes.get(ctx);
|
|
@@ -10172,6 +10461,7 @@ function createCtx(internals, rootWorkflow) {
|
|
|
10172
10461
|
}
|
|
10173
10462
|
const adapter = adapterOf(loopResolved);
|
|
10174
10463
|
const caps = adapter.caps(loopResolved.model);
|
|
10464
|
+
const limits = mergeUsageLimits(opts.limits, profile?.limits, internals.defaults.limits);
|
|
10175
10465
|
let inputTokens;
|
|
10176
10466
|
if (opts.estCost === void 0 && profile?.estCost === void 0 && adapter.countTokens) try {
|
|
10177
10467
|
inputTokens = await adapter.countTokens({
|
|
@@ -10191,8 +10481,9 @@ function createCtx(internals, rootWorkflow) {
|
|
|
10191
10481
|
if (opts.estCost !== void 0) reserveOptions.estCost = opts.estCost;
|
|
10192
10482
|
if (profile?.estCost !== void 0) reserveOptions.profileEstCost = profile.estCost;
|
|
10193
10483
|
if (inputTokens !== void 0) reserveOptions.inputTokens = inputTokens;
|
|
10484
|
+
if (limits.maxOutputTokensPerTurn !== void 0) reserveOptions.maxOutputTokensPerTurn = limits.maxOutputTokensPerTurn;
|
|
10194
10485
|
if (internals.flatReserveUsd !== void 0) reserveOptions.flatReserveUsd = internals.flatReserveUsd;
|
|
10195
|
-
const reserve = admissionReserveUsd(reserveOptions);
|
|
10486
|
+
const reserve = internals.pricingOf !== void 0 && internals.pricingOf(loopResolved.ref) === void 0 && opts.estCost === void 0 && profile?.estCost === void 0 ? 0 : admissionReserveUsd(reserveOptions);
|
|
10196
10487
|
const budgetAccount = state.budgetScope ?? "run";
|
|
10197
10488
|
internals.budget.admitSpawn(reserve, budgetAccount);
|
|
10198
10489
|
let acquired;
|
|
@@ -10222,7 +10513,6 @@ function createCtx(internals, rootWorkflow) {
|
|
|
10222
10513
|
running = await internals.replayer.appendRunning(runningInput);
|
|
10223
10514
|
}
|
|
10224
10515
|
opts[kOnRunning]?.(running.seq);
|
|
10225
|
-
const limits = mergeUsageLimits(opts.limits, profile?.limits, internals.defaults.limits);
|
|
10226
10516
|
const agentSink = { emit: (body) => internals.events.emit(body, spanId) };
|
|
10227
10517
|
const ckptRef = checkpointRefFor(internals.runId, running.seq);
|
|
10228
10518
|
let checkpointWritten = false;
|
|
@@ -10338,6 +10628,7 @@ function createCtx(internals, rootWorkflow) {
|
|
|
10338
10628
|
},
|
|
10339
10629
|
budget: {
|
|
10340
10630
|
beforeTurn: () => internals.budget.beforeTurn(budgetAccount),
|
|
10631
|
+
maxAffordableOutputTokens: (servedBy, estimatedInputTokens) => internals.budget.maxAffordableOutputTokens(servedBy, estimatedInputTokens, budgetAccount),
|
|
10341
10632
|
onUsage: (usage, servedBy) => internals.budget.onUsage(usage, servedBy, budgetAccount),
|
|
10342
10633
|
signal: budgetAccount === "run" ? internals.budget.signal : AbortSignal.any([internals.budget.signal, internals.budget.signalOf(budgetAccount)].filter((signal) => signal !== void 0))
|
|
10343
10634
|
},
|
|
@@ -10461,6 +10752,13 @@ function createCtx(internals, rootWorkflow) {
|
|
|
10461
10752
|
usage: result.usage,
|
|
10462
10753
|
servedBy: result.servedBy,
|
|
10463
10754
|
...result.usageByModel === void 0 ? {} : { usageByModel: result.usageByModel },
|
|
10755
|
+
costAttribution: {
|
|
10756
|
+
...state.phase === void 0 ? {} : { phase: state.phase },
|
|
10757
|
+
agentType,
|
|
10758
|
+
role: primaryRole,
|
|
10759
|
+
budgetAccount: state.budgetScope ?? "run",
|
|
10760
|
+
...opts[kFinalizeReserve] === true ? { finalizeReserve: true } : {}
|
|
10761
|
+
},
|
|
10464
10762
|
transcriptRef: result.transcriptRef
|
|
10465
10763
|
};
|
|
10466
10764
|
if (result.status === "escalated" && result.escalation !== void 0) terminalPatch.escalation = result.escalation;
|
|
@@ -10528,10 +10826,25 @@ function createCtx(internals, rootWorkflow) {
|
|
|
10528
10826
|
bump(internals.cost.byPhase, state.phase ?? "", usd);
|
|
10529
10827
|
bump(internals.cost.byAgentType, agentType, usd);
|
|
10530
10828
|
internals.cost.byRole.set(primaryRole, (internals.cost.byRole.get(primaryRole) ?? 0) + usd);
|
|
10531
|
-
if (result.error?.kind === "budget" || internals.budget.exhausted && result.status !== "ok")
|
|
10532
|
-
|
|
10533
|
-
|
|
10534
|
-
|
|
10829
|
+
if (result.error?.kind === "budget" || internals.budget.exhausted && result.status !== "ok") {
|
|
10830
|
+
const diagnostics = internals.budget.exhaustionDiagnostics(state.budgetScope ?? "run");
|
|
10831
|
+
const crossed = diagnostics.crossed;
|
|
10832
|
+
const rootSuffix = `run root: spent ${diagnostics.root.spentUsd.toFixed(4)}` + (diagnostics.root.ceilingUsd === void 0 ? " USD, no ceiling" : ` of ${diagnostics.root.ceilingUsd.toFixed(4)} USD`);
|
|
10833
|
+
throw new BudgetExhaustedError(crossed === void 0 || crossed.source === "root" ? "run budget ceiling reached during agent execution" : (crossed.source === "orchestrator-cap" ? "orchestrator budget cap reached during agent execution" : "budget sub-account ceiling reached during agent execution") + ` (account '${crossed.scope}': spent ${crossed.spentUsd.toFixed(4)}` + (crossed.committedReserveUsd + crossed.finalizeReserveUsd > 0 ? ` plus ${(crossed.committedReserveUsd + crossed.finalizeReserveUsd).toFixed(4)} reserved` : "") + ` of ${crossed.ceilingUsd.toFixed(4)} USD; ${rootSuffix})`, { data: {
|
|
10834
|
+
scope: state.scope,
|
|
10835
|
+
entryRef: terminal.seq,
|
|
10836
|
+
source: crossed?.source ?? "root",
|
|
10837
|
+
rootSpentUsd: diagnostics.root.spentUsd,
|
|
10838
|
+
...diagnostics.root.ceilingUsd === void 0 ? {} : { rootCeilingUsd: diagnostics.root.ceilingUsd },
|
|
10839
|
+
...crossed === void 0 ? {} : {
|
|
10840
|
+
crossedScope: crossed.scope,
|
|
10841
|
+
crossedCeilingUsd: crossed.ceilingUsd,
|
|
10842
|
+
crossedSpentUsd: crossed.spentUsd,
|
|
10843
|
+
crossedCommittedReserveUsd: crossed.committedReserveUsd,
|
|
10844
|
+
crossedFinalizeReserveUsd: crossed.finalizeReserveUsd
|
|
10845
|
+
}
|
|
10846
|
+
} });
|
|
10847
|
+
}
|
|
10535
10848
|
if (opts.fallback !== void 0) {
|
|
10536
10849
|
const trigger = fallbackTriggerOf(result);
|
|
10537
10850
|
if (trigger !== void 0 && opts.fallback.on.includes(trigger)) return runFallbackAttempt(running.seq, trigger, spanId);
|
|
@@ -11121,10 +11434,16 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
11121
11434
|
const finalizeTurns = spec?.finalizeTurns ?? 2;
|
|
11122
11435
|
const finalizeReserveUsd = spec?.finalizeReserveUsd ?? finalizeTurns * turnEstimateUsd;
|
|
11123
11436
|
if (extension !== void 0 && effectiveCapUsd < finalizeReserveUsd) throw new OrchestratorCapConfigError(`effectiveCap ${effectiveCapUsd.toFixed(4)} USD is below the finalize reserve ${finalizeReserveUsd.toFixed(4)} USD`);
|
|
11437
|
+
if (spec?.capUsd !== void 0 && spec.capFraction === void 0 && effectiveCapUsd < spec.capUsd) internals.events.emit({
|
|
11438
|
+
type: "log",
|
|
11439
|
+
level: "warn",
|
|
11440
|
+
msg: `orchestrator budget.capUsd ${spec.capUsd.toFixed(4)} USD is bounded to ${effectiveCapUsd.toFixed(4)} USD by the default capFraction 0.2 of the run ceiling (effectiveCap = min(capUsd, capFraction * ceiling)); pass capFraction: 1.0 to make capUsd the sole bound`
|
|
11441
|
+
}, callingState.spanId);
|
|
11124
11442
|
orchestratorAccount = callingState.scope === "" ? "orchestrator" : `${callingState.scope}/orchestrator`;
|
|
11125
11443
|
internals.budget.openAccount(orchestratorAccount, {
|
|
11126
11444
|
parentScope: callingState.budgetScope ?? "run",
|
|
11127
|
-
ceilingUsd: effectiveCapUsd
|
|
11445
|
+
ceilingUsd: effectiveCapUsd,
|
|
11446
|
+
kind: "orchestrator-cap"
|
|
11128
11447
|
});
|
|
11129
11448
|
if (extension !== void 0) internals.budget.commitFinalizeReserve(orchestratorAccount, finalizeReserveUsd);
|
|
11130
11449
|
capState = {
|
|
@@ -11140,6 +11459,15 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
11140
11459
|
const records = /* @__PURE__ */ new Map();
|
|
11141
11460
|
const byOrdinal = /* @__PURE__ */ new Map();
|
|
11142
11461
|
const rejectedByOrdinal = /* @__PURE__ */ new Map();
|
|
11462
|
+
/**
|
|
11463
|
+
* The journaled spec behind each recovered ordinal: the idempotent
|
|
11464
|
+
* re-execution guard compares it against the incoming call, because
|
|
11465
|
+
* after a cross-attempt resume a REGENERATED turn (the boundary
|
|
11466
|
+
* checkpoint predates the lost turn) may decide differently, and
|
|
11467
|
+
* handing it the prior ordinal's handle would bind the transcript
|
|
11468
|
+
* to a stranger's child.
|
|
11469
|
+
*/
|
|
11470
|
+
const recoveredSpecByOrdinal = /* @__PURE__ */ new Map();
|
|
11143
11471
|
let nextOrdinal = 0;
|
|
11144
11472
|
let orchSeq;
|
|
11145
11473
|
const deliveredNodeIds = /* @__PURE__ */ new Set();
|
|
@@ -11175,7 +11503,7 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
11175
11503
|
const controller = new AbortController();
|
|
11176
11504
|
const upstream = callingState.signal ?? internals.runSignal;
|
|
11177
11505
|
const scope = placement?.childScope ?? childScopeOf();
|
|
11178
|
-
if (placement
|
|
11506
|
+
if (placement?.ownAccount === true) internals.budget.openAccount(scope, {
|
|
11179
11507
|
parentScope: callingState.budgetScope ?? "run",
|
|
11180
11508
|
...placement.childCeilingUsd === void 0 ? {} : { ceilingUsd: placement.childCeilingUsd }
|
|
11181
11509
|
});
|
|
@@ -11183,7 +11511,7 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
11183
11511
|
scope,
|
|
11184
11512
|
spanId: internals.spans.mint(callingState.spanId),
|
|
11185
11513
|
signal: upstream === void 0 ? controller.signal : AbortSignal.any([upstream, controller.signal]),
|
|
11186
|
-
budgetScope: placement
|
|
11514
|
+
budgetScope: placement?.ownAccount === true ? scope : callingState.budgetScope ?? "run"
|
|
11187
11515
|
};
|
|
11188
11516
|
let resolveHandle = () => void 0;
|
|
11189
11517
|
const handlePromise = new Promise((resolve) => {
|
|
@@ -11265,6 +11593,7 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
11265
11593
|
nextOrdinal += 1;
|
|
11266
11594
|
return { handle: (await dispatchChild(spec, spawnOrdinal, identity, {
|
|
11267
11595
|
childScope,
|
|
11596
|
+
ownAccount: true,
|
|
11268
11597
|
...spec.budgetUsd === void 0 ? {} : { childCeilingUsd: spec.budgetUsd }
|
|
11269
11598
|
})).handle };
|
|
11270
11599
|
},
|
|
@@ -11295,33 +11624,61 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
11295
11624
|
handle
|
|
11296
11625
|
};
|
|
11297
11626
|
};
|
|
11298
|
-
/**
|
|
11627
|
+
/**
|
|
11628
|
+
* True when `scope` is a root-attempt scope of THIS orchestration:
|
|
11629
|
+
* agentScope(callingState.scope, n) for some dispatch seq n. Nested
|
|
11630
|
+
* orchestrations live under their own wf: child scopes and never
|
|
11631
|
+
* match a foreign calling scope.
|
|
11632
|
+
*/
|
|
11633
|
+
const scopeOfThisOrchestration = (scope) => {
|
|
11634
|
+
const prefix = callingState.scope === "" ? "" : `${callingState.scope}/`;
|
|
11635
|
+
return scope.startsWith(prefix) && /^agent:\d+$/.test(scope.slice(prefix.length));
|
|
11636
|
+
};
|
|
11637
|
+
/**
|
|
11638
|
+
* Rebuilds spawn records from the journal (the crash-resume
|
|
11639
|
+
* contract). Recovery is ORCHESTRATION-scoped, not attempt-scoped:
|
|
11640
|
+
* decisions journal at the orchestrate call's own scope, which is
|
|
11641
|
+
* stable across root attempts, so a rerun after a cancelled root
|
|
11642
|
+
* (the budget-abort shape the v1.6.0 follow-up review resumed) sees
|
|
11643
|
+
* every prior decision instead of re-deciding and re-paying.
|
|
11644
|
+
* Recovered children re-dispatch PINNED to their journaled child
|
|
11645
|
+
* scope: settled ones forward-match and replay for free, a dangling
|
|
11646
|
+
* one redispatches live (at-least-once), and a decision without a
|
|
11647
|
+
* dispatch entry rolls forward to a fresh dispatch.
|
|
11648
|
+
*/
|
|
11299
11649
|
const recover = async () => {
|
|
11300
|
-
const
|
|
11650
|
+
const currentScope = childScopeOf();
|
|
11301
11651
|
const admissions = internals.replayer.snapshot().filter((entry) => {
|
|
11302
|
-
if (entry.kind !== "decision") return false;
|
|
11652
|
+
if (entry.kind !== "decision" || entry.scope !== callingState.scope) return false;
|
|
11303
11653
|
const value = entry.value;
|
|
11304
|
-
return value?.decisionType === "spawn-admission" && (value.origin === "spawn_agent" || value.origin === "parallel_agents")
|
|
11654
|
+
return value?.decisionType === "spawn-admission" && (value.origin === "spawn_agent" || value.origin === "parallel_agents");
|
|
11305
11655
|
}).map((entry) => entry.value).sort((a, b) => a.spawnOrdinal - b.spawnOrdinal);
|
|
11306
11656
|
for (const value of admissions) {
|
|
11307
11657
|
nextOrdinal = Math.max(nextOrdinal, value.spawnOrdinal + 1);
|
|
11308
11658
|
const decision = value.decision;
|
|
11659
|
+
recoveredSpecByOrdinal.set(value.spawnOrdinal, value.spec);
|
|
11309
11660
|
if (decision.verdict.kind !== "admit") {
|
|
11310
11661
|
rejectedByOrdinal.set(value.spawnOrdinal, decision);
|
|
11311
11662
|
continue;
|
|
11312
11663
|
}
|
|
11313
|
-
admission.recoverChild(
|
|
11314
|
-
|
|
11664
|
+
admission.recoverChild(currentScope);
|
|
11665
|
+
const childScope = value.childScope ?? value.orchestratorScope;
|
|
11666
|
+
const record = await dispatchChild(value.spec, value.spawnOrdinal, {
|
|
11315
11667
|
nodeId: decision.nodeId ?? "unknown",
|
|
11316
11668
|
logicalTaskId: decision.verdict.lineage.logicalTaskId
|
|
11317
|
-
});
|
|
11669
|
+
}, { childScope });
|
|
11670
|
+
const dispatched = internals.replayer.snapshot().find((entry) => entry.seq === record.handle);
|
|
11671
|
+
if (dispatched !== void 0) {
|
|
11672
|
+
for (const prior of internals.replayer.snapshot()) if (prior.kind === "agent" && prior.status === "running" && prior.seq !== record.handle && prior.scope === dispatched.scope && prior.key === dispatched.key && prior.ordinal === dispatched.ordinal && !records.has(prior.seq)) records.set(prior.seq, record);
|
|
11673
|
+
}
|
|
11318
11674
|
}
|
|
11319
|
-
const wakePrefix = `wake:${String(orchSeq ?? -1)}:`;
|
|
11320
11675
|
for (const entry of internals.replayer.snapshot()) {
|
|
11321
11676
|
if (entry.status !== "suspended" || entry.kind !== "external") continue;
|
|
11677
|
+
if (!scopeOfThisOrchestration(entry.scope)) continue;
|
|
11322
11678
|
const payload = entry.value;
|
|
11323
|
-
|
|
11324
|
-
|
|
11679
|
+
const match = typeof payload?.key === "string" ? /^wake:\d+:(\d+)$/.exec(payload.key) : null;
|
|
11680
|
+
if (match === null) continue;
|
|
11681
|
+
wakeOrdinal = Math.max(wakeOrdinal, Number(match[1]) + 1);
|
|
11325
11682
|
const suspension = internals.replayer.suspensionState(entry.seq);
|
|
11326
11683
|
if (suspension.state === "resolved") markDelivered(suspension.value);
|
|
11327
11684
|
}
|
|
@@ -11449,10 +11806,12 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
11449
11806
|
await recoveryDone;
|
|
11450
11807
|
const spawnOrdinal = nextOrdinal;
|
|
11451
11808
|
nextOrdinal += 1;
|
|
11809
|
+
const priorSpec = recoveredSpecByOrdinal.get(spawnOrdinal);
|
|
11810
|
+
const specMatches = priorSpec === void 0 || priorSpec.agentType === params.agentType && priorSpec.prompt === params.prompt;
|
|
11452
11811
|
const recovered = byOrdinal.get(spawnOrdinal);
|
|
11453
|
-
if (recovered !== void 0) return { handle: recovered.handle };
|
|
11812
|
+
if (recovered !== void 0 && specMatches) return { handle: recovered.handle };
|
|
11454
11813
|
const recoveredRejection = rejectedByOrdinal.get(spawnOrdinal);
|
|
11455
|
-
if (recoveredRejection !== void 0) throw new AdmissionRejectedError(`admission rejected spawn ordinal ${String(spawnOrdinal)} (recovered verdict)`, { data: { decision: recoveredRejection } });
|
|
11814
|
+
if (recoveredRejection !== void 0 && specMatches) throw new AdmissionRejectedError(`admission rejected spawn ordinal ${String(spawnOrdinal)} (recovered verdict)`, { data: { decision: recoveredRejection } });
|
|
11456
11815
|
if (opts?.maxSpawns !== void 0 && spawnOrdinal >= opts.maxSpawns) {
|
|
11457
11816
|
internals.events.emit({
|
|
11458
11817
|
type: "spawn:rejected",
|
|
@@ -11702,7 +12061,7 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
11702
12061
|
role: "orchestrate",
|
|
11703
12062
|
result: "full",
|
|
11704
12063
|
tools: [...buildOrchestratorTools(orchestratorRuntime, fullCardText), ...extension?.tools(io) ?? []],
|
|
11705
|
-
...capState === void 0 ? {} : { estCost: capState.effectiveCapUsd },
|
|
12064
|
+
...capState === void 0 ? {} : { estCost: capState.effectiveCapUsd - (orchestratorAccount === void 0 ? 0 : internals.budget.accountView(orchestratorAccount)?.finalizeReserveUsd ?? 0) },
|
|
11706
12065
|
...opts?.model === void 0 ? {} : { model: opts.model },
|
|
11707
12066
|
...opts?.limits === void 0 ? {} : { limits: opts.limits },
|
|
11708
12067
|
[kOnRunning]: (seq) => {
|
|
@@ -11710,7 +12069,11 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
11710
12069
|
orchSeq = seq;
|
|
11711
12070
|
recover().then(releaseRecovery, releaseRecovery);
|
|
11712
12071
|
},
|
|
11713
|
-
[kTerminalTool]: { name: FINISH_TOOL_NAME }
|
|
12072
|
+
[kTerminalTool]: { name: FINISH_TOOL_NAME },
|
|
12073
|
+
...(() => {
|
|
12074
|
+
const priorCancelledRoot = internals.replayer.snapshot().filter((entry) => entry.kind === "agent" && entry.scope === callingState.scope && entry.status === "cancelled" && entry.checkpointRef !== void 0).at(-1);
|
|
12075
|
+
return priorCancelledRoot?.checkpointRef === void 0 ? {} : { [kBootCheckpoint]: priorCancelledRoot.checkpointRef };
|
|
12076
|
+
})()
|
|
11714
12077
|
};
|
|
11715
12078
|
const orchestratorState = { ...callingState };
|
|
11716
12079
|
if (orchestratorAccount !== void 0) orchestratorState.budgetScope = orchestratorAccount;
|
|
@@ -11736,7 +12099,8 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
11736
12099
|
limits: { maxTurns: capState?.finalizeTurns ?? 2 },
|
|
11737
12100
|
...capState === void 0 ? {} : { estCost: capState.finalizeReserveUsd },
|
|
11738
12101
|
...opts?.model === void 0 ? {} : { model: opts.model },
|
|
11739
|
-
[kTerminalTool]: { name: FINISH_TOOL_NAME }
|
|
12102
|
+
[kTerminalTool]: { name: FINISH_TOOL_NAME },
|
|
12103
|
+
[kFinalizeReserve]: true
|
|
11740
12104
|
};
|
|
11741
12105
|
const finalState = { ...callingState };
|
|
11742
12106
|
if (orchestratorAccount !== void 0) finalState.budgetScope = orchestratorAccount;
|
|
@@ -11904,13 +12268,81 @@ var EventBus = class {
|
|
|
11904
12268
|
//#endregion
|
|
11905
12269
|
//#region src/runner/inprocess.ts
|
|
11906
12270
|
/**
|
|
12271
|
+
* ScriptRunner SPI and InProcessRunner (M1-T11).
|
|
12272
|
+
*
|
|
12273
|
+
* Script runner contract: https://docs.rulvar.com/guide/planner
|
|
12274
|
+
* Workflow (a closure value) runs in process only; CompiledWorkflow is the
|
|
12275
|
+
* only form admissible to the worker sandbox and first exists at M6
|
|
12276
|
+
* (compileScript in @rulvar/planner), so until then the engine accepts
|
|
12277
|
+
* only in-process Workflow values. The SPI's L0 listing refers
|
|
12278
|
+
* to its frozen-seam status; the declaration lives here with its types.
|
|
12279
|
+
*/
|
|
12280
|
+
const detection = new AsyncLocalStorage();
|
|
12281
|
+
let globalsPatched = false;
|
|
12282
|
+
/**
|
|
12283
|
+
* Stack line 0 names the Error, line 1 this helper, line 2 the patched
|
|
12284
|
+
* global, line 3 the caller whose provenance decides (the layout is
|
|
12285
|
+
* pinned by construction: this helper is only ever called by the two
|
|
12286
|
+
* patched globals). Two origins are exempt: installed dependencies (a
|
|
12287
|
+
* provider SDK, any transitive package, rulvar's own published dist),
|
|
12288
|
+
* which live under node_modules, and Node's own machinery (the undici
|
|
12289
|
+
* transport behind fetch, timers, stream internals), whose frames carry
|
|
12290
|
+
* `node:` specifiers and inherit the run's async context. The guard
|
|
12291
|
+
* exists for workflow code, which imports from both but lives in
|
|
12292
|
+
* neither.
|
|
12293
|
+
*/
|
|
12294
|
+
function libraryCaller() {
|
|
12295
|
+
const caller = (/* @__PURE__ */ new Error()).stack?.split("\n")[3];
|
|
12296
|
+
if (caller === void 0) return false;
|
|
12297
|
+
return caller.includes("node_modules") || /[(\s]node:/.test(caller);
|
|
12298
|
+
}
|
|
12299
|
+
/**
|
|
12300
|
+
* Patches Date.now and Math.random ONCE per process and never restores:
|
|
12301
|
+
* outside a workflow's async context the store is absent and the patch is
|
|
12302
|
+
* a transparent passthrough. The previous per-execute patch/restore pair
|
|
12303
|
+
* could race under concurrent runs (one run's restore removed another's
|
|
12304
|
+
* patch, and the second restore re-installed a stale patched function
|
|
12305
|
+
* PERMANENTLY, which could then warn on host code outside any run: the
|
|
12306
|
+
* false RULVAR_BARE_DATE_NOW class the 1.5.2 review reproduced).
|
|
12307
|
+
*/
|
|
12308
|
+
function patchGlobalsOnce() {
|
|
12309
|
+
if (globalsPatched) return;
|
|
12310
|
+
globalsPatched = true;
|
|
12311
|
+
const priorNow = Date.now;
|
|
12312
|
+
const priorRandom = Math.random;
|
|
12313
|
+
Date.now = function rulvarPatchedDateNow() {
|
|
12314
|
+
const state = detection.getStore();
|
|
12315
|
+
if (state !== void 0 && !state.warnedNow && !libraryCaller()) {
|
|
12316
|
+
state.warnedNow = true;
|
|
12317
|
+
process.emitWarning("bare Date.now() called inside a rulvar run; use ctx.now() so the value is journaled and stable on replay", {
|
|
12318
|
+
code: "RULVAR_BARE_DATE_NOW",
|
|
12319
|
+
type: "RulvarWarning"
|
|
12320
|
+
});
|
|
12321
|
+
}
|
|
12322
|
+
return priorNow();
|
|
12323
|
+
};
|
|
12324
|
+
Math.random = function rulvarPatchedMathRandom() {
|
|
12325
|
+
const state = detection.getStore();
|
|
12326
|
+
if (state !== void 0 && !state.warnedRandom && !libraryCaller()) {
|
|
12327
|
+
state.warnedRandom = true;
|
|
12328
|
+
process.emitWarning("bare Math.random() called inside a rulvar run; use ctx.random() so the value is journaled and stable on replay", {
|
|
12329
|
+
code: "RULVAR_BARE_MATH_RANDOM",
|
|
12330
|
+
type: "RulvarWarning"
|
|
12331
|
+
});
|
|
12332
|
+
}
|
|
12333
|
+
return priorRandom();
|
|
12334
|
+
};
|
|
12335
|
+
}
|
|
12336
|
+
/**
|
|
11907
12337
|
* The mode (a) runner for human-authored closures. Determinism is enforced
|
|
11908
12338
|
* by convention, lint, and the ctx shims, NOT by a VM: only the sequence
|
|
11909
|
-
* of keys must be stable. Dev mode (NODE_ENV !== 'production')
|
|
11910
|
-
* Date.now and Math.random
|
|
11911
|
-
*
|
|
11912
|
-
*
|
|
11913
|
-
*
|
|
12339
|
+
* of keys must be stable. Dev mode (NODE_ENV !== 'production') detects
|
|
12340
|
+
* bare Date.now and Math.random and emits one warning per run pointing at
|
|
12341
|
+
* ctx.now()/ctx.random(). Detection is attributed by AsyncLocalStorage:
|
|
12342
|
+
* only code inside the workflow body's async context can trigger it, so
|
|
12343
|
+
* host code running concurrently, engine internals outside the body, and
|
|
12344
|
+
* other runs never produce a false warning, and nothing is ever restored,
|
|
12345
|
+
* so concurrent executes cannot race the patch state.
|
|
11914
12346
|
*/
|
|
11915
12347
|
var InProcessRunner = class {
|
|
11916
12348
|
onEscalation;
|
|
@@ -11923,47 +12355,14 @@ var InProcessRunner = class {
|
|
|
11923
12355
|
}
|
|
11924
12356
|
async execute(wf, ctx, args) {
|
|
11925
12357
|
if (wf.kind !== "workflow") throw new TypeError("InProcessRunner executes closure Workflow values only; CompiledWorkflow runs in the worker sandbox (@rulvar/planner, M6)");
|
|
11926
|
-
|
|
11927
|
-
|
|
11928
|
-
|
|
11929
|
-
|
|
11930
|
-
|
|
11931
|
-
|
|
11932
|
-
let warnedRandom = false;
|
|
11933
|
-
const libraryCaller = () => {
|
|
11934
|
-
const caller = (/* @__PURE__ */ new Error()).stack?.split("\n")[3];
|
|
11935
|
-
return caller !== void 0 && caller.includes("node_modules");
|
|
11936
|
-
};
|
|
11937
|
-
Date.now = function rulvarPatchedDateNow() {
|
|
11938
|
-
if (!warnedNow && !libraryCaller()) {
|
|
11939
|
-
warnedNow = true;
|
|
11940
|
-
process.emitWarning("bare Date.now() called inside a rulvar run; use ctx.now() so the value is journaled and stable on replay", {
|
|
11941
|
-
code: "RULVAR_BARE_DATE_NOW",
|
|
11942
|
-
type: "RulvarWarning"
|
|
11943
|
-
});
|
|
11944
|
-
}
|
|
11945
|
-
return priorNow();
|
|
11946
|
-
};
|
|
11947
|
-
Math.random = function rulvarPatchedMathRandom() {
|
|
11948
|
-
if (!warnedRandom && !libraryCaller()) {
|
|
11949
|
-
warnedRandom = true;
|
|
11950
|
-
process.emitWarning("bare Math.random() called inside a rulvar run; use ctx.random() so the value is journaled and stable on replay", {
|
|
11951
|
-
code: "RULVAR_BARE_MATH_RANDOM",
|
|
11952
|
-
type: "RulvarWarning"
|
|
11953
|
-
});
|
|
11954
|
-
}
|
|
11955
|
-
return priorRandom();
|
|
11956
|
-
};
|
|
11957
|
-
restore = () => {
|
|
11958
|
-
Date.now = priorNow;
|
|
11959
|
-
Math.random = priorRandom;
|
|
11960
|
-
};
|
|
11961
|
-
}
|
|
11962
|
-
try {
|
|
11963
|
-
return await wf.body(ctx, args);
|
|
11964
|
-
} finally {
|
|
11965
|
-
restore?.();
|
|
12358
|
+
if (process.env.NODE_ENV !== "production") {
|
|
12359
|
+
patchGlobalsOnce();
|
|
12360
|
+
return detection.run({
|
|
12361
|
+
warnedNow: false,
|
|
12362
|
+
warnedRandom: false
|
|
12363
|
+
}, () => wf.body(ctx, args));
|
|
11966
12364
|
}
|
|
12365
|
+
return await wf.body(ctx, args);
|
|
11967
12366
|
}
|
|
11968
12367
|
};
|
|
11969
12368
|
//#endregion
|
|
@@ -12000,10 +12399,13 @@ function createEngine(options) {
|
|
|
12000
12399
|
const runner = new InProcessRunner(options.onEscalation === void 0 ? void 0 : { onEscalation: options.onEscalation });
|
|
12001
12400
|
const mintRunId = createCanonicalIdMinter();
|
|
12002
12401
|
const realNow = Date.now.bind(globalThis);
|
|
12402
|
+
const pricingOf = (servedBy) => {
|
|
12403
|
+
const { adapterId, model } = parseModelRef(servedBy);
|
|
12404
|
+
return resolvePricing(servedBy, options.pricing, adapters.get(adapterId)?.caps(model).pricing);
|
|
12405
|
+
};
|
|
12003
12406
|
const priceUsd = (servedBy, usage) => {
|
|
12004
12407
|
if (servedBy === void 0) return;
|
|
12005
|
-
const
|
|
12006
|
-
const pricing = resolvePricing(servedBy, options.pricing, adapters.get(adapterId)?.caps(model).pricing);
|
|
12408
|
+
const pricing = pricingOf(servedBy);
|
|
12007
12409
|
if (pricing === void 0) return;
|
|
12008
12410
|
return priceUsdOf(pricing, usage);
|
|
12009
12411
|
};
|
|
@@ -12029,6 +12431,7 @@ function createEngine(options) {
|
|
|
12029
12431
|
lifetimeSpawnCap: options.budgetDefaults?.lifetimeSpawnCap ?? 500,
|
|
12030
12432
|
events: { emit: (body) => bus.emit(body, rootSpanId) },
|
|
12031
12433
|
priceUsd,
|
|
12434
|
+
pricingOf,
|
|
12032
12435
|
...budgetSeed === void 0 ? {} : { seed: budgetSeed }
|
|
12033
12436
|
});
|
|
12034
12437
|
const invalidated = new Set(resumeCtx?.invalidate ?? []);
|
|
@@ -12132,6 +12535,7 @@ function createEngine(options) {
|
|
|
12132
12535
|
}
|
|
12133
12536
|
},
|
|
12134
12537
|
priceUsd: (servedBy, usage) => priceUsd(servedBy, usage),
|
|
12538
|
+
pricingOf,
|
|
12135
12539
|
runSignal: controller.signal,
|
|
12136
12540
|
...defaults.isolation === void 0 ? {} : { isolation: defaults.isolation },
|
|
12137
12541
|
...options.onEscalation === void 0 ? {} : { onEscalation: options.onEscalation },
|
|
@@ -12242,7 +12646,7 @@ function createEngine(options) {
|
|
|
12242
12646
|
dropped: internals.dropped,
|
|
12243
12647
|
pending,
|
|
12244
12648
|
usage: ledger.usage,
|
|
12245
|
-
cost:
|
|
12649
|
+
cost: costReportFromJournal(replayer.snapshot(), priceUsd)
|
|
12246
12650
|
};
|
|
12247
12651
|
if (value !== void 0 && (status === "ok" || status === "exhausted")) outcome.value = value;
|
|
12248
12652
|
if (wireError !== void 0) outcome.error = wireError;
|
|
@@ -12675,4 +13079,4 @@ function createSandboxBridge(ctx, options) {
|
|
|
12675
13079
|
};
|
|
12676
13080
|
}
|
|
12677
13081
|
//#endregion
|
|
12678
|
-
export { AWAIT_SCHEMA, AdmissionController, AdmissionRejectedError, AgentCallError, BUDGET_ABORT_REASON, BudgetExhaustedError, CANCEL_AGENT_SCHEMA, CHECKPOINT_FORMAT_V1, CLAIM_STATEMENT_MAX_CHARS, CLAIM_TTL_DAYS, COMPACTION_SUMMARY_PREFIX, CURRENT_HASH_VERSION, ConfigError, DEFAULT_CHILD_BUDGET_FRACTION, DEFAULT_COMPACTION_THRESHOLD, DEFAULT_ESCALATION_LIMITS, DEFAULT_FLAT_RESERVE_USD, DEFAULT_MAX_CHILDREN_PER_NODE, DEFAULT_MAX_DEPTH, DEFAULT_MAX_OSCILLATIONS_PER_KEY, DEFAULT_MAX_PINNED_WORKTREES, DEFAULT_MAX_REVISIONS_PER_RUN, DEFAULT_MAX_TOTAL_SPAWNS, DEFAULT_MAX_TURNS, DEFAULT_MODEL_RETRY_ATTEMPTS, DEFAULT_NO_PROGRESS_TURNS, DEFAULT_PER_RUN_CONCURRENCY, DEFAULT_RETRY_POLICY, DEFAULT_STREAM_IDLE_TIMEOUT_MS, DedupIndex, EMIT_RESULT_TOOL, EMPTY_SCHEMA_HASH, EMPTY_TOOLSET_HASH, ESCALATE_TOOL_NAME, ESCALATION_REPORT_SCHEMA, ESCALATION_REQUEST_SCHEMA, EventBus, ExternalRegistry, FINISH_SCHEMA, FINISH_TOOL_NAME, FileModelKnowledgeStore, FileTranscriptStore, GitWorktreeProvider, INBOX_PROPOSAL_TTL_DAYS, InMemoryStore, InMemoryTranscriptStore, InProcessRunner, InvalidResolutionError, JournalCompatibilityError, JournalMatcher, JournalMissError, JournalOrderViolation, JsonlFileStore, KB_ACTIVE_CLAIMS_CAP, KB_CARD_RENDER_BUDGET_CHARS, KeyedLimiter, KnowledgeCasError, LARGE_VALUE_WARN_BYTES, LEGACY_LTID_PREFIX, LEGACY_SIGNATURE_INPUTS, LINEAGE_SIG_VERSION, LeaseHeldError, LineageIndex, MASKED_SECRET, MAX_DEPTH_CEILING, ModelRetry, NoProgressDetector, NonSerializableValueError, ORCHESTRATE_WORKFLOW_NAME, OrchestratorCapConfigError, PARALLEL_AGENTS_SCHEMA, ParallelSiteCounter, PlanInvariantError, ROLE_EFFORT_DEFAULTS, ROOT_ACCOUNT, ROOT_SCOPE, RUN_PROFILES, ReplayPlanHashMismatch, Replayer, ResolutionArbiter, ResolutionFold, RulvarError, RunBudget, SPAWN_AGENT_SCHEMA, SandboxError, ScriptRejected, Semaphore, SpanRegistry, TOOL_NAME_PATTERN, TerminationAccount, WAIT_FOR_EVENTS_SCHEMA, WAIT_FOR_EVENTS_TOOL_NAME, WAKE_SUMMARY_RENDER_BUDGET_CHARS, admissionReserveUsd, agentErrorFromWire, agentErrorToWire, agentScope, applyClaimOps, applyStructuredOutputTier, approachSigCoarse, approachSigOf, archiveDeprecatedModelOps, atCompactionThreshold, buildAbandonFold, buildAdapterRegistry, buildCostReport, buildDeriverRegistry, buildOrchestratorTools, buildTerminationInitValue, buildToolContext, canRideLoopTurn, canonicalIsolationTag, canonicalizeLadder, canonicalizeSchema, capIssues, capsHashOf, checkFloors, checkpointRefFor, childCoveragePrefix, claimExpired, claimExpiry, claimIssues, claimOpIssues, classifyAgentError, classifyAttemptOutcome, collectDeclaredLadders, compactMessages, compilePermissionChain, compilePermissionPreset, compileVerifiedLayer, costReportFromJournal, countsAgainstLimit, createCanonicalIdMinter, createCtx, createEngine, createSandboxBridge, currentOnlyKeyRing, decodeCheckpoint, defineWorkflow, deriveContentKey, deriverV1, deriverV2, digestOf, dispositionHook, emptyDigestBlocks, emptyToolset, encodeCheckpoint, entryUsageSlices, escalateTool, evaluatePermission, evaluateReuse, executeWorkflow, exhaustionCodeOf, extractCandidate, failoverTriggerOf, fallbackTriggerOf, filterClaimsForRun, finalizeFires, foldTermination, formatRePrompt, formatScopePath, hashWorkflowBody, hashWorkflowSource, identityJcs, isEscalated, isSchemaPairSpec, isStandardSchemaSpec, isStrictCompatibleSchema, kMaxOf, knowledgeHash, ladderLengthOf, ladderRungChoice, lexShellCommand, liftRetainedParts, lineageWeightOf, makeOrchestratorWorkflow, maskSecrets, maskSecretsDeep, maskSecretsJson, matchArgvPattern, matchShellCommand, mcp, mergeUsageLimits, modelEpochOf, modelKnowledgeCard, modelSpecIdentity, needsSeparateExtract, nextFailover, nodeLinkKey, normalizeApproachTag, normalizeEntry, normalizeFallbacks, orchestrate, parallelScope, parseModelRef, parseScopePath, phiInitialOf, pipelineScope, planNodeScope, priceEntryUsage, priceUsdOf, profileCard, profileRegistrySnapshotHash, projectHistory, projectIdentity, projectToJsonSchema, proposalStatement, providerOf, readTerminationInit, registryKeyRing, remeasureQueue, replayDisposition, resolveModelInvocation, resolvePricing, resolveToolset, retryClassOf, retryDelayMs, roleConfiguredInRouting, roundOneDisposition, runAgent, runProfile, scanJournalCompatibility, schemaHash, schemaHashOfSpec, selectStructuredOutputTier, shouldCompact, spawnDepthOf, summarizeInstruction, summarizeOutput, terminationConfigDrift, tierWithinCaps, toApprovalDecision, toJournalValue, tool, toolContract, toolsetHash, ttlState, validateEditorialCommit, validateEntryShape, validateEscalationLimits, validateEscalationReport, validateSchemaSpec, validateTerminationLimits, workflowScope, workflowSourceRef, wrapJournalStore, wrapTranscriptStore };
|
|
13082
|
+
export { AWAIT_SCHEMA, AdmissionController, AdmissionRejectedError, AgentCallError, BUDGET_ABORT_REASON, BudgetExhaustedError, CANCEL_AGENT_SCHEMA, CHECKPOINT_FORMAT_V1, CLAIM_STATEMENT_MAX_CHARS, CLAIM_TTL_DAYS, COMPACTION_SUMMARY_PREFIX, CURRENT_HASH_VERSION, ConfigError, DEFAULT_CHILD_BUDGET_FRACTION, DEFAULT_COMPACTION_THRESHOLD, DEFAULT_ESCALATION_LIMITS, DEFAULT_FLAT_RESERVE_USD, DEFAULT_MAX_CHILDREN_PER_NODE, DEFAULT_MAX_DEPTH, DEFAULT_MAX_OSCILLATIONS_PER_KEY, DEFAULT_MAX_PINNED_WORKTREES, DEFAULT_MAX_REVISIONS_PER_RUN, DEFAULT_MAX_TOTAL_SPAWNS, DEFAULT_MAX_TURNS, DEFAULT_MODEL_RETRY_ATTEMPTS, DEFAULT_NO_PROGRESS_TURNS, DEFAULT_PER_RUN_CONCURRENCY, DEFAULT_RETRY_POLICY, DEFAULT_STREAM_IDLE_TIMEOUT_MS, DedupIndex, EMIT_RESULT_TOOL, EMPTY_SCHEMA_HASH, EMPTY_TOOLSET_HASH, ESCALATE_TOOL_NAME, ESCALATION_REPORT_SCHEMA, ESCALATION_REQUEST_SCHEMA, EventBus, ExternalRegistry, FINISH_SCHEMA, FINISH_TOOL_NAME, FileModelKnowledgeStore, FileTranscriptStore, GitWorktreeProvider, INBOX_PROPOSAL_TTL_DAYS, InMemoryStore, InMemoryTranscriptStore, InProcessRunner, InvalidResolutionError, JournalCompatibilityError, JournalMatcher, JournalMissError, JournalOrderViolation, JsonlFileStore, KB_ACTIVE_CLAIMS_CAP, KB_CARD_RENDER_BUDGET_CHARS, KeyedLimiter, KnowledgeCasError, LARGE_VALUE_WARN_BYTES, LEGACY_LTID_PREFIX, LEGACY_SIGNATURE_INPUTS, LINEAGE_SIG_VERSION, LeaseHeldError, LineageIndex, MASKED_SECRET, MAX_DEPTH_CEILING, ModelRetry, NoProgressDetector, NonSerializableValueError, ORCHESTRATE_WORKFLOW_NAME, OrchestratorCapConfigError, PARALLEL_AGENTS_SCHEMA, ParallelSiteCounter, PlanInvariantError, ROLE_EFFORT_DEFAULTS, ROOT_ACCOUNT, ROOT_SCOPE, RUN_PROFILES, ReplayPlanHashMismatch, Replayer, ResolutionArbiter, ResolutionFold, RulvarError, RunBudget, SPAWN_AGENT_SCHEMA, SandboxError, ScriptRejected, Semaphore, SpanRegistry, TOOL_NAME_PATTERN, TerminationAccount, WAIT_FOR_EVENTS_SCHEMA, WAIT_FOR_EVENTS_TOOL_NAME, WAKE_SUMMARY_RENDER_BUDGET_CHARS, admissionReserveUsd, affordableOutputTokens, agentErrorFromWire, agentErrorToWire, agentScope, applyClaimOps, applyStructuredOutputTier, approachSigCoarse, approachSigOf, archiveDeprecatedModelOps, atCompactionThreshold, buildAbandonFold, buildAdapterRegistry, buildCostReport, buildDeriverRegistry, buildOrchestratorTools, buildTerminationInitValue, buildToolContext, canRideLoopTurn, canonicalIsolationTag, canonicalizeLadder, canonicalizeSchema, capIssues, capsHashOf, checkFloors, checkpointRefFor, childCoveragePrefix, claimExpired, claimExpiry, claimIssues, claimOpIssues, classifyAgentError, classifyAttemptOutcome, collectDeclaredLadders, compactMessages, compilePermissionChain, compilePermissionPreset, compileVerifiedLayer, costReportFromJournal, countsAgainstLimit, createCanonicalIdMinter, createCtx, createEngine, createSandboxBridge, currentOnlyKeyRing, decodeCheckpoint, defineWorkflow, deriveContentKey, deriverV1, deriverV2, digestOf, dispositionHook, emptyDigestBlocks, emptyToolset, encodeCheckpoint, entryUsageSlices, escalateTool, evaluatePermission, evaluateReuse, executeWorkflow, exhaustionCodeOf, extractCandidate, failoverTriggerOf, fallbackTriggerOf, filterClaimsForRun, finalizeFires, foldTermination, formatRePrompt, formatScopePath, hashWorkflowBody, hashWorkflowSource, identityJcs, isEscalated, isSchemaPairSpec, isStandardSchemaSpec, isStrictCompatibleSchema, kMaxOf, knowledgeHash, ladderLengthOf, ladderRungChoice, lexShellCommand, liftRetainedParts, lineageWeightOf, makeOrchestratorWorkflow, maskSecrets, maskSecretsDeep, maskSecretsJson, matchArgvPattern, matchShellCommand, mcp, mergeUsageLimits, modelEpochOf, modelKnowledgeCard, modelSpecIdentity, needsSeparateExtract, nextFailover, nodeLinkKey, normalizeApproachTag, normalizeEntry, normalizeFallbacks, orchestrate, parallelScope, parseModelRef, parseScopePath, phiInitialOf, pipelineScope, planNodeScope, priceEntryUsage, priceUsdOf, profileCard, profileRegistrySnapshotHash, projectHistory, projectIdentity, projectToJsonSchema, proposalStatement, providerOf, readTerminationInit, registryKeyRing, remeasureQueue, replayDisposition, resolveModelInvocation, resolvePricing, resolveToolset, retryClassOf, retryDelayMs, roleConfiguredInRouting, roundOneDisposition, runAgent, runProfile, scanJournalCompatibility, schemaHash, schemaHashOfSpec, selectStructuredOutputTier, shouldCompact, spawnDepthOf, summarizeInstruction, summarizeOutput, terminationConfigDrift, tierWithinCaps, toApprovalDecision, toJournalValue, tool, toolContract, toolsetHash, ttlState, validateEditorialCommit, validateEntryShape, validateEscalationLimits, validateEscalationReport, validateSchemaSpec, validateTerminationLimits, workflowScope, workflowSourceRef, wrapJournalStore, wrapTranscriptStore };
|