@rulvar/core 1.4.0 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -602,6 +602,36 @@ type AbandonPayload = {
602
602
  retainCheckpoint?: boolean; /** Default false; counts against the pin cap (DEF-5). */
603
603
  retainWorktree?: boolean;
604
604
  };
605
+ /** One serving model's slice of a multi-model agent call's usage. */
606
+ interface UsageSlice {
607
+ servedBy: ModelRef;
608
+ usage: Usage;
609
+ }
610
+ /**
611
+ * The per-model slices of a terminal entry: the recorded split when the
612
+ * call spanned several models, else the whole usage attributed to
613
+ * `servedBy`. The fallback is what makes every journal written before the
614
+ * split shipped price exactly as it did before.
615
+ */
616
+ declare function entryUsageSlices(entry: JournalEntry): UsageSlice[];
617
+ /** A priced slice, plus the total and the gaps the price table did not cover. */
618
+ interface PricedUsage {
619
+ /** Total of every slice the price table covered. */
620
+ usd: number;
621
+ /** Covered slices with their prices; the basis of per-model attribution. */
622
+ priced: Array<UsageSlice & {
623
+ usd: number;
624
+ }>;
625
+ /** Slices with no price row: surfaced as unpriced, never a silent zero. */
626
+ unpriced: UsageSlice[];
627
+ }
628
+ /**
629
+ * The single pricing fold over one terminal entry, shared by the kernel
630
+ * ledger and the CostReport fold so a run's total and its per-model
631
+ * breakdown can never disagree. Each slice is priced at ITS OWN model's
632
+ * rate.
633
+ */
634
+ declare function priceEntryUsage(entry: JournalEntry, priceUsd: (servedBy: ModelRef, usage: Usage) => number | undefined): PricedUsage;
605
635
  /**
606
636
  * Final entry form (hashVersion 2).
607
637
  * All journaled values MUST be JSON-serializable; a violation raises a
@@ -627,6 +657,18 @@ type JournalEntry = {
627
657
  usage?: Usage; /** True when the stream was cut at the budget ceiling or by a stream failure. */
628
658
  usageApprox?: boolean; /** Who actually served (failover changes only this, never the key). */
629
659
  servedBy?: ModelRef;
660
+ /**
661
+ * Terminal agent entries whose phases were served by MORE THAN ONE
662
+ * model: usage split by the model that actually served each slice. The
663
+ * loop, extract, finalize, and summarize roles resolve independently,
664
+ * so a single agent call routinely spans models at different prices;
665
+ * pricing the whole call at `servedBy` bills the cheap extract at the
666
+ * loop model's rate. Absent when one model served the whole call, and
667
+ * on entries written before the split shipped: readers fall back to
668
+ * pricing `usage` at `servedBy`, which is exactly correct for those.
669
+ * Policy, never identity: it does not enter the content key.
670
+ */
671
+ usageByModel?: UsageSlice[];
630
672
  transcriptRef?: string;
631
673
  checkpointRef?: string;
632
674
  /**
@@ -2018,6 +2060,8 @@ interface TerminalPatch {
2018
2060
  usage?: Usage;
2019
2061
  usageApprox?: boolean;
2020
2062
  servedBy?: ModelRef;
2063
+ /** Set only when the call spanned several serving models; see JournalEntry. */
2064
+ usageByModel?: UsageSlice[];
2021
2065
  transcriptRef?: string;
2022
2066
  checkpointRef?: string;
2023
2067
  /** Terminal agent entries: Artifact list. */
@@ -2312,6 +2356,14 @@ interface CheckpointState {
2312
2356
  turns: number;
2313
2357
  /** Usage accumulated so far (not yet journaled: terminals carry totals). */
2314
2358
  usage: Usage;
2359
+ /**
2360
+ * The same usage split by serving model, so a dangling redispatch
2361
+ * restores the per-model breakdown instead of collapsing every paid
2362
+ * turn onto the loop model. Absent on checkpoints written before the
2363
+ * split shipped: those restore the aggregate against the loop model,
2364
+ * exactly as they did then.
2365
+ */
2366
+ usageByModel?: UsageSlice[];
2315
2367
  toolCallsUsed: number;
2316
2368
  schemaAttempts: number;
2317
2369
  /** Compaction points; producers arrive with M4-T03. */
@@ -2641,6 +2693,14 @@ interface AgentResult<T> {
2641
2693
  * differs from the requested spec only under transport failover.
2642
2694
  */
2643
2695
  servedBy: ModelRef;
2696
+ /**
2697
+ * Present only when the call spanned MORE THAN ONE serving model (the
2698
+ * loop, extract, finalize, and summarize roles resolve independently):
2699
+ * usage split per model, so `costUsd` and every cost bucket price each
2700
+ * slice at its own rate. Absent for a single-model call, which
2701
+ * (usage, servedBy) already describes exactly.
2702
+ */
2703
+ usageByModel?: UsageSlice[];
2644
2704
  transcriptRef: string;
2645
2705
  artifacts?: Artifact[];
2646
2706
  error?: AgentError;
@@ -3268,6 +3328,8 @@ declare class RunBudget {
3268
3328
  private usageInternal;
3269
3329
  private agentsSpawnedInternal;
3270
3330
  private exhaustedInternal;
3331
+ /** Models already warned about; the warning fires once per model per run. */
3332
+ private readonly unpricedWarned;
3271
3333
  constructor(options: {
3272
3334
  ceilingUsd?: number;
3273
3335
  lifetimeSpawnCap?: number;
@@ -5153,12 +5215,27 @@ interface Workflow<A = unknown, R = unknown> {
5153
5215
  readonly name: string;
5154
5216
  readonly argsSchema?: SchemaSpec<A>;
5155
5217
  readonly errorPolicy: ErrorPolicy;
5218
+ /**
5219
+ * Workflow defaults: the third layer of the resolution chain, under the
5220
+ * call override and the agent profile and over the engine defaults.
5221
+ * A workflow that declares nothing contributes no layer and resolves
5222
+ * exactly as it did before. The layer follows the CALL TREE, not the
5223
+ * file: a child spawned through `ctx.workflow` contributes ITS OWN
5224
+ * defaults inside its scope, so nesting a cheap workflow under an
5225
+ * expensive one does the obvious thing.
5226
+ */
5227
+ readonly model?: ModelSpec;
5228
+ readonly routing?: Partial<Record<InvocationRole, ModelSpec>>;
5229
+ readonly effort?: Effort;
5156
5230
  readonly body: (ctx: Ctx<never>, args: A) => Promise<R>;
5157
5231
  }
5158
5232
  declare function defineWorkflow<A, R, P extends ErrorPolicy = "strict">(meta: {
5159
5233
  name: string;
5160
5234
  args?: SchemaSpec<A>;
5161
- errorPolicy?: P;
5235
+ errorPolicy?: P; /** Workflow defaults: resolution-chain layer 3. See Workflow. */
5236
+ model?: ModelSpec;
5237
+ routing?: Partial<Record<InvocationRole, ModelSpec>>;
5238
+ effort?: Effort;
5162
5239
  }, body: (ctx: Ctx<P>, args: A) => Promise<R>): Workflow<A, R>;
5163
5240
  /**
5164
5241
  * Span-aware event sink: bodies are stamped into the WorkflowEvent
@@ -5262,7 +5339,11 @@ interface RunInternals {
5262
5339
  * one ctx object while journaling under their own scope paths (I3:
5263
5340
  * structure from call-and-return only).
5264
5341
  */
5265
- declare function createCtx(internals: RunInternals): Ctx<ErrorPolicy>;
5342
+ declare function createCtx(internals: RunInternals, rootWorkflow?: {
5343
+ model?: ModelSpec;
5344
+ routing?: Partial<Record<InvocationRole, ModelSpec>>;
5345
+ effort?: Effort;
5346
+ }): Ctx<ErrorPolicy>;
5266
5347
  /**
5267
5348
  * Runs a workflow body against a fresh ctx: the engine core that
5268
5349
  * engine.run wraps with RunHandle, events, and outcome assembly (M1-T11).
@@ -6019,4 +6100,4 @@ interface SandboxBridge {
6019
6100
  }
6020
6101
  declare function createSandboxBridge(ctx: Ctx<never>, options: SandboxBridgeOptions): SandboxBridge;
6021
6102
  //#endregion
6022
- 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, type Pricing, 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, 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, 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, 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, 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 };
6103
+ 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 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, 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
@@ -1750,6 +1750,46 @@ async function validateSchemaSpec(spec, value) {
1750
1750
  /** 1 = round 1; 2 = current. */
1751
1751
  const CURRENT_HASH_VERSION = 2;
1752
1752
  /**
1753
+ * The per-model slices of a terminal entry: the recorded split when the
1754
+ * call spanned several models, else the whole usage attributed to
1755
+ * `servedBy`. The fallback is what makes every journal written before the
1756
+ * split shipped price exactly as it did before.
1757
+ */
1758
+ function entryUsageSlices(entry) {
1759
+ if (entry.usage === void 0) return [];
1760
+ if (entry.usageByModel !== void 0 && entry.usageByModel.length > 0) return entry.usageByModel;
1761
+ return entry.servedBy === void 0 ? [] : [{
1762
+ servedBy: entry.servedBy,
1763
+ usage: entry.usage
1764
+ }];
1765
+ }
1766
+ /**
1767
+ * The single pricing fold over one terminal entry, shared by the kernel
1768
+ * ledger and the CostReport fold so a run's total and its per-model
1769
+ * breakdown can never disagree. Each slice is priced at ITS OWN model's
1770
+ * rate.
1771
+ */
1772
+ function priceEntryUsage(entry, priceUsd) {
1773
+ const result = {
1774
+ usd: 0,
1775
+ priced: [],
1776
+ unpriced: []
1777
+ };
1778
+ for (const slice of entryUsageSlices(entry)) {
1779
+ const usd = priceUsd(slice.servedBy, slice.usage);
1780
+ if (usd === void 0) {
1781
+ result.unpriced.push(slice);
1782
+ continue;
1783
+ }
1784
+ result.usd += usd;
1785
+ result.priced.push({
1786
+ ...slice,
1787
+ usd
1788
+ });
1789
+ }
1790
+ return result;
1791
+ }
1792
+ /**
1753
1793
  * Round-1 normalization: hashVersion is taken from `hashVersion`, else
1754
1794
  * from the legacy `v` field, else 1. Stores are never rewritten;
1755
1795
  * normalization happens at read.
@@ -3201,7 +3241,7 @@ function scanJournalCompatibility(runId, entries, registry) {
3201
3241
  min,
3202
3242
  max
3203
3243
  },
3204
- hint: tooNew ? "upgrade rulvar" : `enable deriverV${entry.hashVersion} from @rulvar/compat via extraDerivers`
3244
+ hint: tooNew ? "upgrade rulvar" : `register a hashVersion ${entry.hashVersion} KeyDeriver through createEngine({ extraDerivers }); @rulvar/compat ships the frozen profiles`
3205
3245
  });
3206
3246
  }
3207
3247
  }
@@ -5443,6 +5483,7 @@ var Replayer = class {
5443
5483
  if (patch.usage !== void 0) entry.usage = patch.usage;
5444
5484
  if (patch.usageApprox !== void 0) entry.usageApprox = patch.usageApprox;
5445
5485
  if (patch.servedBy !== void 0) entry.servedBy = patch.servedBy;
5486
+ if (patch.usageByModel !== void 0) entry.usageByModel = patch.usageByModel;
5446
5487
  if (patch.transcriptRef !== void 0) entry.transcriptRef = patch.transcriptRef;
5447
5488
  if (patch.checkpointRef !== void 0) entry.checkpointRef = patch.checkpointRef;
5448
5489
  if (patch.artifacts !== void 0) entry.artifacts = toJournalValue(patch.artifacts, "terminal artifacts");
@@ -5486,7 +5527,7 @@ var Replayer = class {
5486
5527
  usage.cacheReadTokens += entry.usage.cacheReadTokens;
5487
5528
  usage.cacheWriteTokens += entry.usage.cacheWriteTokens;
5488
5529
  reasoning += entry.usage.reasoningTokens ?? 0;
5489
- usd += this.priceUsd?.(entry.servedBy, entry.usage) ?? 0;
5530
+ if (this.priceUsd !== void 0) usd += priceEntryUsage(entry, this.priceUsd).usd;
5490
5531
  }
5491
5532
  if (reasoning > 0) usage.reasoningTokens = reasoning;
5492
5533
  return {
@@ -6178,18 +6219,13 @@ function costReportFromJournal(entries, priceUsd) {
6178
6219
  for (const entry of entries) {
6179
6220
  if (entry.kind !== "resolution" && entry.kind !== "abandon" && abandonFold.isAbandoned(entry.ref ?? entry.seq)) continue;
6180
6221
  if (entry.status === "running" || entry.usage === void 0) continue;
6181
- const servedBy = entry.servedBy;
6182
- if (servedBy === void 0) continue;
6183
- const usd = priceUsd(servedBy, entry.usage);
6184
- if (usd === void 0) {
6185
- unpriced.push({
6186
- model: servedBy,
6187
- usage: entry.usage
6188
- });
6189
- continue;
6190
- }
6191
- byModel[servedBy] = (byModel[servedBy] ?? 0) + usd;
6192
- totalUsd += usd;
6222
+ const priced = priceEntryUsage(entry, priceUsd);
6223
+ for (const slice of priced.unpriced) unpriced.push({
6224
+ model: slice.servedBy,
6225
+ usage: slice.usage
6226
+ });
6227
+ for (const slice of priced.priced) byModel[slice.servedBy] = (byModel[slice.servedBy] ?? 0) + slice.usd;
6228
+ totalUsd += priced.usd;
6193
6229
  }
6194
6230
  return {
6195
6231
  totalUsd,
@@ -6822,7 +6858,13 @@ function resolveModelInvocation(options) {
6822
6858
  });
6823
6859
  const requestedEffort = merged.effort ?? ROLE_EFFORT_DEFAULTS[role];
6824
6860
  const { adapterId, model } = parseModelRef(merged.model);
6825
- const caps = options.capsOf(merged.model);
6861
+ let caps;
6862
+ try {
6863
+ caps = options.capsOf(merged.model);
6864
+ } catch (thrown) {
6865
+ if (thrown instanceof ConfigError) throw new ConfigError(`role '${role}': ${thrown.message}`);
6866
+ throw thrown;
6867
+ }
6826
6868
  const scrubs = [];
6827
6869
  let wireEffort = requestedEffort;
6828
6870
  if (wireEffort !== void 0 && !caps.reasoningEfforts.includes(wireEffort)) {
@@ -7735,6 +7777,7 @@ async function runAgent(options) {
7735
7777
  }]
7736
7778
  }];
7737
7779
  let totalUsage = ZERO_USAGE$1;
7780
+ const usageByModel = /* @__PURE__ */ new Map();
7738
7781
  let turns = 0;
7739
7782
  let schemaAttempts = 0;
7740
7783
  let output = null;
@@ -7764,8 +7807,31 @@ async function runAgent(options) {
7764
7807
  toolCallsUsed = restored.toolCallsUsed;
7765
7808
  schemaAttempts = restored.schemaAttempts;
7766
7809
  compactionPoints.push(...restored.compaction);
7767
- options.budget?.onUsage(restored.usage, servedBy);
7810
+ const restoredSlices = restored.usageByModel ?? [{
7811
+ servedBy,
7812
+ usage: restored.usage
7813
+ }];
7814
+ for (const slice of restoredSlices) {
7815
+ usageByModel.set(slice.servedBy, addUsage(usageByModel.get(slice.servedBy) ?? ZERO_USAGE$1, slice.usage));
7816
+ options.budget?.onUsage(slice.usage, slice.servedBy);
7817
+ }
7768
7818
  }
7819
+ const usageSlices = () => [...usageByModel].map(([sliceServedBy, usage]) => ({
7820
+ servedBy: sliceServedBy,
7821
+ usage
7822
+ }));
7823
+ /**
7824
+ * Every slice priced at ITS OWN model's rate. An unpriced model
7825
+ * contributes zero here and surfaces through CostReport.unpriced, never
7826
+ * as a silent zero.
7827
+ */
7828
+ const priceRecordedUsage = () => {
7829
+ const price = options.priceUsd;
7830
+ if (price === void 0) return 0;
7831
+ let usd = 0;
7832
+ for (const [sliceServedBy, usage] of usageByModel) usd += price(sliceServedBy, usage) ?? 0;
7833
+ return usd;
7834
+ };
7769
7835
  const saveBoundary = async (pending) => {
7770
7836
  if (options.checkpoint === void 0) return;
7771
7837
  await options.checkpoint.save({
@@ -7773,6 +7839,7 @@ async function runAgent(options) {
7773
7839
  messages: [...messages],
7774
7840
  turns,
7775
7841
  usage: totalUsage,
7842
+ usageByModel: usageSlices(),
7776
7843
  toolCallsUsed,
7777
7844
  schemaAttempts,
7778
7845
  compaction: [...compactionPoints],
@@ -7886,7 +7953,7 @@ async function runAgent(options) {
7886
7953
  continue;
7887
7954
  }
7888
7955
  const request = validation.value;
7889
- const spentSoFar = options.priceUsd?.(servedBy, totalUsage) ?? 0;
7956
+ const spentSoFar = priceRecordedUsage();
7890
7957
  if (countsAgainstLimit(request.kind) && spentSoFar < options.escalation.minSpendUsd) {
7891
7958
  events?.emit({
7892
7959
  type: "tool:end",
@@ -8005,6 +8072,7 @@ async function runAgent(options) {
8005
8072
  invariantViolation = thrown instanceof Error ? thrown.message : String(thrown);
8006
8073
  }
8007
8074
  totalUsage = addUsage(totalUsage, usage);
8075
+ usageByModel.set(ref, addUsage(usageByModel.get(ref) ?? ZERO_USAGE$1, usage));
8008
8076
  const remainder = {
8009
8077
  inputTokens: Math.max(0, usage.inputTokens - reported.inputTokens),
8010
8078
  outputTokens: Math.max(0, usage.outputTokens - reported.outputTokens),
@@ -8584,7 +8652,7 @@ async function runAgent(options) {
8584
8652
  const blob = new TextEncoder().encode(JSON.stringify({ messages }));
8585
8653
  await options.transcript.put(transcriptRef, blob);
8586
8654
  }
8587
- const costUsd = options.priceUsd?.(servedBy, totalUsage) ?? 0;
8655
+ const costUsd = priceRecordedUsage();
8588
8656
  const result = {
8589
8657
  status,
8590
8658
  output: status === "ok" ? output : output ?? null,
@@ -8594,6 +8662,7 @@ async function runAgent(options) {
8594
8662
  servedBy,
8595
8663
  transcriptRef
8596
8664
  };
8665
+ if (usageByModel.size > 1) result.usageByModel = usageSlices();
8597
8666
  if (agentError !== void 0) result.error = agentError;
8598
8667
  if (escalationRequest !== void 0) result.escalationRequest = escalationRequest;
8599
8668
  if (abortClass !== void 0) result.abortClass = abortClass;
@@ -8660,6 +8729,8 @@ var RunBudget = class {
8660
8729
  usageInternal = { ...ZERO_USAGE };
8661
8730
  agentsSpawnedInternal = 0;
8662
8731
  exhaustedInternal = false;
8732
+ /** Models already warned about; the warning fires once per model per run. */
8733
+ unpricedWarned = /* @__PURE__ */ new Set();
8663
8734
  constructor(options) {
8664
8735
  if (options.ceilingUsd !== void 0) this.ceilingUsd = options.ceilingUsd;
8665
8736
  this.lifetimeSpawnCap = options.lifetimeSpawnCap ?? 500;
@@ -8864,7 +8935,16 @@ var RunBudget = class {
8864
8935
  };
8865
8936
  const reasoning = (this.usageInternal.reasoningTokens ?? 0) + (usage.reasoningTokens ?? 0);
8866
8937
  if (reasoning > 0) this.usageInternal.reasoningTokens = reasoning;
8867
- const usd = this.priceUsd?.(servedBy, usage) ?? 0;
8938
+ const priced = this.priceUsd?.(servedBy, usage);
8939
+ if (priced === void 0 && this.ceilingUsd !== void 0 && !this.unpricedWarned.has(servedBy)) {
8940
+ this.unpricedWarned.add(servedBy);
8941
+ this.events?.emit({
8942
+ type: "log",
8943
+ level: "warn",
8944
+ msg: `no price row for '${servedBy}': its usage does not debit the budget, so the ${this.ceilingUsd} USD run ceiling does NOT bound this model. Add it to createEngine({ pricing }) to cap it; its usage is reported under CostReport.unpriced`
8945
+ });
8946
+ }
8947
+ const usd = priced ?? 0;
8868
8948
  for (const account of this.chainOf(accountScope)) {
8869
8949
  account.spentUsd += usd;
8870
8950
  if (account.ceilingUsd !== void 0 && account.spentUsd >= account.ceilingUsd && !account.controller.signal.aborted) {
@@ -9569,11 +9649,22 @@ var AgentCallError = class extends Error {
9569
9649
  if (entryRef !== void 0) this.entryRef = entryRef;
9570
9650
  }
9571
9651
  };
9652
+ /** The workflow-defaults layer a Workflow value contributes, or nothing. */
9653
+ function workflowLayerOf(wf) {
9654
+ const layer = {};
9655
+ if (wf.model !== void 0) layer.model = wf.model;
9656
+ if (wf.routing !== void 0) layer.routing = wf.routing;
9657
+ if (wf.effort !== void 0) layer.effort = wf.effort;
9658
+ return Object.keys(layer).length === 0 ? void 0 : layer;
9659
+ }
9572
9660
  function defineWorkflow(meta, body) {
9573
9661
  const wf = {
9574
9662
  kind: "workflow",
9575
9663
  name: meta.name,
9576
9664
  errorPolicy: meta.errorPolicy ?? "strict",
9665
+ ...meta.model === void 0 ? {} : { model: meta.model },
9666
+ ...meta.routing === void 0 ? {} : { routing: meta.routing },
9667
+ ...meta.effort === void 0 ? {} : { effort: meta.effort },
9577
9668
  body
9578
9669
  };
9579
9670
  if (meta.args !== void 0) return {
@@ -9615,19 +9706,24 @@ function buildEscalationReport(request, result, worktreePatchRef) {
9615
9706
  * one ctx object while journaling under their own scope paths (I3:
9616
9707
  * structure from call-and-return only).
9617
9708
  */
9618
- function createCtx(internals) {
9709
+ function createCtx(internals, rootWorkflow) {
9619
9710
  const als = new AsyncLocalStorage();
9620
9711
  const sites = new ParallelSiteCounter();
9712
+ const rootWorkflowLayer = rootWorkflow === void 0 ? void 0 : workflowLayerOf(rootWorkflow);
9621
9713
  const rootState = {
9622
9714
  scope: "",
9623
- spanId: internals.rootSpanId
9715
+ spanId: internals.rootSpanId,
9716
+ ...rootWorkflowLayer === void 0 ? {} : { workflowLayer: rootWorkflowLayer }
9624
9717
  };
9625
9718
  const current = () => als.getStore() ?? rootState;
9626
9719
  const capsOf = (ref) => {
9627
9720
  const colon = ref.indexOf(":");
9628
9721
  const adapterId = ref.slice(0, colon);
9629
9722
  const adapter = internals.adapters.get(adapterId);
9630
- if (adapter === void 0) throw new ConfigError(`no adapter registered for '${adapterId}' (ModelRef '${ref}'); pass it to createEngine`);
9723
+ if (adapter === void 0) {
9724
+ const registered = [...internals.adapters.keys()].sort();
9725
+ throw new ConfigError(`no adapter registered for '${adapterId}' (ModelRef '${ref}'); registered: ${registered.length === 0 ? "(none)" : registered.join(", ")}. Pass the adapter to createEngine, or route this role to a registered adapter through defaults.routing`);
9726
+ }
9631
9727
  return adapter.caps(ref.slice(colon + 1));
9632
9728
  };
9633
9729
  const adapterOf = (resolved) => {
@@ -9720,6 +9816,7 @@ function createCtx(internals) {
9720
9816
  if (profile?.effort !== void 0) profileLayer.effort = profile.effort;
9721
9817
  const engineLayer = {};
9722
9818
  if (internals.defaults.routing !== void 0) engineLayer.routing = internals.defaults.routing;
9819
+ const workflowLayer = state.workflowLayer;
9723
9820
  const telemetryNamespace = { agentType };
9724
9821
  if (opts.label !== void 0) telemetryNamespace.label = opts.label;
9725
9822
  const withTelemetry = (resolved) => ({
@@ -9734,6 +9831,7 @@ function createCtx(internals) {
9734
9831
  role: primaryRole,
9735
9832
  call: callLayer,
9736
9833
  profile: profileLayer,
9834
+ workflow: workflowLayer,
9737
9835
  engine: engineLayer,
9738
9836
  capsOf,
9739
9837
  ...floorContext
@@ -9770,6 +9868,7 @@ function createCtx(internals) {
9770
9868
  role: "extract",
9771
9869
  call: callLayer,
9772
9870
  profile: profileLayer,
9871
+ workflow: workflowLayer,
9773
9872
  engine: engineLayer,
9774
9873
  capsOf,
9775
9874
  ...floorContext
@@ -9803,6 +9902,7 @@ function createCtx(internals) {
9803
9902
  role: "finalize",
9804
9903
  call: callLayer,
9805
9904
  profile: profileLayer,
9905
+ workflow: workflowLayer,
9806
9906
  engine: engineLayer,
9807
9907
  capsOf,
9808
9908
  ...floorContext
@@ -9823,6 +9923,7 @@ function createCtx(internals) {
9823
9923
  role: "summarize",
9824
9924
  call: callLayer,
9825
9925
  profile: profileLayer,
9926
+ workflow: workflowLayer,
9826
9927
  engine: engineLayer,
9827
9928
  capsOf,
9828
9929
  ...floorContext
@@ -9832,6 +9933,7 @@ function createCtx(internals) {
9832
9933
  role: "summarize",
9833
9934
  call: callLayer,
9834
9935
  profile: profileLayer,
9936
+ workflow: workflowLayer,
9835
9937
  engine: {
9836
9938
  ...engineLayer,
9837
9939
  model: loopResolved.ref
@@ -9851,6 +9953,7 @@ function createCtx(internals) {
9851
9953
  role,
9852
9954
  call: fallbackLayer,
9853
9955
  profile: profileLayer,
9956
+ workflow: workflowLayer,
9854
9957
  engine: engineLayer,
9855
9958
  capsOf,
9856
9959
  ...floorContext
@@ -9895,7 +9998,8 @@ function createCtx(internals) {
9895
9998
  cacheReadTokens: 0,
9896
9999
  cacheWriteTokens: 0
9897
10000
  };
9898
- const costUsd = terminal?.servedBy === void 0 ? 0 : internals.priceUsd(terminal.servedBy, usage) ?? 0;
10001
+ const replayPriced = terminal === void 0 ? void 0 : priceEntryUsage(terminal, (ref, sliceUsage) => internals.priceUsd(ref, sliceUsage));
10002
+ const costUsd = replayPriced?.usd ?? 0;
9899
10003
  const result = {
9900
10004
  status: matched.kind === "skip" ? "skipped" : terminal?.status ?? "ok",
9901
10005
  output: matched.kind === "skip" ? null : terminal?.value ?? null,
@@ -9952,7 +10056,11 @@ function createCtx(internals) {
9952
10056
  costUsd,
9953
10057
  entryRef: terminal?.seq ?? matched.running.seq
9954
10058
  }, spanId, true);
9955
- bump(internals.cost.byModel, terminal?.servedBy ?? loopResolved.ref, costUsd);
10059
+ for (const slice of replayPriced?.priced ?? []) bump(internals.cost.byModel, slice.servedBy, slice.usd);
10060
+ for (const slice of replayPriced?.unpriced ?? []) internals.cost.unpriced.push({
10061
+ model: slice.servedBy,
10062
+ usage: slice.usage
10063
+ });
9956
10064
  bump(internals.cost.byPhase, state.phase ?? "", costUsd);
9957
10065
  bump(internals.cost.byAgentType, agentType, costUsd);
9958
10066
  internals.cost.byRole.set(primaryRole, (internals.cost.byRole.get(primaryRole) ?? 0) + costUsd);
@@ -10352,6 +10460,7 @@ function createCtx(internals) {
10352
10460
  status: result.status === "skipped" ? "error" : result.status,
10353
10461
  usage: result.usage,
10354
10462
  servedBy: result.servedBy,
10463
+ ...result.usageByModel === void 0 ? {} : { usageByModel: result.usageByModel },
10355
10464
  transcriptRef: result.transcriptRef
10356
10465
  };
10357
10466
  if (result.status === "escalated" && result.escalation !== void 0) terminalPatch.escalation = result.escalation;
@@ -10402,14 +10511,23 @@ function createCtx(internals) {
10402
10511
  });
10403
10512
  }
10404
10513
  const usd = result.costUsd;
10405
- bump(internals.cost.byModel, loopResolved.ref, usd);
10514
+ for (const slice of result.usageByModel ?? [{
10515
+ servedBy: result.servedBy,
10516
+ usage: result.usage
10517
+ }]) {
10518
+ const priced = internals.priceUsd(slice.servedBy, slice.usage);
10519
+ if (priced === void 0) {
10520
+ internals.cost.unpriced.push({
10521
+ model: slice.servedBy,
10522
+ usage: slice.usage
10523
+ });
10524
+ continue;
10525
+ }
10526
+ bump(internals.cost.byModel, slice.servedBy, priced);
10527
+ }
10406
10528
  bump(internals.cost.byPhase, state.phase ?? "", usd);
10407
10529
  bump(internals.cost.byAgentType, agentType, usd);
10408
10530
  internals.cost.byRole.set(primaryRole, (internals.cost.byRole.get(primaryRole) ?? 0) + usd);
10409
- if (internals.priceUsd(loopResolved.ref, result.usage) === void 0) internals.cost.unpriced.push({
10410
- model: loopResolved.ref,
10411
- usage: result.usage
10412
- });
10413
10531
  if (result.error?.kind === "budget" || internals.budget.exhausted && result.status !== "ok") throw new BudgetExhaustedError("run budget ceiling reached during agent execution", { data: {
10414
10532
  scope: state.scope,
10415
10533
  entryRef: terminal.seq
@@ -10712,10 +10830,12 @@ function createCtx(internals) {
10712
10830
  site: `ctx.workflow('${name}')`
10713
10831
  });
10714
10832
  const signals = [state.signal ?? internals.runSignal, internals.budget.signalOf(childScope)].filter((signal) => signal !== void 0);
10833
+ const childLayer = workflowLayerOf(wf);
10715
10834
  const childState = {
10716
10835
  scope: childScope,
10717
10836
  spanId,
10718
- budgetScope: childScope
10837
+ budgetScope: childScope,
10838
+ ...childLayer === void 0 ? {} : { workflowLayer: childLayer }
10719
10839
  };
10720
10840
  if (signals.length === 1) childState.signal = signals[0];
10721
10841
  else if (signals.length > 1) childState.signal = AbortSignal.any(signals);
@@ -10886,7 +11006,7 @@ async function executeWorkflow(internals, wf, args) {
10886
11006
  const validation = await validateSchemaSpec(wf.argsSchema, args);
10887
11007
  if (!validation.valid) throw new ConfigError(`arguments for workflow '${wf.name}' do not validate: ` + validation.issues.map((issue) => issue.message).join("; "), { data: { issues: validation.issues.map((issue) => issue.message) } });
10888
11008
  }
10889
- const ctx = createCtx(internals);
11009
+ const ctx = createCtx(internals, wf);
10890
11010
  try {
10891
11011
  return await wf.body(ctx, args);
10892
11012
  } finally {
@@ -12059,7 +12179,7 @@ function createEngine(options) {
12059
12179
  const validation = await validateSchemaSpec(wf.argsSchema, args);
12060
12180
  if (!validation.valid) throw new ConfigError(`arguments for workflow '${wf.name}' do not validate: ` + validation.issues.map((issue) => issue.message).join("; "));
12061
12181
  }
12062
- const ctx = createCtx(internals);
12182
+ const ctx = createCtx(internals, wf.kind === "workflow" ? wf : void 0);
12063
12183
  const bodyPromise = (compiled === void 0 ? runner : options.runners?.sandbox).execute(wf, ctx, args);
12064
12184
  const raced = await Promise.race([bodyPromise.then((result) => ({
12065
12185
  kind: "done",
@@ -12555,4 +12675,4 @@ function createSandboxBridge(ctx, options) {
12555
12675
  };
12556
12676
  }
12557
12677
  //#endregion
12558
- 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, 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, 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 };
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 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rulvar/core",
3
- "version": "1.4.0",
3
+ "version": "1.5.1",
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",