@rulvar/core 1.20.0 → 1.21.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 CHANGED
@@ -656,7 +656,10 @@ interface PricedUsage {
656
656
  * The single pricing fold over one terminal entry, shared by the kernel
657
657
  * ledger and the CostReport fold so a run's total and its per-model
658
658
  * breakdown can never disagree. Each slice is priced at ITS OWN model's
659
- * rate.
659
+ * rate. A price function returning NaN or a negative amount (a broken
660
+ * user-supplied rate) is treated exactly like a missing row: the slice
661
+ * folds as unpriced instead of poisoning or crediting the totals
662
+ * (v1.20.0 review follow-up).
660
663
  */
661
664
  declare function priceEntryUsage(entry: JournalEntry, priceUsd: (servedBy: ModelRef, usage: Usage) => number | undefined): PricedUsage;
662
665
  /**
@@ -703,6 +706,21 @@ type JournalEntry = {
703
706
  * like usageByModel.
704
707
  */
705
708
  costAttribution?: CostAttributionFacts;
709
+ /**
710
+ * The serving adapters' declared usage-telemetry semantics at write
711
+ * time (ProviderAdapter.usageSemantics), stamped so cost numbers stay
712
+ * auditable across normalization corrections: an UNSTAMPED OpenAI
713
+ * entry with cacheWriteTokens > 0 may have been written by rulvar
714
+ * v1.19.0, whose adapter double-counted cache writes into inputTokens
715
+ * (v1.20.0 review P1/P2-2). The stamp unions every adapter that
716
+ * served a slice of the entry, distinct declarations joined with '+'
717
+ * in first-appearance order, so a mixed-adapter call whose primary
718
+ * declares nothing is still dated by its declaring slices. Absent
719
+ * only when NO serving adapter declares semantics, and on all entries
720
+ * written before this shipped. Policy, never identity, exactly like
721
+ * usageByModel.
722
+ */
723
+ usageSemantics?: string;
706
724
  transcriptRef?: string;
707
725
  checkpointRef?: string;
708
726
  /**
@@ -854,6 +872,51 @@ declare function maskSecretsDeep<T>(value: T): T;
854
872
  /** Convenience for hosts: masks a Json value (alias of the deep walk). */
855
873
  declare function maskSecretsJson(value: Json): Json;
856
874
  //#endregion
875
+ //#region src/l0/usage.d.ts
876
+ /**
877
+ * Names every rule the given usage violates; an empty array means the
878
+ * usage satisfies the full canonical invariant: each present count is a
879
+ * finite nonnegative integer and
880
+ * `cacheReadTokens + cacheWriteTokens <= inputTokens`. The subset rule
881
+ * is checked with a negated comparison so a NaN operand counts as a
882
+ * violation rather than vacuously passing.
883
+ */
884
+ declare function usageViolations(usage: Usage): string[];
885
+ /**
886
+ * One count, repaired in the conservative direction: non-numbers and
887
+ * non-finite values floor to zero (no evidence, no charge and no
888
+ * credit), negatives floor to zero (a negative count can only CREDIT
889
+ * the budget, which hostile telemetry must never do), and fractions
890
+ * round UP so a repaired charge is never an undercharge.
891
+ */
892
+ declare function sanitizeTokenCount(value: number | undefined): number;
893
+ /**
894
+ * One field read per property, returning a detached plain copy. Both
895
+ * accounting boundaries validate and consume THIS snapshot, never the
896
+ * adapter-owned object, so a hostile accessor cannot answer the
897
+ * validator with valid counts and the accumulator with garbage.
898
+ */
899
+ declare function snapshotUsage(usage: Usage): Usage;
900
+ /**
901
+ * The per-field repair for DELTAS (mid-stream usage reports and other
902
+ * partial increments): each count is repaired like `sanitizeTokenCount`,
903
+ * but the whole-usage subset rule is deliberately NOT applied, because a
904
+ * delta legitimately carries cache counts without restating the full
905
+ * input in the same event; clamping those to the subset rule would
906
+ * silently drop a paid cache debit. Always returns a fresh object and
907
+ * is the identity on valid deltas.
908
+ */
909
+ declare function sanitizeUsageDelta(delta: Usage): Usage;
910
+ /**
911
+ * Conservative repair for accounting. Pairs with `usageViolations`: the
912
+ * violation fails the call loud, and the sanitized numbers are the only
913
+ * ones the journal, the cost report, and the budget may see. After the
914
+ * per-field repair the cache subsets clamp into the input with reads
915
+ * keeping priority, mirroring the adapter-level subset clamp. Valid
916
+ * usage passes through structurally unchanged.
917
+ */
918
+ declare function sanitizeUsage(usage: Usage): Usage;
919
+ //#endregion
857
920
  //#region src/vendor/standard-schema.d.ts
858
921
  // Vendored from @standard-schema/spec@1.1.0 (MIT, Copyright (c) 2024 Colin
859
922
  // McDonnell), file dist/index.d.ts, byte-identical below this header.
@@ -1116,6 +1179,20 @@ interface ProviderAdapter {
1116
1179
  * family share retained blocks and projections; default = id.
1117
1180
  */
1118
1181
  provider?: string;
1182
+ /**
1183
+ * Declares WHICH reading of the provider's usage telemetry this
1184
+ * adapter normalizes under; the engine stamps it on usage-bearing
1185
+ * terminal entries so a journal records not only the numbers but the
1186
+ * semantics they were produced under (v1.20.0 review P1/P2-2). Bump
1187
+ * the string whenever the MEANING of a reported Usage field changes,
1188
+ * even when no pricing rate moves; a rate change is a PriceTable
1189
+ * pricingVersion bump instead. Entries persisted before this shipped
1190
+ * carry no stamp, which is itself information: an unstamped OpenAI
1191
+ * entry with cache writes may predate the v1.20.0 cache-subset
1192
+ * correction. Optional; adapters that never changed semantics can
1193
+ * omit it.
1194
+ */
1195
+ usageSemantics?: string;
1119
1196
  caps(model: string): ModelCaps;
1120
1197
  /** Refresh the capability table from live model lists. */
1121
1198
  refreshCaps?(): Promise<void>;
@@ -2130,6 +2207,8 @@ interface TerminalPatch {
2130
2207
  usageByModel?: UsageSlice[];
2131
2208
  /** Attribution facts behind the CostReport breakdowns; see JournalEntry. */
2132
2209
  costAttribution?: CostAttributionFacts;
2210
+ /** The serving adapter's usage-semantics version; see JournalEntry. */
2211
+ usageSemantics?: string;
2133
2212
  transcriptRef?: string;
2134
2213
  checkpointRef?: string;
2135
2214
  /** Terminal agent entries: Artifact list. */
@@ -3472,6 +3551,8 @@ declare class RunBudget {
3472
3551
  private exhaustedInternal;
3473
3552
  /** Models already warned about; the warning fires once per model per run. */
3474
3553
  private readonly unpricedWarned;
3554
+ /** Models whose price function already returned an invalid USD once. */
3555
+ private readonly invalidPriceWarned;
3475
3556
  constructor(options: {
3476
3557
  ceilingUsd?: number;
3477
3558
  lifetimeSpawnCap?: number;
@@ -6438,4 +6519,4 @@ interface SandboxBridge {
6438
6519
  }
6439
6520
  declare function createSandboxBridge(ctx: Ctx<never>, options: SandboxBridgeOptions): SandboxBridge;
6440
6521
  //#endregion
6441
- 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, FINALIZE_SYNTHESIS_INSTRUCTION, 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, agentResultWire, 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 };
6522
+ 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, FINALIZE_SYNTHESIS_INSTRUCTION, 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, agentResultWire, 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, sanitizeTokenCount, sanitizeUsage, sanitizeUsageDelta, scanJournalCompatibility, schemaHash, schemaHashOfSpec, selectStructuredOutputTier, shouldCompact, snapshotUsage, spawnDepthOf, summarizeInstruction, summarizeOutput, terminationConfigDrift, tierWithinCaps, toApprovalDecision, toJournalValue, tool, toolContract, toolsetHash, ttlState, usageViolations, validateEditorialCommit, validateEntryShape, validateEscalationLimits, validateEscalationReport, validateSchemaSpec, validateTerminationLimits, workflowScope, workflowSourceRef, wrapJournalStore, wrapTranscriptStore };
package/dist/index.js CHANGED
@@ -547,6 +547,105 @@ function createCanonicalIdMinter(options) {
547
547
  return monotonicUlidFactory(options);
548
548
  }
549
549
  //#endregion
550
+ //#region src/l0/usage.ts
551
+ const COUNT_FIELDS = [
552
+ "inputTokens",
553
+ "outputTokens",
554
+ "cacheReadTokens",
555
+ "cacheWriteTokens",
556
+ "reasoningTokens"
557
+ ];
558
+ /**
559
+ * Names every rule the given usage violates; an empty array means the
560
+ * usage satisfies the full canonical invariant: each present count is a
561
+ * finite nonnegative integer and
562
+ * `cacheReadTokens + cacheWriteTokens <= inputTokens`. The subset rule
563
+ * is checked with a negated comparison so a NaN operand counts as a
564
+ * violation rather than vacuously passing.
565
+ */
566
+ function usageViolations(usage) {
567
+ const out = [];
568
+ for (const field of COUNT_FIELDS) {
569
+ const value = usage[field];
570
+ if (field === "reasoningTokens" && value === void 0) continue;
571
+ if (typeof value !== "number" || !Number.isFinite(value)) out.push(`${field} is ${String(value)}, not a finite number`);
572
+ else if (value < 0) out.push(`${field} is negative (${String(value)})`);
573
+ else if (!Number.isInteger(value)) out.push(`${field} is fractional (${String(value)})`);
574
+ else if (!Number.isSafeInteger(value)) out.push(`${field} is beyond the safe integer range (${String(value)})`);
575
+ }
576
+ if (!(usage.inputTokens >= usage.cacheReadTokens + usage.cacheWriteTokens)) out.push(`inputTokens (${String(usage.inputTokens)}) < cacheReadTokens + cacheWriteTokens (${String(usage.cacheReadTokens)} + ${String(usage.cacheWriteTokens)})`);
577
+ return out;
578
+ }
579
+ /**
580
+ * One count, repaired in the conservative direction: non-numbers and
581
+ * non-finite values floor to zero (no evidence, no charge and no
582
+ * credit), negatives floor to zero (a negative count can only CREDIT
583
+ * the budget, which hostile telemetry must never do), and fractions
584
+ * round UP so a repaired charge is never an undercharge.
585
+ */
586
+ function sanitizeTokenCount(value) {
587
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return 0;
588
+ return Math.min(Math.ceil(value), Number.MAX_SAFE_INTEGER);
589
+ }
590
+ /**
591
+ * One field read per property, returning a detached plain copy. Both
592
+ * accounting boundaries validate and consume THIS snapshot, never the
593
+ * adapter-owned object, so a hostile accessor cannot answer the
594
+ * validator with valid counts and the accumulator with garbage.
595
+ */
596
+ function snapshotUsage(usage) {
597
+ const out = {
598
+ inputTokens: usage.inputTokens,
599
+ outputTokens: usage.outputTokens,
600
+ cacheReadTokens: usage.cacheReadTokens,
601
+ cacheWriteTokens: usage.cacheWriteTokens
602
+ };
603
+ const reasoning = usage.reasoningTokens;
604
+ if (reasoning !== void 0) out.reasoningTokens = reasoning;
605
+ return out;
606
+ }
607
+ /**
608
+ * The per-field repair for DELTAS (mid-stream usage reports and other
609
+ * partial increments): each count is repaired like `sanitizeTokenCount`,
610
+ * but the whole-usage subset rule is deliberately NOT applied, because a
611
+ * delta legitimately carries cache counts without restating the full
612
+ * input in the same event; clamping those to the subset rule would
613
+ * silently drop a paid cache debit. Always returns a fresh object and
614
+ * is the identity on valid deltas.
615
+ */
616
+ function sanitizeUsageDelta(delta) {
617
+ const snapshot = snapshotUsage(delta);
618
+ const out = {
619
+ inputTokens: sanitizeTokenCount(snapshot.inputTokens),
620
+ outputTokens: sanitizeTokenCount(snapshot.outputTokens),
621
+ cacheReadTokens: sanitizeTokenCount(snapshot.cacheReadTokens),
622
+ cacheWriteTokens: sanitizeTokenCount(snapshot.cacheWriteTokens)
623
+ };
624
+ if (snapshot.reasoningTokens !== void 0) out.reasoningTokens = sanitizeTokenCount(snapshot.reasoningTokens);
625
+ return out;
626
+ }
627
+ /**
628
+ * Conservative repair for accounting. Pairs with `usageViolations`: the
629
+ * violation fails the call loud, and the sanitized numbers are the only
630
+ * ones the journal, the cost report, and the budget may see. After the
631
+ * per-field repair the cache subsets clamp into the input with reads
632
+ * keeping priority, mirroring the adapter-level subset clamp. Valid
633
+ * usage passes through structurally unchanged.
634
+ */
635
+ function sanitizeUsage(usage) {
636
+ const inputTokens = sanitizeTokenCount(usage.inputTokens);
637
+ const cacheReadTokens = Math.min(sanitizeTokenCount(usage.cacheReadTokens), inputTokens);
638
+ const cacheWriteTokens = Math.min(sanitizeTokenCount(usage.cacheWriteTokens), inputTokens - cacheReadTokens);
639
+ const out = {
640
+ inputTokens,
641
+ outputTokens: sanitizeTokenCount(usage.outputTokens),
642
+ cacheReadTokens,
643
+ cacheWriteTokens
644
+ };
645
+ if (usage.reasoningTokens !== void 0) out.reasoningTokens = sanitizeTokenCount(usage.reasoningTokens);
646
+ return out;
647
+ }
648
+ //#endregion
550
649
  //#region src/vendor/json-schema/deep-compare-strict.ts
551
650
  function deepCompareStrict(a, b) {
552
651
  const typeofa = typeof a;
@@ -1772,7 +1871,10 @@ function entryUsageSlices(entry) {
1772
1871
  * The single pricing fold over one terminal entry, shared by the kernel
1773
1872
  * ledger and the CostReport fold so a run's total and its per-model
1774
1873
  * breakdown can never disagree. Each slice is priced at ITS OWN model's
1775
- * rate.
1874
+ * rate. A price function returning NaN or a negative amount (a broken
1875
+ * user-supplied rate) is treated exactly like a missing row: the slice
1876
+ * folds as unpriced instead of poisoning or crediting the totals
1877
+ * (v1.20.0 review follow-up).
1776
1878
  */
1777
1879
  function priceEntryUsage(entry, priceUsd) {
1778
1880
  const result = {
@@ -1782,7 +1884,7 @@ function priceEntryUsage(entry, priceUsd) {
1782
1884
  };
1783
1885
  for (const slice of entryUsageSlices(entry)) {
1784
1886
  const usd = priceUsd(slice.servedBy, slice.usage);
1785
- if (usd === void 0) {
1887
+ if (usd === void 0 || !Number.isFinite(usd) || usd < 0) {
1786
1888
  result.unpriced.push(slice);
1787
1889
  continue;
1788
1890
  }
@@ -5535,6 +5637,7 @@ var Replayer = class {
5535
5637
  if (patch.servedBy !== void 0) entry.servedBy = patch.servedBy;
5536
5638
  if (patch.usageByModel !== void 0) entry.usageByModel = patch.usageByModel;
5537
5639
  if (patch.costAttribution !== void 0) entry.costAttribution = patch.costAttribution;
5640
+ if (patch.usageSemantics !== void 0) entry.usageSemantics = patch.usageSemantics;
5538
5641
  if (patch.transcriptRef !== void 0) entry.transcriptRef = patch.transcriptRef;
5539
5642
  if (patch.checkpointRef !== void 0) entry.checkpointRef = patch.checkpointRef;
5540
5643
  if (patch.artifacts !== void 0) entry.artifacts = toJournalValue(patch.artifacts, "terminal artifacts");
@@ -7759,8 +7862,17 @@ function addUsage(total, turn) {
7759
7862
  * The Usage invariant is verified at the adapter boundary: inputTokens is
7760
7863
  * the FULL prompt including cache reads and writes.
7761
7864
  */
7762
- function assertUsageInvariant(usage, adapterId) {
7763
- if (usage.inputTokens < usage.cacheReadTokens + usage.cacheWriteTokens) throw new Error(`adapter '${adapterId}' violated the Usage invariant: inputTokens (${usage.inputTokens}) < cacheReadTokens + cacheWriteTokens (${usage.cacheReadTokens} + ${usage.cacheWriteTokens})`);
7865
+ /**
7866
+ * The full canonical invariant at the adapter boundary (v1.20.0 review
7867
+ * P1-1): every count finite, integral, and nonnegative, and the cache
7868
+ * subsets inside the input. One violation message covers every adapter,
7869
+ * injected clients and mocks included; the financial invariant never
7870
+ * depends on the good faith of an external transport.
7871
+ */
7872
+ function usageInvariantViolation(usage, adapterId) {
7873
+ const violations = usageViolations(usage);
7874
+ if (violations.length === 0) return;
7875
+ return `adapter '${adapterId}' violated the Usage invariant: ${violations.join("; ")}`;
7764
7876
  }
7765
7877
  async function streamTurn(adapter, req, options) {
7766
7878
  const idle = new AbortController();
@@ -7774,6 +7886,7 @@ async function streamTurn(adapter, req, options) {
7774
7886
  const pendingArgs = /* @__PURE__ */ new Map();
7775
7887
  let usage = ZERO_USAGE$1;
7776
7888
  let reported = ZERO_USAGE$1;
7889
+ let usageViolation;
7777
7890
  let sawFinish = false;
7778
7891
  let finish;
7779
7892
  let providerMetadata;
@@ -7817,22 +7930,46 @@ async function streamTurn(adapter, req, options) {
7817
7930
  break;
7818
7931
  }
7819
7932
  case "usage": {
7933
+ if (sawFinish) {
7934
+ usageViolation ??= "a usage event arrived after the finish event";
7935
+ break;
7936
+ }
7937
+ const cleaned = {};
7938
+ for (const field of [
7939
+ "inputTokens",
7940
+ "outputTokens",
7941
+ "cacheReadTokens",
7942
+ "cacheWriteTokens",
7943
+ "reasoningTokens"
7944
+ ]) {
7945
+ const value = event.usage[field];
7946
+ if (value === void 0) continue;
7947
+ if (Number.isInteger(value) && value >= 0) cleaned[field] = value;
7948
+ else {
7949
+ usageViolation ??= `mid-stream usage event carried invalid ${field} (${String(value)})`;
7950
+ cleaned[field] = sanitizeTokenCount(value);
7951
+ }
7952
+ }
7820
7953
  usage = {
7821
7954
  ...usage,
7822
- ...event.usage
7955
+ ...cleaned
7823
7956
  };
7824
7957
  const delta = {
7825
- inputTokens: event.usage.inputTokens ?? 0,
7826
- outputTokens: event.usage.outputTokens ?? 0,
7827
- cacheReadTokens: event.usage.cacheReadTokens ?? 0,
7828
- cacheWriteTokens: event.usage.cacheWriteTokens ?? 0
7958
+ inputTokens: cleaned.inputTokens ?? 0,
7959
+ outputTokens: cleaned.outputTokens ?? 0,
7960
+ cacheReadTokens: cleaned.cacheReadTokens ?? 0,
7961
+ cacheWriteTokens: cleaned.cacheWriteTokens ?? 0
7829
7962
  };
7830
- if (event.usage.reasoningTokens !== void 0) delta.reasoningTokens = event.usage.reasoningTokens;
7963
+ if (cleaned.reasoningTokens !== void 0) delta.reasoningTokens = cleaned.reasoningTokens;
7831
7964
  reported = addUsage(reported, delta);
7832
7965
  options.onUsage?.(delta);
7833
7966
  break;
7834
7967
  }
7835
7968
  case "finish":
7969
+ if (sawFinish) {
7970
+ usageViolation ??= "a second finish event arrived on one stream";
7971
+ break;
7972
+ }
7836
7973
  sawFinish = true;
7837
7974
  finish = event.finish;
7838
7975
  usage = event.usage;
@@ -7864,6 +8001,7 @@ async function streamTurn(adapter, req, options) {
7864
8001
  aborted
7865
8002
  };
7866
8003
  if (finish !== void 0) outcome.finish = finish;
8004
+ if (usageViolation !== void 0) outcome.usageViolation = usageViolation;
7867
8005
  return outcome;
7868
8006
  }
7869
8007
  const outcome = {
@@ -7873,6 +8011,7 @@ async function streamTurn(adapter, req, options) {
7873
8011
  usageApprox: !sawFinish
7874
8012
  };
7875
8013
  if (finish !== void 0) outcome.finish = finish;
8014
+ if (usageViolation !== void 0) outcome.usageViolation = usageViolation;
7876
8015
  if (providerMetadata !== void 0) outcome.providerMetadata = providerMetadata;
7877
8016
  if (wireError !== void 0) outcome.wireError = wireError;
7878
8017
  return outcome;
@@ -8095,17 +8234,18 @@ async function runAgent(options) {
8095
8234
  messages.length = 0;
8096
8235
  messages.push(...restored.messages);
8097
8236
  turns = restored.turns;
8098
- totalUsage = restored.usage;
8237
+ totalUsage = usageViolations(restored.usage).length === 0 ? restored.usage : sanitizeUsage(restored.usage);
8099
8238
  toolCallsUsed = restored.toolCallsUsed;
8100
8239
  schemaAttempts = restored.schemaAttempts;
8101
8240
  compactionPoints.push(...restored.compaction);
8102
8241
  const restoredSlices = restored.usageByModel ?? [{
8103
8242
  servedBy,
8104
- usage: restored.usage
8243
+ usage: totalUsage
8105
8244
  }];
8106
8245
  for (const slice of restoredSlices) {
8107
- addPhaseUsage(slice.role ?? primaryRole, slice.servedBy, slice.usage);
8108
- options.budget?.onUsage(slice.usage, slice.servedBy);
8246
+ const sliceUsage = usageViolations(slice.usage).length === 0 ? slice.usage : sanitizeUsage(slice.usage);
8247
+ addPhaseUsage(slice.role ?? primaryRole, slice.servedBy, sliceUsage);
8248
+ options.budget?.onUsage(sliceUsage, slice.servedBy);
8109
8249
  }
8110
8250
  }
8111
8251
  const usageSlices = () => [...usageByPhaseModel.values()].map(({ role, servedBy: sliceServedBy, usage }) => ({
@@ -8122,7 +8262,10 @@ async function runAgent(options) {
8122
8262
  const price = options.priceUsd;
8123
8263
  if (price === void 0) return 0;
8124
8264
  let usd = 0;
8125
- for (const slice of usageByPhaseModel.values()) usd += price(slice.servedBy, slice.usage) ?? 0;
8265
+ for (const slice of usageByPhaseModel.values()) {
8266
+ const sliceUsd = price(slice.servedBy, slice.usage) ?? 0;
8267
+ if (Number.isFinite(sliceUsd) && sliceUsd > 0) usd += sliceUsd;
8268
+ }
8126
8269
  return usd;
8127
8270
  };
8128
8271
  const saveBoundary = async (pending) => {
@@ -8358,21 +8501,29 @@ async function runAgent(options) {
8358
8501
  role: primaryRole
8359
8502
  });
8360
8503
  let invariantViolation;
8361
- const recordUsage = (usage, reported, adapterId, ref, role) => {
8362
- try {
8363
- assertUsageInvariant(usage, adapterId);
8364
- } catch (thrown) {
8365
- invariantViolation = thrown instanceof Error ? thrown.message : String(thrown);
8366
- }
8367
- totalUsage = addUsage(totalUsage, usage);
8368
- addPhaseUsage(role, ref, usage);
8504
+ const recordUsage = (usage, reported, adapterId, ref, role, streamViolation) => {
8505
+ if (streamViolation !== void 0) invariantViolation ??= `adapter '${adapterId}' violated the Usage invariant: ${streamViolation}`;
8506
+ const snapshot = snapshotUsage(usage);
8507
+ const violation = usageInvariantViolation(snapshot, adapterId);
8508
+ if (violation !== void 0) invariantViolation ??= violation;
8509
+ const safe = violation === void 0 ? snapshot : sanitizeUsage(snapshot);
8510
+ totalUsage = addUsage(totalUsage, safe);
8511
+ addPhaseUsage(role, ref, safe);
8369
8512
  const remainder = {
8370
- inputTokens: Math.max(0, usage.inputTokens - reported.inputTokens),
8371
- outputTokens: Math.max(0, usage.outputTokens - reported.outputTokens),
8372
- cacheReadTokens: Math.max(0, usage.cacheReadTokens - reported.cacheReadTokens),
8373
- cacheWriteTokens: Math.max(0, usage.cacheWriteTokens - reported.cacheWriteTokens)
8513
+ inputTokens: Math.max(0, safe.inputTokens - reported.inputTokens),
8514
+ outputTokens: Math.max(0, safe.outputTokens - reported.outputTokens),
8515
+ cacheReadTokens: Math.max(0, safe.cacheReadTokens - reported.cacheReadTokens),
8516
+ cacheWriteTokens: Math.max(0, safe.cacheWriteTokens - reported.cacheWriteTokens)
8374
8517
  };
8375
- const reasoningRemainder = Math.max(0, (usage.reasoningTokens ?? 0) - (reported.reasoningTokens ?? 0));
8518
+ for (const field of [
8519
+ "inputTokens",
8520
+ "outputTokens",
8521
+ "cacheReadTokens",
8522
+ "cacheWriteTokens"
8523
+ ]) if (reported[field] > safe[field]) invariantViolation ??= `adapter '${adapterId}' violated the Usage invariant: mid-stream ${field} (${String(reported[field])}) exceeded the finish total (${String(safe[field])})`;
8524
+ const overReportedReads = Math.max(0, reported.cacheReadTokens - safe.cacheReadTokens);
8525
+ if (overReportedReads > 0) remainder.inputTokens = Math.min(Number.MAX_SAFE_INTEGER, remainder.inputTokens + overReportedReads);
8526
+ const reasoningRemainder = Math.max(0, (safe.reasoningTokens ?? 0) - (reported.reasoningTokens ?? 0));
8376
8527
  if (reasoningRemainder > 0) remainder.reasoningTokens = reasoningRemainder;
8377
8528
  if (remainder.inputTokens > 0 || remainder.outputTokens > 0 || remainder.cacheReadTokens > 0 || remainder.cacheWriteTokens > 0) options.budget?.onUsage(remainder, ref);
8378
8529
  };
@@ -8387,7 +8538,7 @@ async function runAgent(options) {
8387
8538
  inner: for (;;) {
8388
8539
  const dispatch = () => streamTurn(target.adapter, site.requestFor(target), site.streamOptionsFor(target));
8389
8540
  const outcome = await (options.providerSlot === void 0 ? dispatch() : options.providerSlot(target.adapter.id, dispatch));
8390
- recordUsage(outcome.usage, outcome.reported, target.adapter.id, target.resolved.ref, site.role);
8541
+ recordUsage(outcome.usage, outcome.reported, target.adapter.id, target.resolved.ref, site.role, outcome.usageViolation);
8391
8542
  tries += 1;
8392
8543
  const retryClass = outcome.aborted === "idle" ? "transport" : outcome.wireError === void 0 ? void 0 : retryClassOf(outcome.wireError);
8393
8544
  if (retryClass === void 0) return {
@@ -9109,6 +9260,15 @@ const ZERO_USAGE = {
9109
9260
  cacheWriteTokens: 0
9110
9261
  };
9111
9262
  /**
9263
+ * A ceiling that is NaN or negative silently disarms every layer (each
9264
+ * comparison against it is false), which is indistinguishable from
9265
+ * uncapped. That must be a loud configuration error, never a silent
9266
+ * fail-open (v1.20.0 review P1-1).
9267
+ */
9268
+ function requireValidCeiling(ceilingUsd, what) {
9269
+ if (!Number.isFinite(ceilingUsd) || ceilingUsd < 0) throw new ConfigError(`${what} must be a finite nonnegative USD amount, got ${String(ceilingUsd)}`);
9270
+ }
9271
+ /**
9112
9272
  * The admission reserve for a spawn: opts.estCost, else profile.estCost,
9113
9273
  * else price(countTokens(input) + one turn's worth of output), else the
9114
9274
  * engine flat default. The output term is caps.maxOutputTokens clamped to
@@ -9151,8 +9311,13 @@ var RunBudget = class {
9151
9311
  exhaustedInternal = false;
9152
9312
  /** Models already warned about; the warning fires once per model per run. */
9153
9313
  unpricedWarned = /* @__PURE__ */ new Set();
9314
+ /** Models whose price function already returned an invalid USD once. */
9315
+ invalidPriceWarned = /* @__PURE__ */ new Set();
9154
9316
  constructor(options) {
9155
- if (options.ceilingUsd !== void 0) this.ceilingUsd = options.ceilingUsd;
9317
+ if (options.ceilingUsd !== void 0) {
9318
+ requireValidCeiling(options.ceilingUsd, "budget ceiling");
9319
+ this.ceilingUsd = options.ceilingUsd;
9320
+ }
9156
9321
  this.lifetimeSpawnCap = options.lifetimeSpawnCap ?? 500;
9157
9322
  if (options.events !== void 0) this.events = options.events;
9158
9323
  if (options.priceUsd !== void 0) this.priceUsd = options.priceUsd;
@@ -9167,8 +9332,9 @@ var RunBudget = class {
9167
9332
  if (options.ceilingUsd !== void 0) root.ceilingUsd = options.ceilingUsd;
9168
9333
  this.accounts.set("run", root);
9169
9334
  if (options.seed !== void 0) {
9335
+ if (!Number.isFinite(options.seed.usd) || options.seed.usd < 0) throw new ConfigError(`budget resume seed is not a finite nonnegative USD amount: ${String(options.seed.usd)}`);
9170
9336
  root.spentUsd = options.seed.usd;
9171
- this.usageInternal = { ...options.seed.usage };
9337
+ this.usageInternal = sanitizeUsage(options.seed.usage);
9172
9338
  this.agentsSpawnedInternal = options.seed.agentsSpawned;
9173
9339
  }
9174
9340
  }
@@ -9208,7 +9374,10 @@ var RunBudget = class {
9208
9374
  parentScope,
9209
9375
  controller: new AbortController()
9210
9376
  };
9211
- if (options.ceilingUsd !== void 0) account.ceilingUsd = options.ceilingUsd;
9377
+ if (options.ceilingUsd !== void 0) {
9378
+ requireValidCeiling(options.ceilingUsd, `ceiling of budget account '${scope}'`);
9379
+ account.ceilingUsd = options.ceilingUsd;
9380
+ }
9212
9381
  if (options.kind !== void 0) account.kind = options.kind;
9213
9382
  this.accounts.set(scope, account);
9214
9383
  }
@@ -9436,15 +9605,16 @@ var RunBudget = class {
9436
9605
  * in-flight agent; providers bill severed streams).
9437
9606
  */
9438
9607
  onUsage(usage, servedBy, accountScope = "run") {
9608
+ const safe = sanitizeUsageDelta(usage);
9439
9609
  this.usageInternal = {
9440
- inputTokens: this.usageInternal.inputTokens + usage.inputTokens,
9441
- outputTokens: this.usageInternal.outputTokens + usage.outputTokens,
9442
- cacheReadTokens: this.usageInternal.cacheReadTokens + usage.cacheReadTokens,
9443
- cacheWriteTokens: this.usageInternal.cacheWriteTokens + usage.cacheWriteTokens
9610
+ inputTokens: this.usageInternal.inputTokens + safe.inputTokens,
9611
+ outputTokens: this.usageInternal.outputTokens + safe.outputTokens,
9612
+ cacheReadTokens: this.usageInternal.cacheReadTokens + safe.cacheReadTokens,
9613
+ cacheWriteTokens: this.usageInternal.cacheWriteTokens + safe.cacheWriteTokens
9444
9614
  };
9445
- const reasoning = (this.usageInternal.reasoningTokens ?? 0) + (usage.reasoningTokens ?? 0);
9615
+ const reasoning = (this.usageInternal.reasoningTokens ?? 0) + (safe.reasoningTokens ?? 0);
9446
9616
  if (reasoning > 0) this.usageInternal.reasoningTokens = reasoning;
9447
- const priced = this.priceUsd?.(servedBy, usage);
9617
+ const priced = this.priceUsd?.(servedBy, safe);
9448
9618
  if (priced === void 0 && this.ceilingUsd !== void 0 && !this.unpricedWarned.has(servedBy)) {
9449
9619
  this.unpricedWarned.add(servedBy);
9450
9620
  this.events?.emit({
@@ -9453,7 +9623,18 @@ var RunBudget = class {
9453
9623
  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`
9454
9624
  });
9455
9625
  }
9456
- const usd = priced ?? 0;
9626
+ let usd = priced ?? 0;
9627
+ if (!Number.isFinite(usd) || usd < 0) {
9628
+ if (!this.invalidPriceWarned.has(servedBy)) {
9629
+ this.invalidPriceWarned.add(servedBy);
9630
+ this.events?.emit({
9631
+ type: "log",
9632
+ level: "error",
9633
+ msg: `price function returned ${String(usd)} USD for '${servedBy}'; charging 0 for this slice so the budget stays finite and monotone. Fix the pricing row: this usage is NOT debited and any ceiling under-counts it`
9634
+ });
9635
+ }
9636
+ usd = 0;
9637
+ }
9457
9638
  for (const account of this.chainOf(accountScope)) {
9458
9639
  account.spentUsd += usd;
9459
9640
  if (account.ceilingUsd !== void 0 && account.spentUsd >= account.ceilingUsd && !account.controller.signal.aborted) {
@@ -11016,10 +11197,18 @@ function createCtx(internals, rootWorkflow) {
11016
11197
  result.escalation = report;
11017
11198
  delete result.escalationRequest;
11018
11199
  }
11200
+ const adapterOfRef = (ref) => ref.slice(0, ref.indexOf(":"));
11201
+ const declaredSemantics = [];
11202
+ for (const ref of [result.servedBy, ...(result.usageByModel ?? []).map((slice) => slice.servedBy)]) {
11203
+ const declared = internals.adapters.get(adapterOfRef(ref))?.usageSemantics;
11204
+ if (declared !== void 0 && !declaredSemantics.includes(declared)) declaredSemantics.push(declared);
11205
+ }
11206
+ const servedSemantics = declaredSemantics.length === 0 ? void 0 : declaredSemantics.join("+");
11019
11207
  const terminalPatch = {
11020
11208
  status: result.status === "skipped" ? "error" : result.status,
11021
11209
  usage: result.usage,
11022
11210
  servedBy: result.servedBy,
11211
+ ...servedSemantics === void 0 ? {} : { usageSemantics: servedSemantics },
11023
11212
  ...result.usageByModel === void 0 ? {} : { usageByModel: result.usageByModel },
11024
11213
  costAttribution: {
11025
11214
  ...state.phase === void 0 ? {} : { phase: state.phase },
@@ -11084,7 +11273,7 @@ function createCtx(internals, rootWorkflow) {
11084
11273
  }];
11085
11274
  for (const slice of attributionSlices) {
11086
11275
  const priced = internals.priceUsd(slice.servedBy, slice.usage);
11087
- if (priced === void 0) {
11276
+ if (priced === void 0 || !Number.isFinite(priced) || priced < 0) {
11088
11277
  internals.cost.unpriced.push({
11089
11278
  model: slice.servedBy,
11090
11279
  usage: slice.usage
@@ -13057,6 +13246,10 @@ function createEngine(options) {
13057
13246
  }
13058
13247
  const priorEntries = (await journal.load(runId)).map((entry) => normalizeEntry(entry));
13059
13248
  scanJournalCompatibility(runId, priorEntries, buildDeriverRegistry(options.extraDerivers));
13249
+ if (priorEntries.some((entry) => entry.usageSemantics === void 0 && (entry.servedBy?.startsWith("openai:") === true && (entry.usage?.cacheWriteTokens ?? 0) > 0 || (entry.usageByModel?.some((slice) => slice.servedBy.startsWith("openai:") && slice.usage.cacheWriteTokens > 0) ?? false)))) process.emitWarning(`resume: run '${runId}' contains OpenAI cache-write usage recorded without a usage-semantics stamp. Entries written by rulvar v1.19.0 double-counted cache writes into inputTokens, so their recorded cost and budget debits are OVERSTATED; unstamped entries from v1.20.0 are correct. Resuming keeps the recorded debits. Audit procedure: https://docs.rulvar.com/guide/providers#openai-legacy-cache-journals`, {
13250
+ code: "RULVAR_LEGACY_CACHE_SEMANTICS",
13251
+ type: "RulvarWarning"
13252
+ });
13060
13253
  return run(bound, resumeOptions?.args, void 0, {
13061
13254
  runId,
13062
13255
  priorEntries,
@@ -13417,4 +13610,4 @@ function createSandboxBridge(ctx, options) {
13417
13610
  };
13418
13611
  }
13419
13612
  //#endregion
13420
- 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, FINALIZE_SYNTHESIS_INSTRUCTION, FINISH_SCHEMA, FINISH_TOOL_NAME, FileModelKnowledgeStore, FileTranscriptStore, GitWorktreeProvider, INBOX_PROPOSAL_TTL_DAYS, InMemoryStore, InMemoryTranscriptStore, InProcessRunner, InvalidResolutionError, JournalCompatibilityError, JournalMatcher, JournalMissError, JournalOrderViolation, JsonlFileStore, KB_ACTIVE_CLAIMS_CAP, KB_CARD_RENDER_BUDGET_CHARS, KeyedLimiter, KnowledgeCasError, LARGE_VALUE_WARN_BYTES, LEGACY_LTID_PREFIX, LEGACY_SIGNATURE_INPUTS, LINEAGE_SIG_VERSION, LeaseHeldError, LineageIndex, MASKED_SECRET, MAX_DEPTH_CEILING, ModelRetry, NoProgressDetector, NonSerializableValueError, ORCHESTRATE_WORKFLOW_NAME, OrchestratorCapConfigError, PARALLEL_AGENTS_SCHEMA, ParallelSiteCounter, PlanInvariantError, ROLE_EFFORT_DEFAULTS, ROOT_ACCOUNT, ROOT_SCOPE, RUN_PROFILES, ReplayPlanHashMismatch, Replayer, ResolutionArbiter, ResolutionFold, RulvarError, RunBudget, SPAWN_AGENT_SCHEMA, SandboxError, ScriptRejected, Semaphore, SpanRegistry, TOOL_NAME_PATTERN, TerminationAccount, WAIT_FOR_EVENTS_SCHEMA, WAIT_FOR_EVENTS_TOOL_NAME, WAKE_SUMMARY_RENDER_BUDGET_CHARS, admissionReserveUsd, affordableOutputTokens, agentErrorFromWire, agentErrorToWire, agentResultWire, 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 };
13613
+ 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, FINALIZE_SYNTHESIS_INSTRUCTION, FINISH_SCHEMA, FINISH_TOOL_NAME, FileModelKnowledgeStore, FileTranscriptStore, GitWorktreeProvider, INBOX_PROPOSAL_TTL_DAYS, InMemoryStore, InMemoryTranscriptStore, InProcessRunner, InvalidResolutionError, JournalCompatibilityError, JournalMatcher, JournalMissError, JournalOrderViolation, JsonlFileStore, KB_ACTIVE_CLAIMS_CAP, KB_CARD_RENDER_BUDGET_CHARS, KeyedLimiter, KnowledgeCasError, LARGE_VALUE_WARN_BYTES, LEGACY_LTID_PREFIX, LEGACY_SIGNATURE_INPUTS, LINEAGE_SIG_VERSION, LeaseHeldError, LineageIndex, MASKED_SECRET, MAX_DEPTH_CEILING, ModelRetry, NoProgressDetector, NonSerializableValueError, ORCHESTRATE_WORKFLOW_NAME, OrchestratorCapConfigError, PARALLEL_AGENTS_SCHEMA, ParallelSiteCounter, PlanInvariantError, ROLE_EFFORT_DEFAULTS, ROOT_ACCOUNT, ROOT_SCOPE, RUN_PROFILES, ReplayPlanHashMismatch, Replayer, ResolutionArbiter, ResolutionFold, RulvarError, RunBudget, SPAWN_AGENT_SCHEMA, SandboxError, ScriptRejected, Semaphore, SpanRegistry, TOOL_NAME_PATTERN, TerminationAccount, WAIT_FOR_EVENTS_SCHEMA, WAIT_FOR_EVENTS_TOOL_NAME, WAKE_SUMMARY_RENDER_BUDGET_CHARS, admissionReserveUsd, affordableOutputTokens, agentErrorFromWire, agentErrorToWire, agentResultWire, 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, sanitizeTokenCount, sanitizeUsage, sanitizeUsageDelta, scanJournalCompatibility, schemaHash, schemaHashOfSpec, selectStructuredOutputTier, shouldCompact, snapshotUsage, spawnDepthOf, summarizeInstruction, summarizeOutput, terminationConfigDrift, tierWithinCaps, toApprovalDecision, toJournalValue, tool, toolContract, toolsetHash, ttlState, usageViolations, 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.20.0",
3
+ "version": "1.21.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",