@rulvar/core 1.6.0 → 1.8.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/dist/index.d.ts +160 -8
- package/dist/index.js +340 -64
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -608,6 +608,23 @@ interface UsageSlice {
|
|
|
608
608
|
usage: Usage;
|
|
609
609
|
}
|
|
610
610
|
/**
|
|
611
|
+
* Cost-attribution facts a live run knows at settlement and a pure
|
|
612
|
+
* journal fold cannot re-derive: the innermost phase name at the call
|
|
613
|
+
* site, the agent profile, the primary invocation role, the budget
|
|
614
|
+
* account the call debited, and whether the dispatch spent the
|
|
615
|
+
* orchestrator finalize reserve. Policy, never identity, exactly like
|
|
616
|
+
* usageByModel: none of it enters the content key, and entries written
|
|
617
|
+
* before the field shipped fold under the documented fallback buckets
|
|
618
|
+
* (empty phase, 'unknown' agent type, role 'loop').
|
|
619
|
+
*/
|
|
620
|
+
interface CostAttributionFacts {
|
|
621
|
+
phase?: string;
|
|
622
|
+
agentType?: string;
|
|
623
|
+
role?: InvocationRole;
|
|
624
|
+
budgetAccount?: string;
|
|
625
|
+
finalizeReserve?: boolean;
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
611
628
|
* The per-model slices of a terminal entry: the recorded split when the
|
|
612
629
|
* call spanned several models, else the whole usage attributed to
|
|
613
630
|
* `servedBy`. The fallback is what makes every journal written before the
|
|
@@ -669,6 +686,13 @@ type JournalEntry = {
|
|
|
669
686
|
* Policy, never identity: it does not enter the content key.
|
|
670
687
|
*/
|
|
671
688
|
usageByModel?: UsageSlice[];
|
|
689
|
+
/**
|
|
690
|
+
* Terminal usage-bearing entries: the attribution facts behind the
|
|
691
|
+
* CostReport breakdowns, so a pure journal fold reproduces the live
|
|
692
|
+
* report byte for byte on replay. Policy, never identity, exactly
|
|
693
|
+
* like usageByModel.
|
|
694
|
+
*/
|
|
695
|
+
costAttribution?: CostAttributionFacts;
|
|
672
696
|
transcriptRef?: string;
|
|
673
697
|
checkpointRef?: string;
|
|
674
698
|
/**
|
|
@@ -1776,7 +1800,16 @@ interface ResumeReport {
|
|
|
1776
1800
|
misses: number;
|
|
1777
1801
|
skipped: number;
|
|
1778
1802
|
reruns: number;
|
|
1779
|
-
/**
|
|
1803
|
+
/**
|
|
1804
|
+
* Effect roots that genuinely need recovery under the entry-type
|
|
1805
|
+
* pairing rules: dangling dispatches (status 'running' with no
|
|
1806
|
+
* terminal) and suspensions with no resolution, neither consumed by a
|
|
1807
|
+
* live call nor covered by abandon. Complete operations are NEVER
|
|
1808
|
+
* listed: settled roots, single-entry kinds (decisions, facts, plan
|
|
1809
|
+
* and termination entries), and resolved suspensions are whole by
|
|
1810
|
+
* construction. A call deleted from the code is silently skipped and
|
|
1811
|
+
* never re-paid; it appears here only while its effect is dangling.
|
|
1812
|
+
*/
|
|
1780
1813
|
orphaned: number[];
|
|
1781
1814
|
}
|
|
1782
1815
|
/**
|
|
@@ -1789,6 +1822,8 @@ declare class JournalMatcher {
|
|
|
1789
1822
|
private readonly byScope;
|
|
1790
1823
|
private readonly all;
|
|
1791
1824
|
private readonly consumed;
|
|
1825
|
+
/** Suspension seqs holding at least one resolution ref-entry. */
|
|
1826
|
+
private readonly resolvedRefs;
|
|
1792
1827
|
private readonly keyRing;
|
|
1793
1828
|
private disposition;
|
|
1794
1829
|
private aliasDisposition?;
|
|
@@ -2083,6 +2118,8 @@ interface TerminalPatch {
|
|
|
2083
2118
|
servedBy?: ModelRef;
|
|
2084
2119
|
/** Set only when the call spanned several serving models; see JournalEntry. */
|
|
2085
2120
|
usageByModel?: UsageSlice[];
|
|
2121
|
+
/** Attribution facts behind the CostReport breakdowns; see JournalEntry. */
|
|
2122
|
+
costAttribution?: CostAttributionFacts;
|
|
2086
2123
|
transcriptRef?: string;
|
|
2087
2124
|
checkpointRef?: string;
|
|
2088
2125
|
/** Terminal agent entries: Artifact list. */
|
|
@@ -3088,9 +3125,14 @@ interface TerminationLimits {
|
|
|
3088
3125
|
kMax: number;
|
|
3089
3126
|
/** B0; immutable after start, no API including HITL can top up. */
|
|
3090
3127
|
runBudgetUsdCeiling: number;
|
|
3091
|
-
/**
|
|
3128
|
+
/**
|
|
3129
|
+
* The resolved orchestrator cap in absolute USD (DEF-7; XF-09),
|
|
3130
|
+
* frozen with the counters. Journals recorded before v1.8 store 0
|
|
3131
|
+
* ("not yet resolved"); for them the orchestrator_budget_reserve
|
|
3132
|
+
* decision is the authority and is recovered on resume.
|
|
3133
|
+
*/
|
|
3092
3134
|
orchestratorCapUsd: number;
|
|
3093
|
-
/**
|
|
3135
|
+
/** The finalize reserve carved out of the cap; 0 in pre-v1.8 journals. */
|
|
3094
3136
|
finalizeReserveUsd: number;
|
|
3095
3137
|
}
|
|
3096
3138
|
/** Appendix A committed defaults for the countable resources. */
|
|
@@ -3348,6 +3390,26 @@ interface BudgetAccountView {
|
|
|
3348
3390
|
parentScope?: string;
|
|
3349
3391
|
}
|
|
3350
3392
|
/**
|
|
3393
|
+
* Why a ceiling error ended the work: the first closed account walking
|
|
3394
|
+
* from the debited scope toward the root, plus the root state, so the
|
|
3395
|
+
* outward message can name WHICH ceiling actually crossed instead of
|
|
3396
|
+
* blaming the run ceiling for every crossing.
|
|
3397
|
+
*/
|
|
3398
|
+
interface BudgetExhaustionDiagnostics {
|
|
3399
|
+
crossed?: {
|
|
3400
|
+
scope: string;
|
|
3401
|
+
source: "root" | "orchestrator-cap" | "child-account";
|
|
3402
|
+
ceilingUsd: number;
|
|
3403
|
+
spentUsd: number;
|
|
3404
|
+
committedReserveUsd: number;
|
|
3405
|
+
finalizeReserveUsd: number;
|
|
3406
|
+
};
|
|
3407
|
+
root: {
|
|
3408
|
+
ceilingUsd?: number;
|
|
3409
|
+
spentUsd: number;
|
|
3410
|
+
};
|
|
3411
|
+
}
|
|
3412
|
+
/**
|
|
3351
3413
|
* The per-run budget account tree. All spend accounting is per instance;
|
|
3352
3414
|
* the journal remains the durable source (the root is seeded by the
|
|
3353
3415
|
* ledger fold on resume, M2; sub-account reserves are recovered from
|
|
@@ -3395,7 +3457,20 @@ declare class RunBudget {
|
|
|
3395
3457
|
parentScope?: string;
|
|
3396
3458
|
ceilingUsd?: number;
|
|
3397
3459
|
finalizeReserveUsd?: number;
|
|
3460
|
+
kind?: "orchestrator-cap" | "child-allowance";
|
|
3398
3461
|
}): void;
|
|
3462
|
+
/**
|
|
3463
|
+
* The diagnostic projection behind a ceiling error: the first CLOSED
|
|
3464
|
+
* account (projected commitments included, exactly the layer-1
|
|
3465
|
+
* closure test) walking from `scope` toward the root, plus the root
|
|
3466
|
+
* state. 'run budget ceiling reached' under a healthy root misled the
|
|
3467
|
+
* v1.6.0 follow-up review's live probe when only a 0.18 USD
|
|
3468
|
+
* orchestrator cap had crossed under a 0.90 USD root; the message can
|
|
3469
|
+
* now name the account that actually ended the work. An unknown scope
|
|
3470
|
+
* degrades to root-only diagnostics instead of throwing: this runs on
|
|
3471
|
+
* the error path.
|
|
3472
|
+
*/
|
|
3473
|
+
exhaustionDiagnostics(scope: string): BudgetExhaustionDiagnostics;
|
|
3399
3474
|
accountView(scope: string): BudgetAccountView | undefined;
|
|
3400
3475
|
/**
|
|
3401
3476
|
* The admission remainder of one account: ceiling minus spend minus
|
|
@@ -3403,6 +3478,18 @@ declare class RunBudget {
|
|
|
3403
3478
|
* fractions never eat finalization money). Undefined when uncapped.
|
|
3404
3479
|
*/
|
|
3405
3480
|
remainderOf(scope: string): number | undefined;
|
|
3481
|
+
/**
|
|
3482
|
+
* The tightest allowance headroom on the chain of `scope`: the minimum
|
|
3483
|
+
* remainder across 'child-allowance' accounts. An allowance ceiling
|
|
3484
|
+
* bounds the child's LIFETIME spend, so projected admission must never
|
|
3485
|
+
* hold more than this against the chain (the layer-2 mirror lives in
|
|
3486
|
+
* the orchestrator admission's childCeiling clamp): a reserve above
|
|
3487
|
+
* the allowance would deny work that the allowance itself already
|
|
3488
|
+
* bounds. Undefined when no allowance account is on the chain; the
|
|
3489
|
+
* clamp never applies to the run root or an orchestrator cap, whose
|
|
3490
|
+
* headroom is shared money that projected admission must protect.
|
|
3491
|
+
*/
|
|
3492
|
+
allowanceHeadroomOf(scope: string): number | undefined;
|
|
3406
3493
|
/** Layer 3 ceiling signal of the run root; live streams sever through it. */
|
|
3407
3494
|
get signal(): AbortSignal;
|
|
3408
3495
|
/** The layer-3 signal of one sub-account's subtree, when it exists. */
|
|
@@ -3691,6 +3778,23 @@ type AdmitRejectReason = {
|
|
|
3691
3778
|
code: "osc_guard";
|
|
3692
3779
|
spawnKey: SpawnKey;
|
|
3693
3780
|
oscillationCount: number;
|
|
3781
|
+
} | {
|
|
3782
|
+
/**
|
|
3783
|
+
* The declared estimate cannot fit the child's own ceiling: the
|
|
3784
|
+
* host said the work costs more than the budget buys, so the op
|
|
3785
|
+
* is bounced with the actionable correction BEFORE it changes
|
|
3786
|
+
* plan state or consumes a spawn unit (the v1.7.0 follow-up
|
|
3787
|
+
* review's P1). Heuristic reserves never produce this code; they
|
|
3788
|
+
* clamp to the allowance instead.
|
|
3789
|
+
*/
|
|
3790
|
+
code: "reserve_exceeds_budget";
|
|
3791
|
+
agentType: string;
|
|
3792
|
+
childAccount: string;
|
|
3793
|
+
estCostUsd: number;
|
|
3794
|
+
resolvedReserveUsd: number;
|
|
3795
|
+
childCeilingUsd: number;
|
|
3796
|
+
minimumBudgetUsd: number;
|
|
3797
|
+
message: string;
|
|
3694
3798
|
};
|
|
3695
3799
|
/** Every spawn origin routed through the single admission point. */
|
|
3696
3800
|
type SpawnOrigin = "ctx.workflow" | "ctx.orchestrate" | "spawn_agent" | "parallel_agents" | "escalation-decomposition" | "rung-respawn" | "reuse-link";
|
|
@@ -3708,6 +3812,13 @@ interface AdmitSpec {
|
|
|
3708
3812
|
/** Reserve hint; falls back to the flat engine default. */
|
|
3709
3813
|
estCostUsd?: number;
|
|
3710
3814
|
/**
|
|
3815
|
+
* Same-batch reserves already admitted read-only but not yet
|
|
3816
|
+
* committed (a multi-op plan revision): the read-only branch adds
|
|
3817
|
+
* them to this spawn's reserve so every embedded admit of one batch
|
|
3818
|
+
* is dispatchable under the same snapshot, not just the first.
|
|
3819
|
+
*/
|
|
3820
|
+
pendingReserveUsd?: number;
|
|
3821
|
+
/**
|
|
3711
3822
|
* Lineage continuation (DEF-3); absence mints a fresh lineage root. A
|
|
3712
3823
|
* continuation demands a causeRef: the seq of the entry that caused the
|
|
3713
3824
|
* rebirth.
|
|
@@ -3858,6 +3969,17 @@ declare class AdmissionController {
|
|
|
3858
3969
|
* journaled by the caller so replay re-delivers it without
|
|
3859
3970
|
* re-evaluation.
|
|
3860
3971
|
*/
|
|
3972
|
+
/**
|
|
3973
|
+
* The reserve the DISPATCH layer will actually commit for this spec:
|
|
3974
|
+
* the estimate (or the flat default) clamped by the explicit child
|
|
3975
|
+
* budget when one exists, because only an explicit budget opens a
|
|
3976
|
+
* child-allowance account at dispatch; the childBudgetFraction cap
|
|
3977
|
+
* never materializes as an account and must not shrink the
|
|
3978
|
+
* projection. The token-count-priced estimate of ctx.agent is
|
|
3979
|
+
* unreachable here (async); a divergence there lands as a journaled
|
|
3980
|
+
* dispatch rejection instead of a strand.
|
|
3981
|
+
*/
|
|
3982
|
+
projectedDispatchReserveUsd(spec: Pick<AdmitSpec, "estCostUsd" | "budgetUsd">): number;
|
|
3861
3983
|
admit(spec: AdmitSpec, options?: {
|
|
3862
3984
|
commitReserve?: boolean;
|
|
3863
3985
|
}): AdmissionDecision;
|
|
@@ -4146,9 +4268,14 @@ type WorkflowEvent = {
|
|
|
4146
4268
|
/** Folds the per-run attribution buckets into the normative CostReport. */
|
|
4147
4269
|
declare function buildCostReport(attribution: CostAttribution, totalUsd: number): CostReport;
|
|
4148
4270
|
/**
|
|
4149
|
-
* The pure journal fold:
|
|
4150
|
-
* same summation the kernel ledger uses (terminal usage exactly
|
|
4151
|
-
* priced per servedBy, abandoned subtrees contribute zero).
|
|
4271
|
+
* The pure journal fold: the complete CostReport from terminal entries,
|
|
4272
|
+
* the same summation the kernel ledger uses (terminal usage exactly
|
|
4273
|
+
* once, priced per servedBy slice, abandoned subtrees contribute zero).
|
|
4274
|
+
* The orchestrator block folds too: spend attributed to the
|
|
4275
|
+
* orchestrator sub-account, the reserve-funded share of it, the armed
|
|
4276
|
+
* wake count, and the at-cap freeze flag from the journaled cap
|
|
4277
|
+
* decision, so a replay-only resume reproduces the block instead of
|
|
4278
|
+
* reading this process's live accounts (which a replay never charges).
|
|
4152
4279
|
*/
|
|
4153
4280
|
declare function costReportFromJournal(entries: readonly JournalEntry[], priceUsd: (servedBy: ModelRef, usage: Usage) => number | undefined): CostReport;
|
|
4154
4281
|
//#endregion
|
|
@@ -4171,7 +4298,15 @@ interface CostReport {
|
|
|
4171
4298
|
byPhase: Record<string, number>;
|
|
4172
4299
|
byAgentType: Record<string, number>;
|
|
4173
4300
|
byRole: Record<InvocationRole, number>;
|
|
4174
|
-
/**
|
|
4301
|
+
/**
|
|
4302
|
+
* All-zero with forcedFinish false in runs without a dynamic
|
|
4303
|
+
* orchestrator (or when no cap resolved, so no sub-account opened).
|
|
4304
|
+
* Folded purely from the journal: spentUsd is the priced usage of
|
|
4305
|
+
* entries debited to the orchestrator sub-account, reserveUsedUsd its
|
|
4306
|
+
* reserve-funded forced-finish share, wakes the ARMED (journaled)
|
|
4307
|
+
* wake suspensions (a wait satisfied synchronously never suspends and
|
|
4308
|
+
* is not counted), and forcedFinish the journaled at-cap decision.
|
|
4309
|
+
*/
|
|
4175
4310
|
orchestrator: {
|
|
4176
4311
|
spentUsd: number; /** spentUsd / max(totalUsd, 0.01): the epsilon-floored H-OrchShare input. */
|
|
4177
4312
|
share: number;
|
|
@@ -4746,6 +4881,16 @@ interface OrchestratorExtensionIO {
|
|
|
4746
4881
|
readonly gates: Record<string, unknown>;
|
|
4747
4882
|
/** The run USD ceiling (B0), when one exists. */
|
|
4748
4883
|
readonly runCeilingUsd?: number;
|
|
4884
|
+
/**
|
|
4885
|
+
* The resolved orchestrator cap in absolute USD (DEF-7; XF-09):
|
|
4886
|
+
* min(budget.capUsd, capFraction x B0) on a fresh run, the frozen
|
|
4887
|
+
* orchestrator_budget_reserve dollars on resume. Resolved strictly
|
|
4888
|
+
* before boot so an extension can freeze it into termination.init;
|
|
4889
|
+
* always present under PlanRunner (an unresolvable cap refuses boot).
|
|
4890
|
+
*/
|
|
4891
|
+
readonly orchestratorCapUsd?: number;
|
|
4892
|
+
/** The finalize reserve carved out of the cap, resolved with it. */
|
|
4893
|
+
readonly finalizeReserveUsd?: number;
|
|
4749
4894
|
/** ULID minting for engine-owned identifiers (NodeIds). */
|
|
4750
4895
|
mintId(): string;
|
|
4751
4896
|
/**
|
|
@@ -4852,6 +4997,13 @@ interface OrchestratorExtension {
|
|
|
4852
4997
|
* machinery (reserves, freeze) completes in M7 (DEF-7).
|
|
4853
4998
|
*/
|
|
4854
4999
|
interface OrchestratorBudgetSpec {
|
|
5000
|
+
/**
|
|
5001
|
+
* Absolute bound in USD. It never REPLACES the fraction bound:
|
|
5002
|
+
* effectiveCap = min(capUsd, (capFraction ?? 0.2) * ceiling), so an
|
|
5003
|
+
* explicit capUsd larger than the default fraction of the run ceiling
|
|
5004
|
+
* is still cut to that fraction (and a warn log says so). Pass
|
|
5005
|
+
* capFraction: 1.0 to make capUsd the sole bound.
|
|
5006
|
+
*/
|
|
4855
5007
|
capUsd?: number;
|
|
4856
5008
|
/** default 0.2; effectiveCap = min of the given bounds */
|
|
4857
5009
|
capFraction?: number;
|
|
@@ -6181,4 +6333,4 @@ interface SandboxBridge {
|
|
|
6181
6333
|
}
|
|
6182
6334
|
declare function createSandboxBridge(ctx: Ctx<never>, options: SandboxBridgeOptions): SandboxBridge;
|
|
6183
6335
|
//#endregion
|
|
6184
|
-
export { AWAIT_SCHEMA, AbandonAttempt, AbandonFold, AbandonPayload, AbandonedSpendView, AbortClass, type AdaptiveEvents, AdmissionController, AdmissionDecision, AdmissionRejectedError, AdmissionStatsBefore, AdmitLineage, AdmitRejectReason, AdmitSpec, AdmitVerdict, AgentCallError, AgentError, type AgentEvents, AgentIdentityInput, AgentOpts, AgentProfile, AgentProfilePermissions, AgentResult, AgentResultMeta, AgentStatus, ApproachSignatureInputs, ApprovalDecision, ApprovalIdentityInput, Artifact, AttemptOutcomeClass, BUDGET_ABORT_REASON, BriefOpts, BudgetAccountView, BudgetDefaults, BudgetExhaustedError, BudgetHooks, BudgetReserve, type Bytes, CANCEL_AGENT_SCHEMA, CHECKPOINT_FORMAT_V1, CLAIM_STATEMENT_MAX_CHARS, CLAIM_TTL_DAYS, COMPACTION_SUMMARY_PREFIX, CURRENT_HASH_VERSION, CacheHint, CacheTtl, CanUseTool, CanonicalId, CanonicalIdentity, CanonicalLadderSpec, CanonicalModelSpec, ChatEvent, ChatRequest, CheckpointState, ChildIdentityInput, type ClaimClass, type ClaimOp, type ClaimStatus, ClaimValidationOptions, CollectOpts, CollectedTurn, CompactionConfig, CompiledPermissionChain, CompiledWorkflow, ConfigError, type CoreEvents, CostAttribution, CostReport, CreateEngineOptions, Ctx, 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, DebitResult, DeclaredLadder, DedupIndex, DedupNote, DerivedKey, DeriverRegistry, DispositionRule, DispositionTable, DonorCandidate, DonorRef, DroppedItem, EMIT_RESULT_TOOL, EMPTY_SCHEMA_HASH, EMPTY_TOOLSET_HASH, ESCALATE_TOOL_NAME, ESCALATION_REPORT_SCHEMA, ESCALATION_REQUEST_SCHEMA, EffectiveUsageLimits, Effort, Engine, EngineDefaults, EntryKind, EntryRef, EntryStatus, ErrorClass, ErrorCode, ErrorPolicy, EscalatedResult, EscalationDecision, EscalationDigest, EscalationKind, EscalationLimits, EscalationOptions, EscalationReport, EscalationRequest, EventBus, type EvidenceRef, ExtensionAppendInput, ExtensionDispatchSpec, ExternalIdentityInput, ExternalRegistry, ExtractNecessityInput, FINISH_SCHEMA, FINISH_TOOL_NAME, FailoverTarget, FailoverTrigger, FallbackField, FallbackTrigger, FileModelKnowledgeStore, FileModelKnowledgeStoreOptions, FileTranscriptStore, FinishInfo, Gate, GateAudit, type GateRecord, GitWorktreeProvider, GitWorktreeProviderOptions, GraftBoot, HashVersion, HookVerdict, INBOX_PROPOSAL_TTL_DAYS, IdentityInput, InMemoryStore, InMemoryTranscriptStore, InProcessRunner, InvalidResolutionError, InvocationRole, type IsolationProvider, type IsolationSpec, Issue$1 as Issue, JournalCompatSubCode, JournalCompatibilityError, JournalEntry, JournalMatcher, JournalMissError, JournalOperation, JournalOrderViolation, JournalSerializationHook, type JournalStore, type Json, JsonSchema, JsonlFileStore, KB_ACTIVE_CLAIMS_CAP, KB_CARD_RENDER_BUDGET_CHARS, type KbProposal, type KbProposalTrigger, KeyDeriver, KeyRing, KeyedLimiter, KnowledgeCasError, type KnowledgeSnapshot, LARGE_VALUE_WARN_BYTES, LEGACY_LTID_PREFIX, LEGACY_SIGNATURE_INPUTS, LINEAGE_SIG_VERSION, LadderSpec, type LeasableStore, type Lease, LeaseHeldError, Ledger, LineageCounters, LineageIndex, LineageRef, LineageRelation, LineageStats, LogicalTaskId, MASKED_SECRET, MAX_DEPTH_CEILING, MatchResult, McpConfig, MechanicalGateProfile, MechanicalGateVerdict, type ModelCaps, ModelChoice, type ModelClaim, ModelEpochInputs, type ModelKnowledgeHandle, type ModelKnowledgeStore, ModelListConstraint, ModelRef, ModelRetry, ModelSpec, Msg, NoProgressDetector, NodeId, NodeLinkValue, NonSerializableValueError, ORCHESTRATE_WORKFLOW_NAME, OnEscalation, OperationDisposition, OrchestrateOptions, OrchestratorBudgetSpec, OrchestratorCapConfigError, OrchestratorExtension, OrchestratorExtensionIO, OrchestratorRuntime, Out, PARALLEL_AGENTS_SCHEMA, ParallelSiteCounter, Part, PendingExternal, PendingToolTurn, PermissionConfig, PermissionGate, PermissionHook, PermissionPreset, PermissionRule, PermissionVerdict, PhaseTarget, PipelineCollected, PipelineOpts, PlanInvariantError, PriceTable, PricedUsage, type Pricing, type PricingTier, type ProviderAdapter, QualityFloors, ROLE_EFFORT_DEFAULTS, ROOT_ACCOUNT, ROOT_SCOPE, RUN_PROFILES, RandIdentityInput, RandPayload, RefEntryAppender, RefEntryClassification, RefusalInfo, ReplayDisposition, ReplayMode, ReplayPlanHashMismatch, Replayer, ResolutionArbiter, ResolutionAttempt, ResolutionBy, ResolutionFold, ResolutionLayer, ResolutionOutcome, ResolutionPayload, ResolvedInvocation, ResolvedToolset, ResumeHandle, ResumeOptions, ResumePreview, ResumeReport, RetryClass, RetryPolicy, ReuseConfig, RiskRuleValue, Role, RulvarError, RulvarErrorCode, RunAgentOptions, RunBudget, RunEventSink, type RunFilter, RunHandle, RunInternals, type RunMeta, RunOptions, RunOutcome, RunProfile, RunStatus, RuntimeEventSink, SPAWN_AGENT_SCHEMA, SandboxBridge, SandboxBridgeOptions, SandboxError, SandboxHostToWorker, SandboxMethod, SandboxWorkerToHost, SchemaPair, SchemaSpec, SchemaValidationResult, ScopeSegment, ScriptRejected, ScriptRunner, ScrubNote, Semaphore, SerializationHook, Settled, ShellPatternRules, ShellSegment, ShellVerdict, SinglePhaseAppend, SpanMinter, SpanRegistry, SpawnAdmissionValue, SpawnAgentParams, SpawnKey, SpawnLineage, SpawnLineageOpt, SpawnOrigin, SpawnRecord, Spend, Stage, type StandardJSONSchemaV1, type StandardSchemaV1, StepIdentityInput, StructuredOutputTier, SuspendedAppend, SuspensionState, TOOL_NAME_PATTERN, type TaskClass, TaskDigest, TaskSpec, TerminalPatch, TerminationAccount, TerminationAccountSnapshot, TerminationDeniedValue, TerminationDeniedWriter, TerminationInitValue, TerminationLimits, TerminationResource, ToolCallRequest, ToolChoice, type ToolContext, ToolContextSeed, ToolContract, type ToolDef, type ToolEvents, type ToolExecutor, ToolInit, type ToolRisk, ToolRuntime, type ToolSource, type ToolSourceSession, ToolsOption, TranscriptSerializationHook, type TranscriptStore, TriggerClass, TtlState, Usage, UsageLimits, UsageSlice, VerifiedRecommendation, WAIT_FOR_EVENTS_SCHEMA, WAIT_FOR_EVENTS_TOOL_NAME, WAKE_SUMMARY_RENDER_BUDGET_CHARS, WakeBudgetBlock, WakeDigest, WakeTrigger, WireError, Workflow, WorkflowCallOpts, type WorkflowEvent, type WorkflowEventBody, WorkflowRegistry, 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 };
|
|
6336
|
+
export { AWAIT_SCHEMA, AbandonAttempt, AbandonFold, AbandonPayload, AbandonedSpendView, AbortClass, type AdaptiveEvents, AdmissionController, AdmissionDecision, AdmissionRejectedError, AdmissionStatsBefore, AdmitLineage, AdmitRejectReason, AdmitSpec, AdmitVerdict, AgentCallError, AgentError, type AgentEvents, AgentIdentityInput, AgentOpts, AgentProfile, AgentProfilePermissions, AgentResult, AgentResultMeta, AgentStatus, ApproachSignatureInputs, ApprovalDecision, ApprovalIdentityInput, Artifact, AttemptOutcomeClass, BUDGET_ABORT_REASON, BriefOpts, BudgetAccountView, BudgetDefaults, BudgetExhaustedError, BudgetExhaustionDiagnostics, BudgetHooks, BudgetReserve, type Bytes, CANCEL_AGENT_SCHEMA, CHECKPOINT_FORMAT_V1, CLAIM_STATEMENT_MAX_CHARS, CLAIM_TTL_DAYS, COMPACTION_SUMMARY_PREFIX, CURRENT_HASH_VERSION, CacheHint, CacheTtl, CanUseTool, CanonicalId, CanonicalIdentity, CanonicalLadderSpec, CanonicalModelSpec, ChatEvent, ChatRequest, CheckpointState, ChildIdentityInput, type ClaimClass, type ClaimOp, type ClaimStatus, ClaimValidationOptions, CollectOpts, CollectedTurn, CompactionConfig, CompiledPermissionChain, CompiledWorkflow, ConfigError, type CoreEvents, CostAttribution, CostAttributionFacts, CostReport, CreateEngineOptions, Ctx, 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, DebitResult, DeclaredLadder, DedupIndex, DedupNote, DerivedKey, DeriverRegistry, DispositionRule, DispositionTable, DonorCandidate, DonorRef, DroppedItem, EMIT_RESULT_TOOL, EMPTY_SCHEMA_HASH, EMPTY_TOOLSET_HASH, ESCALATE_TOOL_NAME, ESCALATION_REPORT_SCHEMA, ESCALATION_REQUEST_SCHEMA, EffectiveUsageLimits, Effort, Engine, EngineDefaults, EntryKind, EntryRef, EntryStatus, ErrorClass, ErrorCode, ErrorPolicy, EscalatedResult, EscalationDecision, EscalationDigest, EscalationKind, EscalationLimits, EscalationOptions, EscalationReport, EscalationRequest, EventBus, type EvidenceRef, ExtensionAppendInput, ExtensionDispatchSpec, ExternalIdentityInput, ExternalRegistry, ExtractNecessityInput, FINISH_SCHEMA, FINISH_TOOL_NAME, FailoverTarget, FailoverTrigger, FallbackField, FallbackTrigger, FileModelKnowledgeStore, FileModelKnowledgeStoreOptions, FileTranscriptStore, FinishInfo, Gate, GateAudit, type GateRecord, GitWorktreeProvider, GitWorktreeProviderOptions, GraftBoot, HashVersion, HookVerdict, INBOX_PROPOSAL_TTL_DAYS, IdentityInput, InMemoryStore, InMemoryTranscriptStore, InProcessRunner, InvalidResolutionError, InvocationRole, type IsolationProvider, type IsolationSpec, Issue$1 as Issue, JournalCompatSubCode, JournalCompatibilityError, JournalEntry, JournalMatcher, JournalMissError, JournalOperation, JournalOrderViolation, JournalSerializationHook, type JournalStore, type Json, JsonSchema, JsonlFileStore, KB_ACTIVE_CLAIMS_CAP, KB_CARD_RENDER_BUDGET_CHARS, type KbProposal, type KbProposalTrigger, KeyDeriver, KeyRing, KeyedLimiter, KnowledgeCasError, type KnowledgeSnapshot, LARGE_VALUE_WARN_BYTES, LEGACY_LTID_PREFIX, LEGACY_SIGNATURE_INPUTS, LINEAGE_SIG_VERSION, LadderSpec, type LeasableStore, type Lease, LeaseHeldError, Ledger, LineageCounters, LineageIndex, LineageRef, LineageRelation, LineageStats, LogicalTaskId, MASKED_SECRET, MAX_DEPTH_CEILING, MatchResult, McpConfig, MechanicalGateProfile, MechanicalGateVerdict, type ModelCaps, ModelChoice, type ModelClaim, ModelEpochInputs, type ModelKnowledgeHandle, type ModelKnowledgeStore, ModelListConstraint, ModelRef, ModelRetry, ModelSpec, Msg, NoProgressDetector, NodeId, NodeLinkValue, NonSerializableValueError, ORCHESTRATE_WORKFLOW_NAME, OnEscalation, OperationDisposition, OrchestrateOptions, OrchestratorBudgetSpec, OrchestratorCapConfigError, OrchestratorExtension, OrchestratorExtensionIO, OrchestratorRuntime, Out, PARALLEL_AGENTS_SCHEMA, ParallelSiteCounter, Part, PendingExternal, PendingToolTurn, PermissionConfig, PermissionGate, PermissionHook, PermissionPreset, PermissionRule, PermissionVerdict, PhaseTarget, PipelineCollected, PipelineOpts, PlanInvariantError, PriceTable, PricedUsage, type Pricing, type PricingTier, type ProviderAdapter, QualityFloors, ROLE_EFFORT_DEFAULTS, ROOT_ACCOUNT, ROOT_SCOPE, RUN_PROFILES, RandIdentityInput, RandPayload, RefEntryAppender, RefEntryClassification, RefusalInfo, ReplayDisposition, ReplayMode, ReplayPlanHashMismatch, Replayer, ResolutionArbiter, ResolutionAttempt, ResolutionBy, ResolutionFold, ResolutionLayer, ResolutionOutcome, ResolutionPayload, ResolvedInvocation, ResolvedToolset, ResumeHandle, ResumeOptions, ResumePreview, ResumeReport, RetryClass, RetryPolicy, ReuseConfig, RiskRuleValue, Role, RulvarError, RulvarErrorCode, RunAgentOptions, RunBudget, RunEventSink, type RunFilter, RunHandle, RunInternals, type RunMeta, RunOptions, RunOutcome, RunProfile, RunStatus, RuntimeEventSink, SPAWN_AGENT_SCHEMA, SandboxBridge, SandboxBridgeOptions, SandboxError, SandboxHostToWorker, SandboxMethod, SandboxWorkerToHost, SchemaPair, SchemaSpec, SchemaValidationResult, ScopeSegment, ScriptRejected, ScriptRunner, ScrubNote, Semaphore, SerializationHook, Settled, ShellPatternRules, ShellSegment, ShellVerdict, SinglePhaseAppend, SpanMinter, SpanRegistry, SpawnAdmissionValue, SpawnAgentParams, SpawnKey, SpawnLineage, SpawnLineageOpt, SpawnOrigin, SpawnRecord, Spend, Stage, type StandardJSONSchemaV1, type StandardSchemaV1, StepIdentityInput, StructuredOutputTier, SuspendedAppend, SuspensionState, TOOL_NAME_PATTERN, type TaskClass, TaskDigest, TaskSpec, TerminalPatch, TerminationAccount, TerminationAccountSnapshot, TerminationDeniedValue, TerminationDeniedWriter, TerminationInitValue, TerminationLimits, TerminationResource, ToolCallRequest, ToolChoice, type ToolContext, ToolContextSeed, ToolContract, type ToolDef, type ToolEvents, type ToolExecutor, ToolInit, type ToolRisk, ToolRuntime, type ToolSource, type ToolSourceSession, ToolsOption, TranscriptSerializationHook, type TranscriptStore, TriggerClass, TtlState, Usage, UsageLimits, UsageSlice, VerifiedRecommendation, WAIT_FOR_EVENTS_SCHEMA, WAIT_FOR_EVENTS_TOOL_NAME, WAKE_SUMMARY_RENDER_BUDGET_CHARS, WakeBudgetBlock, WakeDigest, WakeTrigger, WireError, Workflow, WorkflowCallOpts, type WorkflowEvent, type WorkflowEventBody, WorkflowRegistry, 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 };
|
package/dist/index.js
CHANGED
|
@@ -5054,6 +5054,8 @@ var JournalMatcher = class {
|
|
|
5054
5054
|
byScope = /* @__PURE__ */ new Map();
|
|
5055
5055
|
all = [];
|
|
5056
5056
|
consumed = /* @__PURE__ */ new Set();
|
|
5057
|
+
/** Suspension seqs holding at least one resolution ref-entry. */
|
|
5058
|
+
resolvedRefs = /* @__PURE__ */ new Set();
|
|
5057
5059
|
keyRing;
|
|
5058
5060
|
disposition;
|
|
5059
5061
|
aliasDisposition;
|
|
@@ -5069,7 +5071,10 @@ var JournalMatcher = class {
|
|
|
5069
5071
|
this.disposition = options?.disposition ?? roundOneDisposition;
|
|
5070
5072
|
const terminalsByRef = /* @__PURE__ */ new Map();
|
|
5071
5073
|
for (const entry of entries) {
|
|
5072
|
-
if (REF_ENTRY_KINDS.has(entry.kind))
|
|
5074
|
+
if (REF_ENTRY_KINDS.has(entry.kind)) {
|
|
5075
|
+
if (entry.kind === "resolution" && entry.ref !== void 0) this.resolvedRefs.add(entry.ref);
|
|
5076
|
+
continue;
|
|
5077
|
+
}
|
|
5073
5078
|
if (entry.ref !== void 0) terminalsByRef.set(entry.ref, entry);
|
|
5074
5079
|
}
|
|
5075
5080
|
for (const entry of entries) {
|
|
@@ -5246,7 +5251,12 @@ var JournalMatcher = class {
|
|
|
5246
5251
|
misses: this.missesInternal,
|
|
5247
5252
|
skipped: this.skippedInternal,
|
|
5248
5253
|
reruns: this.rerunsInternal,
|
|
5249
|
-
orphaned: this.all.filter((op) =>
|
|
5254
|
+
orphaned: this.all.filter((op) => {
|
|
5255
|
+
if (this.consumed.has(op.running.seq) || op.terminal !== void 0) return false;
|
|
5256
|
+
if (op.running.status === "running") return true;
|
|
5257
|
+
if (op.running.status === "suspended") return !this.resolvedRefs.has(op.running.seq);
|
|
5258
|
+
return false;
|
|
5259
|
+
}).map((op) => op.running.seq)
|
|
5250
5260
|
};
|
|
5251
5261
|
}
|
|
5252
5262
|
};
|
|
@@ -5484,6 +5494,7 @@ var Replayer = class {
|
|
|
5484
5494
|
if (patch.usageApprox !== void 0) entry.usageApprox = patch.usageApprox;
|
|
5485
5495
|
if (patch.servedBy !== void 0) entry.servedBy = patch.servedBy;
|
|
5486
5496
|
if (patch.usageByModel !== void 0) entry.usageByModel = patch.usageByModel;
|
|
5497
|
+
if (patch.costAttribution !== void 0) entry.costAttribution = patch.costAttribution;
|
|
5487
5498
|
if (patch.transcriptRef !== void 0) entry.transcriptRef = patch.transcriptRef;
|
|
5488
5499
|
if (patch.checkpointRef !== void 0) entry.checkpointRef = patch.checkpointRef;
|
|
5489
5500
|
if (patch.artifacts !== void 0) entry.artifacts = toJournalValue(patch.artifacts, "terminal artifacts");
|
|
@@ -6147,19 +6158,28 @@ var FileTranscriptStore = class {
|
|
|
6147
6158
|
//#endregion
|
|
6148
6159
|
//#region src/engine/cost-report.ts
|
|
6149
6160
|
/**
|
|
6150
|
-
* CostReport builders (M5-T03).
|
|
6151
|
-
*
|
|
6161
|
+
* CostReport builders (M5-T03; follow-up: one pure fold).
|
|
6162
|
+
*
|
|
6163
|
+
* `costReportFromJournal` is THE report: a pure fold over terminal
|
|
6164
|
+
* entries that both the engine's settle path and stored-run inspection
|
|
6165
|
+
* (shells, `rulvar inspect`) use, so a replayed run reports the same
|
|
6166
|
+
* numbers byte for byte. Terminal entries carry their attribution facts
|
|
6167
|
+
* (`costAttribution`: phase, agent type, primary role, budget account,
|
|
6168
|
+
* finalize-reserve flag) exactly so this fold can reproduce every
|
|
6169
|
+
* breakdown without live state; entries written before the facts
|
|
6170
|
+
* shipped fold under the documented fallbacks (empty phase, 'unknown'
|
|
6171
|
+
* agent type, role 'loop').
|
|
6152
6172
|
*
|
|
6153
|
-
*
|
|
6154
|
-
*
|
|
6155
|
-
*
|
|
6156
|
-
*
|
|
6157
|
-
*
|
|
6158
|
-
*
|
|
6159
|
-
*
|
|
6160
|
-
*
|
|
6161
|
-
*
|
|
6162
|
-
*
|
|
6173
|
+
* Inclusion policy, applied to the total and EVERY breakdown alike:
|
|
6174
|
+
* terminal usage exactly once, priced per serving slice, entries under
|
|
6175
|
+
* abandoned subtrees contribute zero (their spend is tracked separately
|
|
6176
|
+
* in the abandoned-spend ledger the orchestrator sees). Attempts that
|
|
6177
|
+
* were paid but never abandoned (a cancelled root attempt, a dangling
|
|
6178
|
+
* child) are real spend and stay included everywhere.
|
|
6179
|
+
*
|
|
6180
|
+
* `buildCostReport` folds the LIVE per-run attribution buckets around
|
|
6181
|
+
* the ledger total; it remains for hosts that accumulated their own
|
|
6182
|
+
* `CostAttribution`, but the engine no longer builds outcomes from it.
|
|
6163
6183
|
*
|
|
6164
6184
|
* Unpriced models surface in `unpriced`, never as a silent zero.
|
|
6165
6185
|
*/
|
|
@@ -6174,14 +6194,9 @@ const ROLES = [
|
|
|
6174
6194
|
function emptyByRole() {
|
|
6175
6195
|
return Object.fromEntries(ROLES.map((role) => [role, 0]));
|
|
6176
6196
|
}
|
|
6177
|
-
|
|
6178
|
-
|
|
6179
|
-
|
|
6180
|
-
share: 0,
|
|
6181
|
-
wakes: 0,
|
|
6182
|
-
forcedFinish: false,
|
|
6183
|
-
reserveUsedUsd: 0
|
|
6184
|
-
};
|
|
6197
|
+
/** The orchestrator sub-account naming rule of makeOrchestratorWorkflow. */
|
|
6198
|
+
function isOrchestratorAccount(scope) {
|
|
6199
|
+
return scope === "orchestrator" || scope.endsWith("/orchestrator");
|
|
6185
6200
|
}
|
|
6186
6201
|
/** Folds the per-run attribution buckets into the normative CostReport. */
|
|
6187
6202
|
function buildCostReport(attribution, totalUsd) {
|
|
@@ -6207,16 +6222,30 @@ function buildCostReport(attribution, totalUsd) {
|
|
|
6207
6222
|
};
|
|
6208
6223
|
}
|
|
6209
6224
|
/**
|
|
6210
|
-
* The pure journal fold:
|
|
6211
|
-
* same summation the kernel ledger uses (terminal usage exactly
|
|
6212
|
-
* priced per servedBy, abandoned subtrees contribute zero).
|
|
6225
|
+
* The pure journal fold: the complete CostReport from terminal entries,
|
|
6226
|
+
* the same summation the kernel ledger uses (terminal usage exactly
|
|
6227
|
+
* once, priced per servedBy slice, abandoned subtrees contribute zero).
|
|
6228
|
+
* The orchestrator block folds too: spend attributed to the
|
|
6229
|
+
* orchestrator sub-account, the reserve-funded share of it, the armed
|
|
6230
|
+
* wake count, and the at-cap freeze flag from the journaled cap
|
|
6231
|
+
* decision, so a replay-only resume reproduces the block instead of
|
|
6232
|
+
* reading this process's live accounts (which a replay never charges).
|
|
6213
6233
|
*/
|
|
6214
6234
|
function costReportFromJournal(entries, priceUsd) {
|
|
6215
6235
|
const abandonFold = buildAbandonFold(entries);
|
|
6216
6236
|
const byModel = {};
|
|
6237
|
+
const byPhase = {};
|
|
6238
|
+
const byAgentType = {};
|
|
6239
|
+
const byRole = emptyByRole();
|
|
6217
6240
|
const unpriced = [];
|
|
6218
6241
|
let totalUsd = 0;
|
|
6242
|
+
let orchestratorSpentUsd = 0;
|
|
6243
|
+
let reserveUsedUsd = 0;
|
|
6244
|
+
let wakes = 0;
|
|
6245
|
+
let forcedFinish = false;
|
|
6219
6246
|
for (const entry of entries) {
|
|
6247
|
+
if (entry.kind === "decision" && entry.value?.decisionType === "orchestrator_budget_cap") forcedFinish = true;
|
|
6248
|
+
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
6249
|
if (entry.kind !== "resolution" && entry.kind !== "abandon" && abandonFold.isAbandoned(entry.ref ?? entry.seq)) continue;
|
|
6221
6250
|
if (entry.status === "running" || entry.usage === void 0) continue;
|
|
6222
6251
|
const priced = priceEntryUsage(entry, priceUsd);
|
|
@@ -6226,14 +6255,30 @@ function costReportFromJournal(entries, priceUsd) {
|
|
|
6226
6255
|
});
|
|
6227
6256
|
for (const slice of priced.priced) byModel[slice.servedBy] = (byModel[slice.servedBy] ?? 0) + slice.usd;
|
|
6228
6257
|
totalUsd += priced.usd;
|
|
6258
|
+
const facts = entry.costAttribution;
|
|
6259
|
+
const phase = facts?.phase ?? "";
|
|
6260
|
+
byPhase[phase] = (byPhase[phase] ?? 0) + priced.usd;
|
|
6261
|
+
const agentType = facts?.agentType ?? "unknown";
|
|
6262
|
+
byAgentType[agentType] = (byAgentType[agentType] ?? 0) + priced.usd;
|
|
6263
|
+
byRole[facts?.role ?? "loop"] += priced.usd;
|
|
6264
|
+
if (facts?.budgetAccount !== void 0 && isOrchestratorAccount(facts.budgetAccount)) {
|
|
6265
|
+
orchestratorSpentUsd += priced.usd;
|
|
6266
|
+
if (facts.finalizeReserve === true) reserveUsedUsd += priced.usd;
|
|
6267
|
+
}
|
|
6229
6268
|
}
|
|
6230
6269
|
return {
|
|
6231
6270
|
totalUsd,
|
|
6232
6271
|
byModel,
|
|
6233
|
-
byPhase
|
|
6234
|
-
byAgentType
|
|
6235
|
-
byRole
|
|
6236
|
-
orchestrator:
|
|
6272
|
+
byPhase,
|
|
6273
|
+
byAgentType,
|
|
6274
|
+
byRole,
|
|
6275
|
+
orchestrator: {
|
|
6276
|
+
spentUsd: orchestratorSpentUsd,
|
|
6277
|
+
share: orchestratorSpentUsd / Math.max(totalUsd, .01),
|
|
6278
|
+
wakes,
|
|
6279
|
+
forcedFinish,
|
|
6280
|
+
reserveUsedUsd
|
|
6281
|
+
},
|
|
6237
6282
|
unpriced
|
|
6238
6283
|
};
|
|
6239
6284
|
}
|
|
@@ -7250,7 +7295,7 @@ var NoProgressDetector = class {
|
|
|
7250
7295
|
return this.streakInternal >= this.threshold;
|
|
7251
7296
|
}
|
|
7252
7297
|
describe() {
|
|
7253
|
-
return `no-progress abort after ${this.streakInternal} consecutive turns without tool calls or artifact deltas (threshold ${this.threshold}; docs/
|
|
7298
|
+
return `no-progress abort after ${this.streakInternal} consecutive turns without tool calls or artifact deltas (threshold ${this.threshold}; https://docs.rulvar.com/guide/agents#the-agent-loop-and-turns)`;
|
|
7254
7299
|
}
|
|
7255
7300
|
};
|
|
7256
7301
|
//#endregion
|
|
@@ -8510,6 +8555,28 @@ async function runAgent(options) {
|
|
|
8510
8555
|
await saveBoundary();
|
|
8511
8556
|
continue loop;
|
|
8512
8557
|
}
|
|
8558
|
+
if (options.terminalTool !== void 0) {
|
|
8559
|
+
noProgress.recordTurn({ toolCalls: 0 });
|
|
8560
|
+
if (noProgress.tripped) {
|
|
8561
|
+
status = "limit";
|
|
8562
|
+
abortClass = "no-progress";
|
|
8563
|
+
agentError = {
|
|
8564
|
+
kind: "terminal",
|
|
8565
|
+
retryable: false
|
|
8566
|
+
};
|
|
8567
|
+
errorMessage = noProgress.describe();
|
|
8568
|
+
break;
|
|
8569
|
+
}
|
|
8570
|
+
messages.push({
|
|
8571
|
+
role: "user",
|
|
8572
|
+
parts: [{
|
|
8573
|
+
type: "text",
|
|
8574
|
+
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.`
|
|
8575
|
+
}]
|
|
8576
|
+
});
|
|
8577
|
+
await saveBoundary();
|
|
8578
|
+
continue loop;
|
|
8579
|
+
}
|
|
8513
8580
|
if (options.schema === void 0) {
|
|
8514
8581
|
output = outcome.turn.text;
|
|
8515
8582
|
break;
|
|
@@ -8942,8 +9009,43 @@ var RunBudget = class {
|
|
|
8942
9009
|
controller: new AbortController()
|
|
8943
9010
|
};
|
|
8944
9011
|
if (options.ceilingUsd !== void 0) account.ceilingUsd = options.ceilingUsd;
|
|
9012
|
+
if (options.kind !== void 0) account.kind = options.kind;
|
|
8945
9013
|
this.accounts.set(scope, account);
|
|
8946
9014
|
}
|
|
9015
|
+
/**
|
|
9016
|
+
* The diagnostic projection behind a ceiling error: the first CLOSED
|
|
9017
|
+
* account (projected commitments included, exactly the layer-1
|
|
9018
|
+
* closure test) walking from `scope` toward the root, plus the root
|
|
9019
|
+
* state. 'run budget ceiling reached' under a healthy root misled the
|
|
9020
|
+
* v1.6.0 follow-up review's live probe when only a 0.18 USD
|
|
9021
|
+
* orchestrator cap had crossed under a 0.90 USD root; the message can
|
|
9022
|
+
* now name the account that actually ended the work. An unknown scope
|
|
9023
|
+
* degrades to root-only diagnostics instead of throwing: this runs on
|
|
9024
|
+
* the error path.
|
|
9025
|
+
*/
|
|
9026
|
+
exhaustionDiagnostics(scope) {
|
|
9027
|
+
let chain;
|
|
9028
|
+
try {
|
|
9029
|
+
chain = this.chainOf(scope);
|
|
9030
|
+
} catch {
|
|
9031
|
+
chain = [this.root];
|
|
9032
|
+
}
|
|
9033
|
+
const crossed = chain.find((account) => account.ceilingUsd !== void 0 && account.spentUsd + account.committedReserveUsd + account.finalizeReserveUsd >= account.ceilingUsd);
|
|
9034
|
+
const root = this.root;
|
|
9035
|
+
const diagnostics = { root: {
|
|
9036
|
+
spentUsd: root.spentUsd,
|
|
9037
|
+
...root.ceilingUsd === void 0 ? {} : { ceilingUsd: root.ceilingUsd }
|
|
9038
|
+
} };
|
|
9039
|
+
if (crossed?.ceilingUsd !== void 0) diagnostics.crossed = {
|
|
9040
|
+
scope: crossed.scope,
|
|
9041
|
+
source: crossed.scope === "run" ? "root" : crossed.kind === "orchestrator-cap" ? "orchestrator-cap" : "child-account",
|
|
9042
|
+
ceilingUsd: crossed.ceilingUsd,
|
|
9043
|
+
spentUsd: crossed.spentUsd,
|
|
9044
|
+
committedReserveUsd: crossed.committedReserveUsd,
|
|
9045
|
+
finalizeReserveUsd: crossed.finalizeReserveUsd
|
|
9046
|
+
};
|
|
9047
|
+
return diagnostics;
|
|
9048
|
+
}
|
|
8947
9049
|
accountView(scope) {
|
|
8948
9050
|
const account = this.accounts.get(scope);
|
|
8949
9051
|
if (account === void 0) return;
|
|
@@ -8967,6 +9069,26 @@ var RunBudget = class {
|
|
|
8967
9069
|
if (account?.ceilingUsd === void 0) return;
|
|
8968
9070
|
return Math.max(0, account.ceilingUsd - account.spentUsd - account.committedReserveUsd - account.finalizeReserveUsd);
|
|
8969
9071
|
}
|
|
9072
|
+
/**
|
|
9073
|
+
* The tightest allowance headroom on the chain of `scope`: the minimum
|
|
9074
|
+
* remainder across 'child-allowance' accounts. An allowance ceiling
|
|
9075
|
+
* bounds the child's LIFETIME spend, so projected admission must never
|
|
9076
|
+
* hold more than this against the chain (the layer-2 mirror lives in
|
|
9077
|
+
* the orchestrator admission's childCeiling clamp): a reserve above
|
|
9078
|
+
* the allowance would deny work that the allowance itself already
|
|
9079
|
+
* bounds. Undefined when no allowance account is on the chain; the
|
|
9080
|
+
* clamp never applies to the run root or an orchestrator cap, whose
|
|
9081
|
+
* headroom is shared money that projected admission must protect.
|
|
9082
|
+
*/
|
|
9083
|
+
allowanceHeadroomOf(scope) {
|
|
9084
|
+
let headroom;
|
|
9085
|
+
for (const account of this.chainOf(scope)) {
|
|
9086
|
+
if (account.kind !== "child-allowance" || account.ceilingUsd === void 0) continue;
|
|
9087
|
+
const remainder = Math.max(0, account.ceilingUsd - account.spentUsd - account.committedReserveUsd - account.finalizeReserveUsd);
|
|
9088
|
+
headroom = headroom === void 0 ? remainder : Math.min(headroom, remainder);
|
|
9089
|
+
}
|
|
9090
|
+
return headroom;
|
|
9091
|
+
}
|
|
8970
9092
|
/** Layer 3 ceiling signal of the run root; live streams sever through it. */
|
|
8971
9093
|
get signal() {
|
|
8972
9094
|
return this.root.controller.signal;
|
|
@@ -9324,6 +9446,20 @@ var AdmissionController = class {
|
|
|
9324
9446
|
* journaled by the caller so replay re-delivers it without
|
|
9325
9447
|
* re-evaluation.
|
|
9326
9448
|
*/
|
|
9449
|
+
/**
|
|
9450
|
+
* The reserve the DISPATCH layer will actually commit for this spec:
|
|
9451
|
+
* the estimate (or the flat default) clamped by the explicit child
|
|
9452
|
+
* budget when one exists, because only an explicit budget opens a
|
|
9453
|
+
* child-allowance account at dispatch; the childBudgetFraction cap
|
|
9454
|
+
* never materializes as an account and must not shrink the
|
|
9455
|
+
* projection. The token-count-priced estimate of ctx.agent is
|
|
9456
|
+
* unreachable here (async); a divergence there lands as a journaled
|
|
9457
|
+
* dispatch rejection instead of a strand.
|
|
9458
|
+
*/
|
|
9459
|
+
projectedDispatchReserveUsd(spec) {
|
|
9460
|
+
const base = spec.estCostUsd ?? this.flatReserveUsd;
|
|
9461
|
+
return spec.budgetUsd === void 0 ? base : Math.min(base, spec.budgetUsd);
|
|
9462
|
+
}
|
|
9327
9463
|
admit(spec, options) {
|
|
9328
9464
|
const commitReserve = options?.commitReserve ?? true;
|
|
9329
9465
|
const nodeKey = spec.nodeKey ?? spec.parentAccountScope;
|
|
@@ -9410,7 +9546,8 @@ var AdmissionController = class {
|
|
|
9410
9546
|
}
|
|
9411
9547
|
else {
|
|
9412
9548
|
const remainder = this.budget.remainderOf(spec.parentAccountScope);
|
|
9413
|
-
|
|
9549
|
+
const projection = this.projectedDispatchReserveUsd(spec);
|
|
9550
|
+
if (remainder !== void 0 && (remainder <= 0 || remainder < projection + (spec.pendingReserveUsd ?? 0))) return {
|
|
9414
9551
|
verdict: {
|
|
9415
9552
|
kind: "reject",
|
|
9416
9553
|
reason: { code: "budget" }
|
|
@@ -9791,6 +9928,13 @@ const kTerminalTool = Symbol("rulvar.terminalTool");
|
|
|
9791
9928
|
* graft boot). Dangling redispatch checkpoints take precedence.
|
|
9792
9929
|
*/
|
|
9793
9930
|
const kBootCheckpoint = Symbol("rulvar.bootCheckpoint");
|
|
9931
|
+
/**
|
|
9932
|
+
* Internal AgentOpts channel: marks the orchestrator forced-finish
|
|
9933
|
+
* dispatch, whose spend draws from the released finalize reserve
|
|
9934
|
+
* (DEF-7). Settlement stamps the flag into the terminal's cost
|
|
9935
|
+
* attribution so the journal fold reproduces reserveUsedUsd.
|
|
9936
|
+
*/
|
|
9937
|
+
const kFinalizeReserve = Symbol("rulvar.finalizeReserve");
|
|
9794
9938
|
/** Typed accessor used by the in-package consumers. */
|
|
9795
9939
|
function runtimeOf(ctx) {
|
|
9796
9940
|
const runtime = ctxRuntimes.get(ctx);
|
|
@@ -10386,7 +10530,8 @@ function createCtx(internals, rootWorkflow) {
|
|
|
10386
10530
|
if (internals.flatReserveUsd !== void 0) reserveOptions.flatReserveUsd = internals.flatReserveUsd;
|
|
10387
10531
|
const reserve = internals.pricingOf !== void 0 && internals.pricingOf(loopResolved.ref) === void 0 && opts.estCost === void 0 && profile?.estCost === void 0 ? 0 : admissionReserveUsd(reserveOptions);
|
|
10388
10532
|
const budgetAccount = state.budgetScope ?? "run";
|
|
10389
|
-
internals.budget.
|
|
10533
|
+
const allowanceHeadroomUsd = internals.budget.allowanceHeadroomOf(budgetAccount);
|
|
10534
|
+
internals.budget.admitSpawn(allowanceHeadroomUsd === void 0 ? reserve : Math.min(reserve, allowanceHeadroomUsd), budgetAccount);
|
|
10390
10535
|
let acquired;
|
|
10391
10536
|
if (typeof isolation === "object" && isolation.kind === "worktree") {
|
|
10392
10537
|
const acquireInput = {
|
|
@@ -10653,6 +10798,13 @@ function createCtx(internals, rootWorkflow) {
|
|
|
10653
10798
|
usage: result.usage,
|
|
10654
10799
|
servedBy: result.servedBy,
|
|
10655
10800
|
...result.usageByModel === void 0 ? {} : { usageByModel: result.usageByModel },
|
|
10801
|
+
costAttribution: {
|
|
10802
|
+
...state.phase === void 0 ? {} : { phase: state.phase },
|
|
10803
|
+
agentType,
|
|
10804
|
+
role: primaryRole,
|
|
10805
|
+
budgetAccount: state.budgetScope ?? "run",
|
|
10806
|
+
...opts[kFinalizeReserve] === true ? { finalizeReserve: true } : {}
|
|
10807
|
+
},
|
|
10656
10808
|
transcriptRef: result.transcriptRef
|
|
10657
10809
|
};
|
|
10658
10810
|
if (result.status === "escalated" && result.escalation !== void 0) terminalPatch.escalation = result.escalation;
|
|
@@ -10720,10 +10872,25 @@ function createCtx(internals, rootWorkflow) {
|
|
|
10720
10872
|
bump(internals.cost.byPhase, state.phase ?? "", usd);
|
|
10721
10873
|
bump(internals.cost.byAgentType, agentType, usd);
|
|
10722
10874
|
internals.cost.byRole.set(primaryRole, (internals.cost.byRole.get(primaryRole) ?? 0) + usd);
|
|
10723
|
-
if (result.error?.kind === "budget" || internals.budget.exhausted && result.status !== "ok")
|
|
10724
|
-
|
|
10725
|
-
|
|
10726
|
-
|
|
10875
|
+
if (result.error?.kind === "budget" || internals.budget.exhausted && result.status !== "ok") {
|
|
10876
|
+
const diagnostics = internals.budget.exhaustionDiagnostics(state.budgetScope ?? "run");
|
|
10877
|
+
const crossed = diagnostics.crossed;
|
|
10878
|
+
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`);
|
|
10879
|
+
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: {
|
|
10880
|
+
scope: state.scope,
|
|
10881
|
+
entryRef: terminal.seq,
|
|
10882
|
+
source: crossed?.source ?? "root",
|
|
10883
|
+
rootSpentUsd: diagnostics.root.spentUsd,
|
|
10884
|
+
...diagnostics.root.ceilingUsd === void 0 ? {} : { rootCeilingUsd: diagnostics.root.ceilingUsd },
|
|
10885
|
+
...crossed === void 0 ? {} : {
|
|
10886
|
+
crossedScope: crossed.scope,
|
|
10887
|
+
crossedCeilingUsd: crossed.ceilingUsd,
|
|
10888
|
+
crossedSpentUsd: crossed.spentUsd,
|
|
10889
|
+
crossedCommittedReserveUsd: crossed.committedReserveUsd,
|
|
10890
|
+
crossedFinalizeReserveUsd: crossed.finalizeReserveUsd
|
|
10891
|
+
}
|
|
10892
|
+
} });
|
|
10893
|
+
}
|
|
10727
10894
|
if (opts.fallback !== void 0) {
|
|
10728
10895
|
const trigger = fallbackTriggerOf(result);
|
|
10729
10896
|
if (trigger !== void 0 && opts.fallback.on.includes(trigger)) return runFallbackAttempt(running.seq, trigger, spanId);
|
|
@@ -11008,7 +11175,10 @@ function createCtx(internals, rootWorkflow) {
|
|
|
11008
11175
|
if (verdict.kind !== "admit") throw new ConfigError(`admission verdict '${verdict.kind}' has no producer before M7 (DEF-5)`);
|
|
11009
11176
|
const reserve = verdict.reserve;
|
|
11010
11177
|
const openOptions = { parentScope: budgetAccount };
|
|
11011
|
-
if (reserve.childCeilingUsd !== void 0)
|
|
11178
|
+
if (reserve.childCeilingUsd !== void 0) {
|
|
11179
|
+
openOptions.ceilingUsd = reserve.childCeilingUsd;
|
|
11180
|
+
openOptions.kind = "child-allowance";
|
|
11181
|
+
}
|
|
11012
11182
|
internals.budget.openAccount(childScope, openOptions);
|
|
11013
11183
|
const running = danglingRunning ?? await internals.replayer.appendRunning({
|
|
11014
11184
|
scope: state.scope,
|
|
@@ -11298,6 +11468,8 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
11298
11468
|
const cardText = declaredLadderNames.length === 0 ? profileCard(advertisedProfiles) : `${profileCard(spawnableProfiles)}\nDeclared ladders (tier context for the knowledge card; NOT agentType values, never spawn them): ${declaredLadderNames.join(", ")}.`;
|
|
11299
11469
|
const extension = opts?.extension;
|
|
11300
11470
|
let orchestratorAccount;
|
|
11471
|
+
/** DEF-2 cap drift found in the sync prologue; emitted after boot. */
|
|
11472
|
+
const pendingCapDrifts = [];
|
|
11301
11473
|
let capState;
|
|
11302
11474
|
{
|
|
11303
11475
|
const runCeiling = internals.budget.accountView(callingState.budgetScope ?? "run")?.ceilingUsd;
|
|
@@ -11306,17 +11478,56 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
11306
11478
|
if (fraction > 1) throw new OrchestratorCapConfigError(`capFraction ${String(fraction)} exceeds 1.0 (opting out of the cap is explicit only, up to 1.0 inclusive)`);
|
|
11307
11479
|
const fromFraction = runCeiling === void 0 ? void 0 : fraction * runCeiling;
|
|
11308
11480
|
const bounds = [spec?.capUsd, fromFraction].filter((bound) => bound !== void 0);
|
|
11309
|
-
|
|
11310
|
-
|
|
11481
|
+
const priorReserveDecision = internals.replayer.snapshot().find((entry) => {
|
|
11482
|
+
if (entry.kind !== "decision" || entry.scope !== callingState.scope) return false;
|
|
11483
|
+
return entry.value?.decisionType === "orchestrator_budget_reserve";
|
|
11484
|
+
});
|
|
11485
|
+
if (priorReserveDecision !== void 0) {
|
|
11486
|
+
const frozen = priorReserveDecision.value;
|
|
11487
|
+
const turnEstimateUsd = internals.flatReserveUsd ?? .5;
|
|
11488
|
+
const liveFinalizeReserveUsd = spec?.finalizeReserveUsd ?? (spec?.finalizeTurns ?? 2) * turnEstimateUsd;
|
|
11489
|
+
pendingCapDrifts.push(...bounds.length > 0 && Math.min(...bounds) !== frozen.capUsd ? [{
|
|
11490
|
+
field: "orchestratorCapUsd",
|
|
11491
|
+
frozenValue: frozen.capUsd,
|
|
11492
|
+
liveValue: Math.min(...bounds)
|
|
11493
|
+
}] : [], ...liveFinalizeReserveUsd !== frozen.finalizeReserveUsd ? [{
|
|
11494
|
+
field: "finalizeReserveUsd",
|
|
11495
|
+
frozenValue: frozen.finalizeReserveUsd,
|
|
11496
|
+
liveValue: liveFinalizeReserveUsd
|
|
11497
|
+
}] : []);
|
|
11498
|
+
orchestratorAccount = callingState.scope === "" ? "orchestrator" : `${callingState.scope}/orchestrator`;
|
|
11499
|
+
internals.budget.openAccount(orchestratorAccount, {
|
|
11500
|
+
parentScope: callingState.budgetScope ?? "run",
|
|
11501
|
+
ceilingUsd: frozen.capUsd,
|
|
11502
|
+
kind: "orchestrator-cap"
|
|
11503
|
+
});
|
|
11504
|
+
if (extension !== void 0) internals.budget.commitFinalizeReserve(orchestratorAccount, frozen.finalizeReserveUsd);
|
|
11505
|
+
capState = {
|
|
11506
|
+
effectiveCapUsd: frozen.capUsd,
|
|
11507
|
+
finalizeReserveUsd: frozen.finalizeReserveUsd,
|
|
11508
|
+
finalizeTurns: frozen.finalizeTurns,
|
|
11509
|
+
turnEstimateUsd,
|
|
11510
|
+
atCap: spec?.atCap ?? "finish-with-partial",
|
|
11511
|
+
source: frozen.source
|
|
11512
|
+
};
|
|
11513
|
+
}
|
|
11514
|
+
if (capState === void 0 && extension !== void 0 && bounds.length === 0) throw new OrchestratorCapConfigError("the orchestrator cap is unresolvable: the run has no USD ceiling and no explicit budget.capUsd; PlanRunner requires a resolved effectiveCap");
|
|
11515
|
+
if (capState === void 0 && bounds.length > 0) {
|
|
11311
11516
|
const effectiveCapUsd = Math.min(...bounds);
|
|
11312
11517
|
const turnEstimateUsd = internals.flatReserveUsd ?? .5;
|
|
11313
11518
|
const finalizeTurns = spec?.finalizeTurns ?? 2;
|
|
11314
11519
|
const finalizeReserveUsd = spec?.finalizeReserveUsd ?? finalizeTurns * turnEstimateUsd;
|
|
11315
11520
|
if (extension !== void 0 && effectiveCapUsd < finalizeReserveUsd) throw new OrchestratorCapConfigError(`effectiveCap ${effectiveCapUsd.toFixed(4)} USD is below the finalize reserve ${finalizeReserveUsd.toFixed(4)} USD`);
|
|
11521
|
+
if (spec?.capUsd !== void 0 && spec.capFraction === void 0 && effectiveCapUsd < spec.capUsd) internals.events.emit({
|
|
11522
|
+
type: "log",
|
|
11523
|
+
level: "warn",
|
|
11524
|
+
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`
|
|
11525
|
+
}, callingState.spanId);
|
|
11316
11526
|
orchestratorAccount = callingState.scope === "" ? "orchestrator" : `${callingState.scope}/orchestrator`;
|
|
11317
11527
|
internals.budget.openAccount(orchestratorAccount, {
|
|
11318
11528
|
parentScope: callingState.budgetScope ?? "run",
|
|
11319
|
-
ceilingUsd: effectiveCapUsd
|
|
11529
|
+
ceilingUsd: effectiveCapUsd,
|
|
11530
|
+
kind: "orchestrator-cap"
|
|
11320
11531
|
});
|
|
11321
11532
|
if (extension !== void 0) internals.budget.commitFinalizeReserve(orchestratorAccount, finalizeReserveUsd);
|
|
11322
11533
|
capState = {
|
|
@@ -11332,6 +11543,15 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
11332
11543
|
const records = /* @__PURE__ */ new Map();
|
|
11333
11544
|
const byOrdinal = /* @__PURE__ */ new Map();
|
|
11334
11545
|
const rejectedByOrdinal = /* @__PURE__ */ new Map();
|
|
11546
|
+
/**
|
|
11547
|
+
* The journaled spec behind each recovered ordinal: the idempotent
|
|
11548
|
+
* re-execution guard compares it against the incoming call, because
|
|
11549
|
+
* after a cross-attempt resume a REGENERATED turn (the boundary
|
|
11550
|
+
* checkpoint predates the lost turn) may decide differently, and
|
|
11551
|
+
* handing it the prior ordinal's handle would bind the transcript
|
|
11552
|
+
* to a stranger's child.
|
|
11553
|
+
*/
|
|
11554
|
+
const recoveredSpecByOrdinal = /* @__PURE__ */ new Map();
|
|
11335
11555
|
let nextOrdinal = 0;
|
|
11336
11556
|
let orchSeq;
|
|
11337
11557
|
const deliveredNodeIds = /* @__PURE__ */ new Set();
|
|
@@ -11367,15 +11587,18 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
11367
11587
|
const controller = new AbortController();
|
|
11368
11588
|
const upstream = callingState.signal ?? internals.runSignal;
|
|
11369
11589
|
const scope = placement?.childScope ?? childScopeOf();
|
|
11370
|
-
if (placement
|
|
11590
|
+
if (placement?.ownAccount === true) internals.budget.openAccount(scope, {
|
|
11371
11591
|
parentScope: callingState.budgetScope ?? "run",
|
|
11372
|
-
...placement.childCeilingUsd === void 0 ? {} : {
|
|
11592
|
+
...placement.childCeilingUsd === void 0 ? {} : {
|
|
11593
|
+
ceilingUsd: placement.childCeilingUsd,
|
|
11594
|
+
kind: "child-allowance"
|
|
11595
|
+
}
|
|
11373
11596
|
});
|
|
11374
11597
|
const childState = {
|
|
11375
11598
|
scope,
|
|
11376
11599
|
spanId: internals.spans.mint(callingState.spanId),
|
|
11377
11600
|
signal: upstream === void 0 ? controller.signal : AbortSignal.any([upstream, controller.signal]),
|
|
11378
|
-
budgetScope: placement
|
|
11601
|
+
budgetScope: placement?.ownAccount === true ? scope : callingState.budgetScope ?? "run"
|
|
11379
11602
|
};
|
|
11380
11603
|
let resolveHandle = () => void 0;
|
|
11381
11604
|
const handlePromise = new Promise((resolve) => {
|
|
@@ -11438,6 +11661,10 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
11438
11661
|
profiles: advertisedProfiles,
|
|
11439
11662
|
gates: internals.defaults.gates ?? {},
|
|
11440
11663
|
...internals.budget.ceilingUsd === void 0 ? {} : { runCeilingUsd: internals.budget.ceilingUsd },
|
|
11664
|
+
...capState === void 0 ? {} : {
|
|
11665
|
+
orchestratorCapUsd: capState.effectiveCapUsd,
|
|
11666
|
+
finalizeReserveUsd: capState.finalizeReserveUsd
|
|
11667
|
+
},
|
|
11441
11668
|
mintId: createCanonicalIdMinter(),
|
|
11442
11669
|
random: (key) => runtime.runInScope(callingState, () => Promise.resolve(ctx.random(key))),
|
|
11443
11670
|
append: (input) => internals.replayer.appendSinglePhase({
|
|
@@ -11457,6 +11684,7 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
11457
11684
|
nextOrdinal += 1;
|
|
11458
11685
|
return { handle: (await dispatchChild(spec, spawnOrdinal, identity, {
|
|
11459
11686
|
childScope,
|
|
11687
|
+
ownAccount: true,
|
|
11460
11688
|
...spec.budgetUsd === void 0 ? {} : { childCeilingUsd: spec.budgetUsd }
|
|
11461
11689
|
})).handle };
|
|
11462
11690
|
},
|
|
@@ -11487,33 +11715,61 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
11487
11715
|
handle
|
|
11488
11716
|
};
|
|
11489
11717
|
};
|
|
11490
|
-
/**
|
|
11718
|
+
/**
|
|
11719
|
+
* True when `scope` is a root-attempt scope of THIS orchestration:
|
|
11720
|
+
* agentScope(callingState.scope, n) for some dispatch seq n. Nested
|
|
11721
|
+
* orchestrations live under their own wf: child scopes and never
|
|
11722
|
+
* match a foreign calling scope.
|
|
11723
|
+
*/
|
|
11724
|
+
const scopeOfThisOrchestration = (scope) => {
|
|
11725
|
+
const prefix = callingState.scope === "" ? "" : `${callingState.scope}/`;
|
|
11726
|
+
return scope.startsWith(prefix) && /^agent:\d+$/.test(scope.slice(prefix.length));
|
|
11727
|
+
};
|
|
11728
|
+
/**
|
|
11729
|
+
* Rebuilds spawn records from the journal (the crash-resume
|
|
11730
|
+
* contract). Recovery is ORCHESTRATION-scoped, not attempt-scoped:
|
|
11731
|
+
* decisions journal at the orchestrate call's own scope, which is
|
|
11732
|
+
* stable across root attempts, so a rerun after a cancelled root
|
|
11733
|
+
* (the budget-abort shape the v1.6.0 follow-up review resumed) sees
|
|
11734
|
+
* every prior decision instead of re-deciding and re-paying.
|
|
11735
|
+
* Recovered children re-dispatch PINNED to their journaled child
|
|
11736
|
+
* scope: settled ones forward-match and replay for free, a dangling
|
|
11737
|
+
* one redispatches live (at-least-once), and a decision without a
|
|
11738
|
+
* dispatch entry rolls forward to a fresh dispatch.
|
|
11739
|
+
*/
|
|
11491
11740
|
const recover = async () => {
|
|
11492
|
-
const
|
|
11741
|
+
const currentScope = childScopeOf();
|
|
11493
11742
|
const admissions = internals.replayer.snapshot().filter((entry) => {
|
|
11494
|
-
if (entry.kind !== "decision") return false;
|
|
11743
|
+
if (entry.kind !== "decision" || entry.scope !== callingState.scope) return false;
|
|
11495
11744
|
const value = entry.value;
|
|
11496
|
-
return value?.decisionType === "spawn-admission" && (value.origin === "spawn_agent" || value.origin === "parallel_agents")
|
|
11745
|
+
return value?.decisionType === "spawn-admission" && (value.origin === "spawn_agent" || value.origin === "parallel_agents");
|
|
11497
11746
|
}).map((entry) => entry.value).sort((a, b) => a.spawnOrdinal - b.spawnOrdinal);
|
|
11498
11747
|
for (const value of admissions) {
|
|
11499
11748
|
nextOrdinal = Math.max(nextOrdinal, value.spawnOrdinal + 1);
|
|
11500
11749
|
const decision = value.decision;
|
|
11750
|
+
recoveredSpecByOrdinal.set(value.spawnOrdinal, value.spec);
|
|
11501
11751
|
if (decision.verdict.kind !== "admit") {
|
|
11502
11752
|
rejectedByOrdinal.set(value.spawnOrdinal, decision);
|
|
11503
11753
|
continue;
|
|
11504
11754
|
}
|
|
11505
|
-
admission.recoverChild(
|
|
11506
|
-
|
|
11755
|
+
admission.recoverChild(currentScope);
|
|
11756
|
+
const childScope = value.childScope ?? value.orchestratorScope;
|
|
11757
|
+
const record = await dispatchChild(value.spec, value.spawnOrdinal, {
|
|
11507
11758
|
nodeId: decision.nodeId ?? "unknown",
|
|
11508
11759
|
logicalTaskId: decision.verdict.lineage.logicalTaskId
|
|
11509
|
-
});
|
|
11760
|
+
}, { childScope });
|
|
11761
|
+
const dispatched = internals.replayer.snapshot().find((entry) => entry.seq === record.handle);
|
|
11762
|
+
if (dispatched !== void 0) {
|
|
11763
|
+
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);
|
|
11764
|
+
}
|
|
11510
11765
|
}
|
|
11511
|
-
const wakePrefix = `wake:${String(orchSeq ?? -1)}:`;
|
|
11512
11766
|
for (const entry of internals.replayer.snapshot()) {
|
|
11513
11767
|
if (entry.status !== "suspended" || entry.kind !== "external") continue;
|
|
11768
|
+
if (!scopeOfThisOrchestration(entry.scope)) continue;
|
|
11514
11769
|
const payload = entry.value;
|
|
11515
|
-
|
|
11516
|
-
|
|
11770
|
+
const match = typeof payload?.key === "string" ? /^wake:\d+:(\d+)$/.exec(payload.key) : null;
|
|
11771
|
+
if (match === null) continue;
|
|
11772
|
+
wakeOrdinal = Math.max(wakeOrdinal, Number(match[1]) + 1);
|
|
11517
11773
|
const suspension = internals.replayer.suspensionState(entry.seq);
|
|
11518
11774
|
if (suspension.state === "resolved") markDelivered(suspension.value);
|
|
11519
11775
|
}
|
|
@@ -11641,10 +11897,12 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
11641
11897
|
await recoveryDone;
|
|
11642
11898
|
const spawnOrdinal = nextOrdinal;
|
|
11643
11899
|
nextOrdinal += 1;
|
|
11900
|
+
const priorSpec = recoveredSpecByOrdinal.get(spawnOrdinal);
|
|
11901
|
+
const specMatches = priorSpec === void 0 || priorSpec.agentType === params.agentType && priorSpec.prompt === params.prompt;
|
|
11644
11902
|
const recovered = byOrdinal.get(spawnOrdinal);
|
|
11645
|
-
if (recovered !== void 0) return { handle: recovered.handle };
|
|
11903
|
+
if (recovered !== void 0 && specMatches) return { handle: recovered.handle };
|
|
11646
11904
|
const recoveredRejection = rejectedByOrdinal.get(spawnOrdinal);
|
|
11647
|
-
if (recoveredRejection !== void 0) throw new AdmissionRejectedError(`admission rejected spawn ordinal ${String(spawnOrdinal)} (recovered verdict)`, { data: { decision: recoveredRejection } });
|
|
11905
|
+
if (recoveredRejection !== void 0 && specMatches) throw new AdmissionRejectedError(`admission rejected spawn ordinal ${String(spawnOrdinal)} (recovered verdict)`, { data: { decision: recoveredRejection } });
|
|
11648
11906
|
if (opts?.maxSpawns !== void 0 && spawnOrdinal >= opts.maxSpawns) {
|
|
11649
11907
|
internals.events.emit({
|
|
11650
11908
|
type: "spawn:rejected",
|
|
@@ -11664,6 +11922,7 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
11664
11922
|
parentAccountScope: callingState.budgetScope ?? "run",
|
|
11665
11923
|
nodeKey: scope,
|
|
11666
11924
|
...params.budgetUsd === void 0 ? {} : { budgetUsd: params.budgetUsd },
|
|
11925
|
+
...profile?.estCost === void 0 ? {} : { estCostUsd: profile.estCost },
|
|
11667
11926
|
...params.lineage === void 0 ? {} : { lineage: {
|
|
11668
11927
|
continues: params.lineage.continues,
|
|
11669
11928
|
causeRef: params.lineage.causeRef,
|
|
@@ -11827,6 +12086,12 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
11827
12086
|
}
|
|
11828
12087
|
};
|
|
11829
12088
|
if (extension?.boot !== void 0) await extension.boot(io);
|
|
12089
|
+
for (const drift of pendingCapDrifts) internals.events.emit({
|
|
12090
|
+
type: "termination:config-drift",
|
|
12091
|
+
field: drift.field,
|
|
12092
|
+
frozenValue: drift.frozenValue,
|
|
12093
|
+
liveValue: drift.liveValue
|
|
12094
|
+
}, callingState.spanId);
|
|
11830
12095
|
let kbCardText;
|
|
11831
12096
|
const appendKbPin = async (decisionType, key) => {
|
|
11832
12097
|
const handle = internals.knowledge;
|
|
@@ -11870,7 +12135,7 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
11870
12135
|
}
|
|
11871
12136
|
const fullCardText = kbCardText === void 0 ? cardText : `${cardText}\n${kbCardText}`;
|
|
11872
12137
|
const reserveKey = deriverV2.deriveKey({ kind: "orchestrator-budget-reserve" });
|
|
11873
|
-
if (extension !== void 0 && capState !== void 0 && !internals.replayer.snapshot().some((entry) => entry.kind === "decision" && entry.key === reserveKey)) {
|
|
12138
|
+
if (extension !== void 0 && capState !== void 0 && !internals.replayer.snapshot().some((entry) => entry.kind === "decision" && entry.scope === callingState.scope && entry.key === reserveKey)) {
|
|
11874
12139
|
const initRef = internals.replayer.snapshot().find((entry) => entry.kind === "termination.init")?.seq;
|
|
11875
12140
|
await internals.replayer.appendSinglePhase({
|
|
11876
12141
|
scope: callingState.scope,
|
|
@@ -11902,7 +12167,11 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
11902
12167
|
orchSeq = seq;
|
|
11903
12168
|
recover().then(releaseRecovery, releaseRecovery);
|
|
11904
12169
|
},
|
|
11905
|
-
[kTerminalTool]: { name: FINISH_TOOL_NAME }
|
|
12170
|
+
[kTerminalTool]: { name: FINISH_TOOL_NAME },
|
|
12171
|
+
...(() => {
|
|
12172
|
+
const priorCancelledRoot = internals.replayer.snapshot().filter((entry) => entry.kind === "agent" && entry.scope === callingState.scope && entry.status === "cancelled" && entry.checkpointRef !== void 0).at(-1);
|
|
12173
|
+
return priorCancelledRoot?.checkpointRef === void 0 ? {} : { [kBootCheckpoint]: priorCancelledRoot.checkpointRef };
|
|
12174
|
+
})()
|
|
11906
12175
|
};
|
|
11907
12176
|
const orchestratorState = { ...callingState };
|
|
11908
12177
|
if (orchestratorAccount !== void 0) orchestratorState.budgetScope = orchestratorAccount;
|
|
@@ -11928,7 +12197,8 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
11928
12197
|
limits: { maxTurns: capState?.finalizeTurns ?? 2 },
|
|
11929
12198
|
...capState === void 0 ? {} : { estCost: capState.finalizeReserveUsd },
|
|
11930
12199
|
...opts?.model === void 0 ? {} : { model: opts.model },
|
|
11931
|
-
[kTerminalTool]: { name: FINISH_TOOL_NAME }
|
|
12200
|
+
[kTerminalTool]: { name: FINISH_TOOL_NAME },
|
|
12201
|
+
[kFinalizeReserve]: true
|
|
11932
12202
|
};
|
|
11933
12203
|
const finalState = { ...callingState };
|
|
11934
12204
|
if (orchestratorAccount !== void 0) finalState.budgetScope = orchestratorAccount;
|
|
@@ -12109,14 +12379,20 @@ const detection = new AsyncLocalStorage();
|
|
|
12109
12379
|
let globalsPatched = false;
|
|
12110
12380
|
/**
|
|
12111
12381
|
* Stack line 0 names the Error, line 1 this helper, line 2 the patched
|
|
12112
|
-
* global, line 3 the caller whose provenance decides
|
|
12113
|
-
*
|
|
12114
|
-
*
|
|
12115
|
-
*
|
|
12382
|
+
* global, line 3 the caller whose provenance decides (the layout is
|
|
12383
|
+
* pinned by construction: this helper is only ever called by the two
|
|
12384
|
+
* patched globals). Two origins are exempt: installed dependencies (a
|
|
12385
|
+
* provider SDK, any transitive package, rulvar's own published dist),
|
|
12386
|
+
* which live under node_modules, and Node's own machinery (the undici
|
|
12387
|
+
* transport behind fetch, timers, stream internals), whose frames carry
|
|
12388
|
+
* `node:` specifiers and inherit the run's async context. The guard
|
|
12389
|
+
* exists for workflow code, which imports from both but lives in
|
|
12390
|
+
* neither.
|
|
12116
12391
|
*/
|
|
12117
12392
|
function libraryCaller() {
|
|
12118
12393
|
const caller = (/* @__PURE__ */ new Error()).stack?.split("\n")[3];
|
|
12119
|
-
|
|
12394
|
+
if (caller === void 0) return false;
|
|
12395
|
+
return caller.includes("node_modules") || /[(\s]node:/.test(caller);
|
|
12120
12396
|
}
|
|
12121
12397
|
/**
|
|
12122
12398
|
* Patches Date.now and Math.random ONCE per process and never restores:
|
|
@@ -12468,7 +12744,7 @@ function createEngine(options) {
|
|
|
12468
12744
|
dropped: internals.dropped,
|
|
12469
12745
|
pending,
|
|
12470
12746
|
usage: ledger.usage,
|
|
12471
|
-
cost:
|
|
12747
|
+
cost: costReportFromJournal(replayer.snapshot(), priceUsd)
|
|
12472
12748
|
};
|
|
12473
12749
|
if (value !== void 0 && (status === "ok" || status === "exhausted")) outcome.value = value;
|
|
12474
12750
|
if (wireError !== void 0) outcome.error = wireError;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rulvar/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"description": "Rulvar core: L0 contracts, journal kernel, ctx primitives, agent runtime, model router, tool system, dynamic orchestrator, InMemory and JSONL stores, event stream.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|