@rulvar/core 1.59.4 → 1.61.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
@@ -663,6 +663,49 @@ interface UsageSlice {
663
663
  role?: InvocationRole;
664
664
  }
665
665
  /**
666
+ * One live provider dispatch of an agent invocation (P1.3, the durable
667
+ * reconciliation ledger): every wire call the engine actually made,
668
+ * successful or not, with the usage it consumed and the provider's
669
+ * response id when the adapter surfaced one. Quota-denied attempts and
670
+ * abort short circuits that never reached the adapter mint no record:
671
+ * the ledger enumerates exactly the calls a provider could bill.
672
+ * Records are minted from the same sanitized usage the phase slices
673
+ * accumulate, so per-model sums over an entry's records reconcile with
674
+ * `usageByModel` (and with `usage`) by construction on a fully live
675
+ * invocation.
676
+ */
677
+ interface ProviderCallRecord {
678
+ /** 1-based dispatch order across the whole invocation, phases included. */
679
+ ordinal: number;
680
+ /** The invocation phase that paid the call. */
681
+ role: InvocationRole;
682
+ servedBy: ModelRef;
683
+ /** 1-based try number on the serving target; retries increment it. */
684
+ attempt: number;
685
+ /**
686
+ * 'ok' = a terminal finish; 'error' = a wire failure after dispatch
687
+ * (the provider may still have billed the recorded usage); 'aborted' =
688
+ * the stream was severed by `aborted` below.
689
+ */
690
+ outcome: "ok" | "error" | "aborted";
691
+ /**
692
+ * The provider's response id from the finish metadata
693
+ * (`providerMetadata[<adapter id>].responseId`, surfaced by both
694
+ * shipped adapters). Absent when the adapter reported none or the
695
+ * call never finished; the invoice export marks such rows instead of
696
+ * dropping them.
697
+ */
698
+ responseId?: string;
699
+ /** This call's usage exactly, sanitized like every accounted number. */
700
+ usage: Usage;
701
+ /** True when the stream was cut, so the usage is a lower bound. */
702
+ usageApprox?: boolean;
703
+ /** WireError.code on 'error' outcomes. */
704
+ errorCode?: string;
705
+ /** What severed an 'aborted' call. */
706
+ aborted?: "budget" | "external" | "idle";
707
+ }
708
+ /**
666
709
  * Cost-attribution facts a live run knows at settlement and a pure
667
710
  * journal fold cannot re-derive: the innermost phase name at the call
668
711
  * site, the agent profile, the primary invocation role, the budget
@@ -752,6 +795,18 @@ type JournalEntry = {
752
795
  */
753
796
  costAttribution?: CostAttributionFacts;
754
797
  /**
798
+ * Terminal agent entries: the per-dispatch reconciliation ledger
799
+ * (P1.3), one record per live provider call the invocation made,
800
+ * failed and retried attempts included, so every billable wire call
801
+ * maps to a journal entry and the invoice export can name the
802
+ * provider response ids behind the usage total. Absent on entries
803
+ * written before this shipped and on fully replayed invocations
804
+ * (which made no calls); the invoice fold surfaces such entries as
805
+ * unattributed rows instead of losing their spend. Policy, never
806
+ * identity, exactly like usageByModel.
807
+ */
808
+ providerCalls?: ProviderCallRecord[];
809
+ /**
755
810
  * The serving adapters' declared usage-telemetry semantics at write
756
811
  * time (ProviderAdapter.usageSemantics), stamped so cost numbers stay
757
812
  * auditable across normalization corrections: an UNSTAMPED OpenAI
@@ -2627,6 +2682,8 @@ interface TerminalPatch {
2627
2682
  usageByModel?: UsageSlice[];
2628
2683
  /** Attribution facts behind the CostReport breakdowns; see JournalEntry. */
2629
2684
  costAttribution?: CostAttributionFacts;
2685
+ /** The per-dispatch reconciliation ledger (P1.3); see JournalEntry. */
2686
+ providerCalls?: ProviderCallRecord[];
2630
2687
  /** The serving adapter's usage-semantics version; see JournalEntry. */
2631
2688
  usageSemantics?: string;
2632
2689
  transcriptRef?: string;
@@ -3096,6 +3153,15 @@ interface CheckpointState {
3096
3153
  * exactly as they did then.
3097
3154
  */
3098
3155
  usageByModel?: UsageSlice[];
3156
+ /**
3157
+ * The per-dispatch reconciliation ledger so far (P1.3), carried at
3158
+ * every boundary so a kill-and-resume keeps pre-kill wire calls
3159
+ * attributable. Absent before the first call and on checkpoints
3160
+ * written before the ledger shipped: those restore none, and the
3161
+ * invoice fold surfaces the restored usage as an unattributed
3162
+ * remainder instead of losing it.
3163
+ */
3164
+ providerCalls?: ProviderCallRecord[];
3099
3165
  toolCallsUsed: number;
3100
3166
  schemaAttempts: number;
3101
3167
  /** Compaction points; producers arrive with M4-T03. */
@@ -3876,6 +3942,24 @@ interface UsageLimits {
3876
3942
  max: number;
3877
3943
  costs?: Record<string, number>;
3878
3944
  };
3945
+ /**
3946
+ * The guaranteed finalization turn (the experiment-review P1.1): when
3947
+ * a TOOL budget limiter (maxToolCalls or toolUnits) expires, the
3948
+ * runtime closes the current batch's remaining calls with explicit
3949
+ * skipped-call error results instead of dropping them silently, then
3950
+ * grants the model exactly ONE summary turn with tools withheld
3951
+ * before the invocation settles as status 'limit' with the exact
3952
+ * limiter named in the terminal error. The summary text becomes the
3953
+ * limit result's output for schema-less calls; a ridden schema
3954
+ * validates into typed output when the summary parses (one attempt,
3955
+ * no re-prompt). `maxOutputTokens` bounds the summary turn only;
3956
+ * absent, the ordinary per-turn output policy applies. Off by
3957
+ * default: the skip results and the summary instruction enter the
3958
+ * conversation, so enabling it changes recorded model requests.
3959
+ */
3960
+ finalizationReserve?: {
3961
+ maxOutputTokens?: number;
3962
+ };
3879
3963
  }
3880
3964
  declare const DEFAULT_MAX_TURNS = 32;
3881
3965
  declare const DEFAULT_STREAM_IDLE_TIMEOUT_MS = 12e4;
@@ -3896,6 +3980,9 @@ interface EffectiveUsageLimits {
3896
3980
  max: number;
3897
3981
  costs?: Record<string, number>;
3898
3982
  };
3983
+ finalizationReserve?: {
3984
+ maxOutputTokens?: number;
3985
+ };
3899
3986
  }
3900
3987
  /**
3901
3988
  * Limits merge per spawn: AgentOpts.limits over profile limits over engine
@@ -3967,6 +4054,17 @@ interface AgentResult<T> {
3967
4054
  * which (usage, servedBy) already describes exactly.
3968
4055
  */
3969
4056
  usageByModel?: UsageSlice[];
4057
+ /**
4058
+ * The per-dispatch reconciliation ledger (P1.3): one record per live
4059
+ * provider call this invocation made, failed and retried attempts
4060
+ * included, each with its own usage and the provider's response id
4061
+ * when the adapter surfaced one. Journaled on the terminal entry and
4062
+ * restored verbatim on replay, so a live result and its replayed one
4063
+ * read the same ledger; `invoiceFromJournal` folds the same records
4064
+ * into the invoice export. Absent when the invocation made no wire
4065
+ * call (a fully replayed invocation).
4066
+ */
4067
+ providerCalls?: ProviderCallRecord[];
3970
4068
  transcriptRef: string;
3971
4069
  artifacts?: Artifact[];
3972
4070
  error?: AgentError;
@@ -5319,8 +5417,13 @@ declare class AdmissionController {
5319
5417
  }
5320
5418
  //#endregion
5321
5419
  //#region src/engine/cost-report.d.ts
5322
- /** Folds the per-run attribution buckets into the normative CostReport. */
5323
- declare function buildCostReport(attribution: CostAttribution, totalUsd: number): CostReport;
5420
+ /**
5421
+ * Folds the per-run attribution buckets into the normative CostReport.
5422
+ * Live attribution buckets never see abandoned subtrees, so a host
5423
+ * that tracked abandoned spend itself passes it as `abandoned`;
5424
+ * omitted, the report shows a gross equal to the net.
5425
+ */
5426
+ declare function buildCostReport(attribution: CostAttribution, totalUsd: number, abandoned?: CostReport["abandoned"]): CostReport;
5324
5427
  /**
5325
5428
  * The pure journal fold: the complete CostReport from terminal entries,
5326
5429
  * the same summation the kernel ledger uses (terminal usage exactly
@@ -5345,7 +5448,37 @@ interface PendingExternal {
5345
5448
  }
5346
5449
  /** Full contract: https://docs.rulvar.com/guide/observability. */
5347
5450
  interface CostReport {
5451
+ /**
5452
+ * The NET ledger: priced terminal usage with abandoned subtrees
5453
+ * contributing zero (their spend is a sunk cost of branches the
5454
+ * orchestrator discarded, not of the work the run kept). The
5455
+ * provider still billed them: reconcile invoices against `grossUsd`,
5456
+ * never this.
5457
+ */
5348
5458
  totalUsd: number;
5459
+ /**
5460
+ * The gross/net split (P1.3): totalUsd + abandoned.usd, every priced
5461
+ * terminal slice with abandonment included. This is the immutable
5462
+ * provider-spend figure an invoice reconciles against; abandoning a
5463
+ * branch never shrinks it.
5464
+ */
5465
+ grossUsd: number;
5466
+ /**
5467
+ * Priced spend under abandoned subtrees, exactly the part totalUsd
5468
+ * excludes. `unpriced` here surfaces abandoned slices with no price
5469
+ * row (the top-level `unpriced` lists only slices contributing to
5470
+ * totalUsd), and `usageApprox` follows the same semantics as the
5471
+ * top-level flag over the abandoned entries; grossUsd is an estimate
5472
+ * whenever either flag is raised.
5473
+ */
5474
+ abandoned: {
5475
+ usd: number;
5476
+ unpriced: Array<{
5477
+ model: string;
5478
+ usage: Usage;
5479
+ }>;
5480
+ usageApprox?: boolean;
5481
+ };
5349
5482
  /** Keyed by canonical ModelRef 'adapterId:model'. */
5350
5483
  byModel: Record<string, number>;
5351
5484
  /** ctx.phase names; phase is structural for this map. */
@@ -8150,6 +8283,57 @@ declare class FileTranscriptStore implements TranscriptStore {
8150
8283
  delete(ref: string): Promise<void>;
8151
8284
  }
8152
8285
  //#endregion
8286
+ //#region src/engine/invoice.d.ts
8287
+ /** How a row lines up against a provider invoice. */
8288
+ type InvoiceReconciliation = "matched" | "missing-provider-id" | "unconfirmed" | "unattributed";
8289
+ /** One billable provider call (or an unattributed usage remainder). */
8290
+ interface InvoiceRow {
8291
+ /** The terminal journal entry the row folds from. */
8292
+ entrySeq: number;
8293
+ scope: string;
8294
+ key: string;
8295
+ /** The call's dispatch ordinal within its invocation; remainder and slice rows continue past it. */
8296
+ ordinal: number;
8297
+ servedBy: ModelRef;
8298
+ role?: InvocationRole;
8299
+ /** 1-based try number on the serving target (retries increment it). */
8300
+ attempt?: number;
8301
+ outcome: ProviderCallRecord["outcome"] | "unattributed";
8302
+ responseId?: string;
8303
+ usage: Usage;
8304
+ usageApprox?: boolean;
8305
+ /** This row priced at its own model's rate; absent when no price row covers it. */
8306
+ usd?: number;
8307
+ /** The row lies under an abandoned subtree: in grossUsd, not in netUsd. */
8308
+ abandoned?: true;
8309
+ reconciliation: InvoiceReconciliation;
8310
+ }
8311
+ /** The machine-readable invoice: rows plus the ledger totals. */
8312
+ interface InvoiceExport {
8313
+ rows: InvoiceRow[];
8314
+ /** Every priced terminal slice, abandonment included: equals CostReport.grossUsd. */
8315
+ totalUsd: number;
8316
+ /** The net ledger (abandoned subtrees contribute zero): equals CostReport.totalUsd. */
8317
+ netUsd: number;
8318
+ /** The abandoned share: totalUsd - netUsd, equals CostReport.abandoned.usd. */
8319
+ abandonedUsd: number;
8320
+ /** Usage on models absent from pricing, net and abandoned alike; never a silent zero. */
8321
+ unpriced: Array<{
8322
+ model: string;
8323
+ usage: Usage;
8324
+ }>;
8325
+ /** Rows whose reconciliation is not 'matched'. */
8326
+ reconciliationFailures: number;
8327
+ /** Present and true when any contributing entry carried approximate usage. */
8328
+ usageApprox?: boolean;
8329
+ }
8330
+ /**
8331
+ * The pure invoice fold. Pass the same entries and price table you
8332
+ * would pass `costReportFromJournal`; the totals are that report's
8333
+ * gross/net split verbatim.
8334
+ */
8335
+ declare function invoiceFromJournal(entries: readonly JournalEntry[], priceUsd: (servedBy: ModelRef, usage: Usage) => number | undefined): InvoiceExport;
8336
+ //#endregion
8153
8337
  //#region src/engine/run-profiles.d.ts
8154
8338
  interface RunProfile {
8155
8339
  /** Per-role canonical effort hints (the model refs come from the host). */
@@ -8651,4 +8835,4 @@ interface SandboxBridge {
8651
8835
  declare const SANDBOX_AGENT_OPT_KEYS: readonly string[];
8652
8836
  declare function createSandboxBridge(ctx: Ctx<never>, options: SandboxBridgeOptions): SandboxBridge;
8653
8837
  //#endregion
8654
- export { AWAIT_SCHEMA, AbandonAttempt, AbandonFold, AbandonPayload, AbandonedSpendView, AbortClass, type AdaptiveEvents, AdmissionController, AdmissionDecision, AdmissionRejectedError, AdmissionStatsBefore, AdmitLineage, AdmitRejectReason, AdmitSpec, AdmitVerdict, AgentCallError, AgentError, type AgentEvents, AgentIdentityInput, type AgentInvocationRow, AgentOpts, AgentProfile, AgentProfilePermissions, AgentProfileTemplateOptions, AgentResult, AgentResultMeta, AgentStatus, ApproachSignatureInputs, ApprovalDecision, ApprovalIdentityInput, Artifact, AttemptOutcomeClass, AuditCategory, AuditRecord, AuditRunsOptions, BUDGET_ABORT_REASON, BaseAppend, 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, ChildArtifactPage, ChildIdentityInput, ChildResultPage, type ClaimClass, type ClaimOp, type ClaimStatus, ClaimValidationOptions, CollectOpts, CollectedTurn, CompactionConfig, CompiledPermissionChain, CompiledWorkflow, ConfigError, type CoreEvents, CostAttribution, CostAttributionFacts, CostReport, CreateEngineOptions, type CriticalPath, Ctx, DEFAULT_CHILD_BUDGET_FRACTION, DEFAULT_CHILD_RESULT_PAGE_CHARS, DEFAULT_CITATION_PATTERN, DEFAULT_COMPACTION_THRESHOLD, DEFAULT_ESCALATION_LIMITS, DEFAULT_EVIDENCE_MIN_SHARE, DEFAULT_FINISH_MAX_REPAIRS, 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, DEFAULT_SYNTHESIS_MAX_TURNS, DEFAULT_SYNTHESIS_NOTE_MAX_TURNS, DataKeyProvider, DebitResult, DeclaredLadder, DedupIndex, DedupNote, DedupedClaims, DerivedKey, DeriverRegistry, type DeterminismConfig, DeterminismError, type DeterminismEvents, type DeterminismMode, DispositionRule, DispositionTable, DonorCandidate, DonorRef, DroppedItem, EMIT_RESULT_TOOL, EMPTY_SCHEMA_HASH, EMPTY_TOOLSET_HASH, ESCALATE_TOOL_NAME, ESCALATION_REPORT_SCHEMA, ESCALATION_REQUEST_SCHEMA, EVENT_SEGMENT_STRIDE, EffectiveUsageLimits, Effort, Engine, EngineDefaults, EngineQuotaConfig, EngineQuotaRuntime, EntryKind, EntryRef, EntryStatus, EnvelopeEncryption, EnvelopeEncryptionOptions, ErrorClass, ErrorCode, ErrorPolicy, EscalatedResult, EscalationDecision, EscalationDecisionAbortedError, EscalationDigest, EscalationKind, EscalationLimits, EscalationOptions, EscalationReport, EscalationRequest, EventBus, type EvidenceRef, type ExecutorRegistry, type ExplorationSummary, ExtensionAppendInput, ExtensionDispatchSpec, ExternalIdentityInput, ExternalRegistry, ExtractNecessityInput, FINALIZE_SYNTHESIS_INSTRUCTION, FINISH_SCHEMA, FINISH_TOOL_NAME, FailRunError, FailoverTarget, FailoverTrigger, FallbackField, FallbackTrigger, FileModelKnowledgeStore, FileModelKnowledgeStoreOptions, FileTranscriptStore, FinishInfo, FinishValidationChild, FinishValidationInput, FinishValidationSpec, FinishValidationVerdict, FinishValidator, GET_CHILD_RESULT_SCHEMA, GET_CHILD_RESULT_TOOL_NAME, Gate, GateAudit, type GateRecord, GitWorktreeProvider, GitWorktreeProviderOptions, GraftBoot, HashVersion, HookVerdict, IMPLEMENTATION_PROFILE_LIMITS, INBOX_PROPOSAL_TTL_DAYS, IdentityInput, InMemoryStore, InMemoryTranscriptStore, InProcessRunner, IncrementalSynthesisResult, InvalidResolutionError, InvocationRole, type InvocationTable, type IsolatedExecContext, type IsolatedExecRequest, type IsolatedExecutorTag, type IsolationProvider, type IsolationSpec, Issue$1 as Issue, JOURNAL_ENVELOPE_MARKER, JournalCompatSubCode, JournalCompatibilityError, JournalEntry, JournalMatcher, JournalMissError, JournalOperation, JournalOrderViolation, JournalSerializationContext, 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_CHILD_RESULT_PAGE_CHARS, MAX_DEPTH_CEILING, MatchResult, McpConfig, McpToolSource, MechanicalGateProfile, MechanicalGateVerdict, MemoryQuotaLimiter, type MetaLookupStore, type ModelCaps, ModelChoice, type ModelClaim, ModelEpochInputs, type ModelKnowledgeHandle, type ModelKnowledgeStore, ModelListConstraint, ModelRef, ModelRetry, ModelSpec, Msg, NoProgressDetector, NodeId, NodeLinkValue, NonSerializableValueError, ORCHESTRATE_WORKFLOW_NAME, OnEscalation, OperationDisposition, OrchestrateAcceptance, OrchestrateOptions, OrchestrateSynthesis, OrchestratorBudgetSpec, OrchestratorCapConfigError, OrchestratorExtension, OrchestratorExtensionIO, OrchestratorRuntime, Out, PARALLEL_AGENTS_SCHEMA, PROGRESS_REPORT_TOOL_NAME, ParallelSiteCounter, Part, PendingExternal, PendingToolTurn, PermissionConfig, PermissionGate, PermissionHook, PermissionPreset, PermissionRule, PermissionVerdict, type PhaseRow, PhaseTarget, PipelineCollected, PipelineOpts, PlanInvariantError, PriceTable, PricedUsage, type Pricing, type PricingTier, ProgressReport, type ProviderAdapter, QUOTA_WINDOW_MS, QualityFloors, QuotaCounters, type QuotaDecision, type QuotaEstimate, type QuotaLimiter, type QuotaReservationRequest, QuotaRule, QuotaWindowSnapshot, READ_CHILD_ARTIFACT_SCHEMA, READ_CHILD_ARTIFACT_TOOL_NAME, RESEARCH_PROFILE_LIMITS, REVIEW_PROFILE_LIMITS, ROLE_EFFORT_DEFAULTS, ROOT_ACCOUNT, ROOT_SCOPE, RUN_PROFILES, RUN_SETTLE_DECISION_TYPE, RandIdentityInput, RandPayload, ReconcileOptions, ReconcileResult, RefEntryAppender, RefEntryClassification, RefusalInfo, RepeatedClaim, ReplayDisposition, ReplayMode, ReplayPlanHashMismatch, Replayer, RepositoryResearchToolset, RepositoryResearchToolsetOptions, ResearchAgentProfileOptions, ResearchAgentProfileResult, ResearchEvidenceEntry, ResolutionArbiter, ResolutionAttempt, ResolutionBy, ResolutionFold, ResolutionLayer, ResolutionOutcome, ResolutionPayload, ResolvedInvocation, ResolvedToolset, ResumeHandle, ResumeOptions, ResumePreview, ResumeReport, RetryClass, RetryPolicy, ReuseConfig, RiskRuleValue, Role, RulvarError, RulvarErrorCode, RunAgentOptions, RunAuditVerdict, RunBudget, RunEventSink, RunExport, type RunFilter, RunHandle, RunInternals, type RunMeta, RunOptions, RunOutcome, RunProfile, RunStateAudit, RunStatus, RuntimeEventSink, SANDBOX_AGENT_OPT_KEYS, SPAWN_AGENT_SCHEMA, SandboxBridge, SandboxBridgeOptions, SandboxError, SandboxHostToWorker, SandboxMethod, SandboxWorkerToHost, SchemaPair, SchemaSpec, SchemaValidationResult, ScopeSegment, ScriptRejected, ScriptRunner, ScrubNote, SecretMasker, 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, type ToolExecutorProvider, 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, assertFencedWrites, atCompactionThreshold, auditRun, auditRuns, 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, compileSecretMasker, compileVerifiedLayer, constantTimeEqual, costReportFromJournal, countsAgainstLimit, createCanonicalIdMinter, createCtx, createEngine, createEnvelopeEncryption, createSandboxBridge, currentOnlyKeyRing, decodeCheckpoint, dedupeRepeatedClaims, defineWorkflow, deriveContentKey, deriverV1, deriverV2, digestOf, dispositionHook, emptyDigestBlocks, emptyToolset, encodeCheckpoint, entryUsageSlices, escalateTool, evaluatePermission, evaluateReuse, evidencePreservedValidator, executeWorkflow, exhaustionCodeOf, extractCandidate, failoverTriggerOf, fallbackTriggerOf, filterClaimsForRun, finalizeFires, foldTermination, formatRePrompt, formatScopePath, hasFencedWrites, hasMetaLookup, hashRunArgs, hashRunOutput, hashWorkflowBody, hashWorkflowSource, identityJcs, implementationAgentProfile, isEscalated, isSchemaPairSpec, isStandardSchemaSpec, isStrictCompatibleSchema, kMaxOf, knowledgeHash, ladderLengthOf, ladderRungChoice, lastRunSettle, latestProgressReport, lexShellCommand, liftRetainedParts, lineageWeightOf, localKeyProvider, makeOrchestratorWorkflow, maskSecrets, maskSecretsDeep, maskSecretsJson, matchArgvPattern, matchShellCommand, mcp, memoryQuotaLimiter, mergeQuotaDenial, mergeUsageLimits, metaMatchesFilter, minMatchesValidator, modelEpochOf, modelKnowledgeCard, modelSpecIdentity, needsSeparateExtract, nextFailover, nodeLinkKey, normalizeApproachTag, normalizeEntry, normalizeFallbacks, orchestrate, parallelScope, parseModelRef, parseScopePath, phiInitialOf, pipelineScope, planNodeScope, priceEntryUsage, priceUsdOf, profileCard, profileRegistrySnapshotHash, progressReportTool, projectHistory, projectIdentity, projectToJsonSchema, proposalStatement, providerOf, quotaActualTokens, quotaEstimateTokens, quotaRuleAdmission, quotaRuleMatches, readRunMeta, readTerminationInit, reconcileRunMeta, reduceAuditTrail, reduceCriticalPath, reduceInvocationTable, registryKeyRing, remeasureQueue, replayDisposition, repositoryResearchToolset, requiredFieldsValidator, requiredSectionsValidator, researchAgentProfile, resolveModelInvocation, resolvePricing, resolveToolset, retryClassOf, retryDelayMs, reviewAgentProfile, roleConfiguredInRouting, roundOneDisposition, runAgent, runProfile, sanitizeTerminalText, sanitizeTokenCount, sanitizeUsage, sanitizeUsageDelta, scanJournalCompatibility, schemaHash, schemaHashOfSpec, selectStructuredOutputTier, shouldCompact, snapshotUsage, spawnDepthOf, summarizeInstruction, summarizeOutput, terminationConfigDrift, tierWithinCaps, toApprovalDecision, toJournalValue, tool, toolContract, toolsetHash, ttlState, usageViolations, validateEditorialCommit, validateEngineQuotaConfig, validateEntryShape, validateEscalationLimits, validateEscalationReport, validateQuotaRules, validateRetryPolicy, validateSchemaSpec, validateTerminationLimits, validateUsageLimits, workflowScope, workflowSourceRef, wrapJournalStore, wrapTranscriptStore };
8838
+ export { AWAIT_SCHEMA, AbandonAttempt, AbandonFold, AbandonPayload, AbandonedSpendView, AbortClass, type AdaptiveEvents, AdmissionController, AdmissionDecision, AdmissionRejectedError, AdmissionStatsBefore, AdmitLineage, AdmitRejectReason, AdmitSpec, AdmitVerdict, AgentCallError, AgentError, type AgentEvents, AgentIdentityInput, type AgentInvocationRow, AgentOpts, AgentProfile, AgentProfilePermissions, AgentProfileTemplateOptions, AgentResult, AgentResultMeta, AgentStatus, ApproachSignatureInputs, ApprovalDecision, ApprovalIdentityInput, Artifact, AttemptOutcomeClass, AuditCategory, AuditRecord, AuditRunsOptions, BUDGET_ABORT_REASON, BaseAppend, 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, ChildArtifactPage, ChildIdentityInput, ChildResultPage, type ClaimClass, type ClaimOp, type ClaimStatus, ClaimValidationOptions, CollectOpts, CollectedTurn, CompactionConfig, CompiledPermissionChain, CompiledWorkflow, ConfigError, type CoreEvents, CostAttribution, CostAttributionFacts, CostReport, CreateEngineOptions, type CriticalPath, Ctx, DEFAULT_CHILD_BUDGET_FRACTION, DEFAULT_CHILD_RESULT_PAGE_CHARS, DEFAULT_CITATION_PATTERN, DEFAULT_COMPACTION_THRESHOLD, DEFAULT_ESCALATION_LIMITS, DEFAULT_EVIDENCE_MIN_SHARE, DEFAULT_FINISH_MAX_REPAIRS, 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, DEFAULT_SYNTHESIS_MAX_TURNS, DEFAULT_SYNTHESIS_NOTE_MAX_TURNS, DataKeyProvider, DebitResult, DeclaredLadder, DedupIndex, DedupNote, DedupedClaims, DerivedKey, DeriverRegistry, type DeterminismConfig, DeterminismError, type DeterminismEvents, type DeterminismMode, DispositionRule, DispositionTable, DonorCandidate, DonorRef, DroppedItem, EMIT_RESULT_TOOL, EMPTY_SCHEMA_HASH, EMPTY_TOOLSET_HASH, ESCALATE_TOOL_NAME, ESCALATION_REPORT_SCHEMA, ESCALATION_REQUEST_SCHEMA, EVENT_SEGMENT_STRIDE, EffectiveUsageLimits, Effort, Engine, EngineDefaults, EngineQuotaConfig, EngineQuotaRuntime, EntryKind, EntryRef, EntryStatus, EnvelopeEncryption, EnvelopeEncryptionOptions, ErrorClass, ErrorCode, ErrorPolicy, EscalatedResult, EscalationDecision, EscalationDecisionAbortedError, EscalationDigest, EscalationKind, EscalationLimits, EscalationOptions, EscalationReport, EscalationRequest, EventBus, type EvidenceRef, type ExecutorRegistry, type ExplorationSummary, ExtensionAppendInput, ExtensionDispatchSpec, ExternalIdentityInput, ExternalRegistry, ExtractNecessityInput, FINALIZE_SYNTHESIS_INSTRUCTION, FINISH_SCHEMA, FINISH_TOOL_NAME, FailRunError, FailoverTarget, FailoverTrigger, FallbackField, FallbackTrigger, FileModelKnowledgeStore, FileModelKnowledgeStoreOptions, FileTranscriptStore, FinishInfo, FinishValidationChild, FinishValidationInput, FinishValidationSpec, FinishValidationVerdict, FinishValidator, GET_CHILD_RESULT_SCHEMA, GET_CHILD_RESULT_TOOL_NAME, Gate, GateAudit, type GateRecord, GitWorktreeProvider, GitWorktreeProviderOptions, GraftBoot, HashVersion, HookVerdict, IMPLEMENTATION_PROFILE_LIMITS, INBOX_PROPOSAL_TTL_DAYS, IdentityInput, InMemoryStore, InMemoryTranscriptStore, InProcessRunner, IncrementalSynthesisResult, InvalidResolutionError, InvocationRole, type InvocationTable, InvoiceExport, InvoiceReconciliation, InvoiceRow, type IsolatedExecContext, type IsolatedExecRequest, type IsolatedExecutorTag, type IsolationProvider, type IsolationSpec, Issue$1 as Issue, JOURNAL_ENVELOPE_MARKER, JournalCompatSubCode, JournalCompatibilityError, JournalEntry, JournalMatcher, JournalMissError, JournalOperation, JournalOrderViolation, JournalSerializationContext, 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_CHILD_RESULT_PAGE_CHARS, MAX_DEPTH_CEILING, MatchResult, McpConfig, McpToolSource, MechanicalGateProfile, MechanicalGateVerdict, MemoryQuotaLimiter, type MetaLookupStore, type ModelCaps, ModelChoice, type ModelClaim, ModelEpochInputs, type ModelKnowledgeHandle, type ModelKnowledgeStore, ModelListConstraint, ModelRef, ModelRetry, ModelSpec, Msg, NoProgressDetector, NodeId, NodeLinkValue, NonSerializableValueError, ORCHESTRATE_WORKFLOW_NAME, OnEscalation, OperationDisposition, OrchestrateAcceptance, OrchestrateOptions, OrchestrateSynthesis, OrchestratorBudgetSpec, OrchestratorCapConfigError, OrchestratorExtension, OrchestratorExtensionIO, OrchestratorRuntime, Out, PARALLEL_AGENTS_SCHEMA, PROGRESS_REPORT_TOOL_NAME, ParallelSiteCounter, Part, PendingExternal, PendingToolTurn, PermissionConfig, PermissionGate, PermissionHook, PermissionPreset, PermissionRule, PermissionVerdict, type PhaseRow, PhaseTarget, PipelineCollected, PipelineOpts, PlanInvariantError, PriceTable, PricedUsage, type Pricing, type PricingTier, ProgressReport, type ProviderAdapter, ProviderCallRecord, QUOTA_WINDOW_MS, QualityFloors, QuotaCounters, type QuotaDecision, type QuotaEstimate, type QuotaLimiter, type QuotaReservationRequest, QuotaRule, QuotaWindowSnapshot, READ_CHILD_ARTIFACT_SCHEMA, READ_CHILD_ARTIFACT_TOOL_NAME, RESEARCH_PROFILE_LIMITS, REVIEW_PROFILE_LIMITS, ROLE_EFFORT_DEFAULTS, ROOT_ACCOUNT, ROOT_SCOPE, RUN_PROFILES, RUN_SETTLE_DECISION_TYPE, RandIdentityInput, RandPayload, ReconcileOptions, ReconcileResult, RefEntryAppender, RefEntryClassification, RefusalInfo, RepeatedClaim, ReplayDisposition, ReplayMode, ReplayPlanHashMismatch, Replayer, RepositoryResearchToolset, RepositoryResearchToolsetOptions, ResearchAgentProfileOptions, ResearchAgentProfileResult, ResearchEvidenceEntry, ResolutionArbiter, ResolutionAttempt, ResolutionBy, ResolutionFold, ResolutionLayer, ResolutionOutcome, ResolutionPayload, ResolvedInvocation, ResolvedToolset, ResumeHandle, ResumeOptions, ResumePreview, ResumeReport, RetryClass, RetryPolicy, ReuseConfig, RiskRuleValue, Role, RulvarError, RulvarErrorCode, RunAgentOptions, RunAuditVerdict, RunBudget, RunEventSink, RunExport, type RunFilter, RunHandle, RunInternals, type RunMeta, RunOptions, RunOutcome, RunProfile, RunStateAudit, RunStatus, RuntimeEventSink, SANDBOX_AGENT_OPT_KEYS, SPAWN_AGENT_SCHEMA, SandboxBridge, SandboxBridgeOptions, SandboxError, SandboxHostToWorker, SandboxMethod, SandboxWorkerToHost, SchemaPair, SchemaSpec, SchemaValidationResult, ScopeSegment, ScriptRejected, ScriptRunner, ScrubNote, SecretMasker, 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, type ToolExecutorProvider, 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, assertFencedWrites, atCompactionThreshold, auditRun, auditRuns, 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, compileSecretMasker, compileVerifiedLayer, constantTimeEqual, costReportFromJournal, countsAgainstLimit, createCanonicalIdMinter, createCtx, createEngine, createEnvelopeEncryption, createSandboxBridge, currentOnlyKeyRing, decodeCheckpoint, dedupeRepeatedClaims, defineWorkflow, deriveContentKey, deriverV1, deriverV2, digestOf, dispositionHook, emptyDigestBlocks, emptyToolset, encodeCheckpoint, entryUsageSlices, escalateTool, evaluatePermission, evaluateReuse, evidencePreservedValidator, executeWorkflow, exhaustionCodeOf, extractCandidate, failoverTriggerOf, fallbackTriggerOf, filterClaimsForRun, finalizeFires, foldTermination, formatRePrompt, formatScopePath, hasFencedWrites, hasMetaLookup, hashRunArgs, hashRunOutput, hashWorkflowBody, hashWorkflowSource, identityJcs, implementationAgentProfile, invoiceFromJournal, isEscalated, isSchemaPairSpec, isStandardSchemaSpec, isStrictCompatibleSchema, kMaxOf, knowledgeHash, ladderLengthOf, ladderRungChoice, lastRunSettle, latestProgressReport, lexShellCommand, liftRetainedParts, lineageWeightOf, localKeyProvider, makeOrchestratorWorkflow, maskSecrets, maskSecretsDeep, maskSecretsJson, matchArgvPattern, matchShellCommand, mcp, memoryQuotaLimiter, mergeQuotaDenial, mergeUsageLimits, metaMatchesFilter, minMatchesValidator, modelEpochOf, modelKnowledgeCard, modelSpecIdentity, needsSeparateExtract, nextFailover, nodeLinkKey, normalizeApproachTag, normalizeEntry, normalizeFallbacks, orchestrate, parallelScope, parseModelRef, parseScopePath, phiInitialOf, pipelineScope, planNodeScope, priceEntryUsage, priceUsdOf, profileCard, profileRegistrySnapshotHash, progressReportTool, projectHistory, projectIdentity, projectToJsonSchema, proposalStatement, providerOf, quotaActualTokens, quotaEstimateTokens, quotaRuleAdmission, quotaRuleMatches, readRunMeta, readTerminationInit, reconcileRunMeta, reduceAuditTrail, reduceCriticalPath, reduceInvocationTable, registryKeyRing, remeasureQueue, replayDisposition, repositoryResearchToolset, requiredFieldsValidator, requiredSectionsValidator, researchAgentProfile, resolveModelInvocation, resolvePricing, resolveToolset, retryClassOf, retryDelayMs, reviewAgentProfile, roleConfiguredInRouting, roundOneDisposition, runAgent, runProfile, sanitizeTerminalText, sanitizeTokenCount, sanitizeUsage, sanitizeUsageDelta, scanJournalCompatibility, schemaHash, schemaHashOfSpec, selectStructuredOutputTier, shouldCompact, snapshotUsage, spawnDepthOf, summarizeInstruction, summarizeOutput, terminationConfigDrift, tierWithinCaps, toApprovalDecision, toJournalValue, tool, toolContract, toolsetHash, ttlState, usageViolations, validateEditorialCommit, validateEngineQuotaConfig, validateEntryShape, validateEscalationLimits, validateEscalationReport, validateQuotaRules, validateRetryPolicy, validateSchemaSpec, validateTerminationLimits, validateUsageLimits, workflowScope, workflowSourceRef, wrapJournalStore, wrapTranscriptStore };
package/dist/index.js CHANGED
@@ -6995,6 +6995,7 @@ var Replayer = class {
6995
6995
  if (patch.servedBy !== void 0) entry.servedBy = patch.servedBy;
6996
6996
  if (patch.usageByModel !== void 0) entry.usageByModel = patch.usageByModel;
6997
6997
  if (patch.costAttribution !== void 0) entry.costAttribution = patch.costAttribution;
6998
+ if (patch.providerCalls !== void 0) entry.providerCalls = patch.providerCalls;
6998
6999
  if (patch.usageSemantics !== void 0) entry.usageSemantics = patch.usageSemantics;
6999
7000
  if (patch.transcriptRef !== void 0) entry.transcriptRef = patch.transcriptRef;
7000
7001
  if (patch.checkpointRef !== void 0) entry.checkpointRef = patch.checkpointRef;
@@ -8064,8 +8065,16 @@ function emptyByRole() {
8064
8065
  function isOrchestratorAccount(scope) {
8065
8066
  return scope === "orchestrator" || scope.endsWith("/orchestrator");
8066
8067
  }
8067
- /** Folds the per-run attribution buckets into the normative CostReport. */
8068
- function buildCostReport(attribution, totalUsd) {
8068
+ /**
8069
+ * Folds the per-run attribution buckets into the normative CostReport.
8070
+ * Live attribution buckets never see abandoned subtrees, so a host
8071
+ * that tracked abandoned spend itself passes it as `abandoned`;
8072
+ * omitted, the report shows a gross equal to the net.
8073
+ */
8074
+ function buildCostReport(attribution, totalUsd, abandoned = {
8075
+ usd: 0,
8076
+ unpriced: []
8077
+ }) {
8069
8078
  const byRole = emptyByRole();
8070
8079
  for (const [role, usd] of attribution.byRole) byRole[role] = usd;
8071
8080
  const orchestrator = attribution.orchestrator ?? {
@@ -8076,6 +8085,8 @@ function buildCostReport(attribution, totalUsd) {
8076
8085
  };
8077
8086
  return {
8078
8087
  totalUsd,
8088
+ grossUsd: totalUsd + abandoned.usd,
8089
+ abandoned,
8079
8090
  byModel: Object.fromEntries(attribution.byModel),
8080
8091
  byPhase: Object.fromEntries(attribution.byPhase),
8081
8092
  byAgentType: Object.fromEntries(attribution.byAgentType),
@@ -8106,6 +8117,9 @@ function costReportFromJournal(entries, priceUsd) {
8106
8117
  const unpriced = [];
8107
8118
  let totalUsd = 0;
8108
8119
  let usageApprox = false;
8120
+ let abandonedUsd = 0;
8121
+ const abandonedUnpriced = [];
8122
+ let abandonedApprox = false;
8109
8123
  let orchestratorSpentUsd = 0;
8110
8124
  let reserveUsedUsd = 0;
8111
8125
  let wakes = 0;
@@ -8113,7 +8127,18 @@ function costReportFromJournal(entries, priceUsd) {
8113
8127
  for (const entry of entries) {
8114
8128
  if (entry.kind === "decision" && entry.value?.decisionType === "orchestrator_budget_cap") forcedFinish = true;
8115
8129
  if (entry.kind === "external" && entry.status === "suspended" && typeof entry.value?.key === "string" && (entry.value.key.startsWith("wake:") || entry.value.key.includes(":wake:"))) wakes += 1;
8116
- if (entry.kind !== "resolution" && entry.kind !== "abandon" && abandonFold.isAbandoned(entry.ref ?? entry.seq)) continue;
8130
+ if (entry.kind !== "resolution" && entry.kind !== "abandon" && abandonFold.isAbandoned(entry.ref ?? entry.seq)) {
8131
+ if (entry.status !== "running" && entry.usage !== void 0) {
8132
+ const abandonedPriced = priceEntryUsage(entry, priceUsd);
8133
+ abandonedUsd += abandonedPriced.usd;
8134
+ for (const slice of abandonedPriced.unpriced) abandonedUnpriced.push({
8135
+ model: slice.servedBy,
8136
+ usage: slice.usage
8137
+ });
8138
+ if (entry.usageApprox === true) abandonedApprox = true;
8139
+ }
8140
+ continue;
8141
+ }
8117
8142
  if (entry.status === "running" || entry.usage === void 0) continue;
8118
8143
  const priced = priceEntryUsage(entry, priceUsd);
8119
8144
  for (const slice of priced.unpriced) unpriced.push({
@@ -8137,6 +8162,12 @@ function costReportFromJournal(entries, priceUsd) {
8137
8162
  }
8138
8163
  return {
8139
8164
  totalUsd,
8165
+ grossUsd: totalUsd + abandonedUsd,
8166
+ abandoned: {
8167
+ usd: abandonedUsd,
8168
+ unpriced: abandonedUnpriced,
8169
+ ...abandonedApprox ? { usageApprox: true } : {}
8170
+ },
8140
8171
  byModel,
8141
8172
  byPhase,
8142
8173
  byAgentType,
@@ -8153,6 +8184,142 @@ function costReportFromJournal(entries, priceUsd) {
8153
8184
  };
8154
8185
  }
8155
8186
  //#endregion
8187
+ //#region src/engine/invoice.ts
8188
+ /**
8189
+ * The invoice export (P1.3): a pure fold over terminal entries that
8190
+ * turns the per-dispatch reconciliation ledger (`providerCalls`) into
8191
+ * one row per billable provider call, so a host can line the run up
8192
+ * against the provider's invoice. The totals are the SAME slice fold
8193
+ * `costReportFromJournal` runs, so `totalUsd` here equals
8194
+ * `CostReport.grossUsd` (and `netUsd` equals `CostReport.totalUsd`)
8195
+ * exactly, never approximately; per-row `usd` prices each call
8196
+ * individually and is informational, since a nonlinear price table
8197
+ * (long-context tiers) prices a split differently from its sum.
8198
+ *
8199
+ * Coverage is loss-free by construction: an entry whose records do not
8200
+ * cover its usage total (a resume restored from a checkpoint written
8201
+ * before the ledger shipped) contributes an `unattributed` remainder
8202
+ * row, and an entry with no records at all (written before the ledger
8203
+ * shipped, or a fully replayed invocation) contributes one
8204
+ * `unattributed` row per usage slice. Missing provider ids are marked,
8205
+ * never dropped: a finished call without one reconciles as
8206
+ * `missing-provider-id`, a failed or severed call without one as
8207
+ * `unconfirmed` (the provider may or may not have billed it; there is
8208
+ * no id to match).
8209
+ *
8210
+ * Pricing happens at fold time from the table you pass, exactly like
8211
+ * CostReport: the export reflects current rates, not the rates at
8212
+ * write time.
8213
+ */
8214
+ const USAGE_FIELDS = [
8215
+ "inputTokens",
8216
+ "outputTokens",
8217
+ "cacheReadTokens",
8218
+ "cacheWriteTokens"
8219
+ ];
8220
+ /** entry.usage minus the records' sum, clamped at zero per field. */
8221
+ function usageRemainder(total, records) {
8222
+ const remainder = {
8223
+ inputTokens: total.inputTokens,
8224
+ outputTokens: total.outputTokens,
8225
+ cacheReadTokens: total.cacheReadTokens,
8226
+ cacheWriteTokens: total.cacheWriteTokens
8227
+ };
8228
+ let reasoning = total.reasoningTokens ?? 0;
8229
+ for (const record of records) {
8230
+ for (const field of USAGE_FIELDS) remainder[field] = Math.max(0, remainder[field] - record.usage[field]);
8231
+ reasoning = Math.max(0, reasoning - (record.usage.reasoningTokens ?? 0));
8232
+ }
8233
+ if (reasoning > 0) remainder.reasoningTokens = reasoning;
8234
+ return USAGE_FIELDS.some((field) => remainder[field] > 0) || (remainder.reasoningTokens ?? 0) > 0 ? remainder : void 0;
8235
+ }
8236
+ /** A single row priced at its own model's rate; broken rates fold as unpriced. */
8237
+ function rowUsd(priceUsd, servedBy, usage) {
8238
+ const usd = priceUsd(servedBy, usage);
8239
+ return usd !== void 0 && Number.isFinite(usd) && usd >= 0 ? usd : void 0;
8240
+ }
8241
+ /**
8242
+ * The pure invoice fold. Pass the same entries and price table you
8243
+ * would pass `costReportFromJournal`; the totals are that report's
8244
+ * gross/net split verbatim.
8245
+ */
8246
+ function invoiceFromJournal(entries, priceUsd) {
8247
+ const report = costReportFromJournal(entries, priceUsd);
8248
+ const abandonFold = buildAbandonFold(entries);
8249
+ const rows = [];
8250
+ for (const entry of entries) {
8251
+ if (entry.status === "running" || entry.usage === void 0) continue;
8252
+ const abandoned = entry.kind !== "resolution" && entry.kind !== "abandon" && abandonFold.isAbandoned(entry.ref ?? entry.seq);
8253
+ const base = {
8254
+ entrySeq: entry.seq,
8255
+ scope: entry.scope,
8256
+ key: entry.key
8257
+ };
8258
+ const mark = abandoned ? { abandoned: true } : {};
8259
+ const records = entry.providerCalls ?? [];
8260
+ for (const record of records) {
8261
+ const usd = rowUsd(priceUsd, record.servedBy, record.usage);
8262
+ rows.push({
8263
+ ...base,
8264
+ ordinal: record.ordinal,
8265
+ servedBy: record.servedBy,
8266
+ role: record.role,
8267
+ attempt: record.attempt,
8268
+ outcome: record.outcome,
8269
+ ...record.responseId === void 0 ? {} : { responseId: record.responseId },
8270
+ usage: record.usage,
8271
+ ...record.usageApprox === true ? { usageApprox: true } : {},
8272
+ ...usd === void 0 ? {} : { usd },
8273
+ ...mark,
8274
+ reconciliation: record.responseId !== void 0 ? "matched" : record.outcome === "ok" ? "missing-provider-id" : "unconfirmed"
8275
+ });
8276
+ }
8277
+ if (records.length === 0) {
8278
+ entryUsageSlices(entry).forEach((slice, index) => {
8279
+ const usd = rowUsd(priceUsd, slice.servedBy, slice.usage);
8280
+ rows.push({
8281
+ ...base,
8282
+ ordinal: index + 1,
8283
+ servedBy: slice.servedBy,
8284
+ ...slice.role === void 0 ? {} : { role: slice.role },
8285
+ outcome: "unattributed",
8286
+ usage: slice.usage,
8287
+ ...entry.usageApprox === true ? { usageApprox: true } : {},
8288
+ ...usd === void 0 ? {} : { usd },
8289
+ ...mark,
8290
+ reconciliation: "unattributed"
8291
+ });
8292
+ });
8293
+ continue;
8294
+ }
8295
+ const remainder = usageRemainder(entry.usage, records);
8296
+ if (remainder !== void 0 && entry.servedBy !== void 0) {
8297
+ const usd = rowUsd(priceUsd, entry.servedBy, remainder);
8298
+ rows.push({
8299
+ ...base,
8300
+ ordinal: records.length + 1,
8301
+ servedBy: entry.servedBy,
8302
+ outcome: "unattributed",
8303
+ usage: remainder,
8304
+ ...entry.usageApprox === true ? { usageApprox: true } : {},
8305
+ ...usd === void 0 ? {} : { usd },
8306
+ ...mark,
8307
+ reconciliation: "unattributed"
8308
+ });
8309
+ }
8310
+ }
8311
+ const usageApprox = report.usageApprox === true || report.abandoned.usageApprox === true;
8312
+ return {
8313
+ rows,
8314
+ totalUsd: report.grossUsd,
8315
+ netUsd: report.totalUsd,
8316
+ abandonedUsd: report.abandoned.usd,
8317
+ unpriced: [...report.unpriced, ...report.abandoned.unpriced],
8318
+ reconciliationFailures: rows.filter((row) => row.reconciliation !== "matched").length,
8319
+ ...usageApprox ? { usageApprox: true } : {}
8320
+ };
8321
+ }
8322
+ //#endregion
8156
8323
  //#region src/engine/run-profiles.ts
8157
8324
  /**
8158
8325
  * The shipped presets (fast / standard / deep / ultra "and similar").
@@ -9328,6 +9495,8 @@ function mergeUsageLimits(call, profile, engine) {
9328
9495
  if (maxCallsPerTool !== void 0) merged.maxCallsPerTool = maxCallsPerTool;
9329
9496
  const toolUnits = pick("toolUnits");
9330
9497
  if (toolUnits !== void 0) merged.toolUnits = toolUnits;
9498
+ const finalizationReserve = pick("finalizationReserve");
9499
+ if (finalizationReserve !== void 0) merged.finalizationReserve = finalizationReserve;
9331
9500
  return merged;
9332
9501
  }
9333
9502
  /**
@@ -9367,6 +9536,12 @@ function validateUsageLimits(limits, site) {
9367
9536
  for (const [name, cost] of Object.entries(costs)) requireNonNegativeInteger(cost, `${site}.toolUnits.costs['${name}']`);
9368
9537
  }
9369
9538
  }
9539
+ if (limits.finalizationReserve !== void 0) {
9540
+ const reserve = limits.finalizationReserve;
9541
+ if (typeof reserve !== "object" || reserve === null || Array.isArray(reserve)) throw new ConfigError(`${site}.finalizationReserve must be { maxOutputTokens? }`);
9542
+ const { maxOutputTokens } = reserve;
9543
+ if (maxOutputTokens !== void 0) requirePositiveInteger(maxOutputTokens, `${site}.finalizationReserve.maxOutputTokens`);
9544
+ }
9370
9545
  }
9371
9546
  //#endregion
9372
9547
  //#region src/runtime/model-retry.ts
@@ -10455,6 +10630,7 @@ async function runAgent(options) {
10455
10630
  usage: addUsage$1(prior?.usage ?? ZERO_USAGE$1, usage)
10456
10631
  });
10457
10632
  };
10633
+ const providerCalls = [];
10458
10634
  let invocationCounter = 0;
10459
10635
  let transportRetries = 0;
10460
10636
  const roleUsageSnapshot = (role) => {
@@ -10530,8 +10706,27 @@ async function runAgent(options) {
10530
10706
  let toolCallsUsed = 0;
10531
10707
  let escalationRequest;
10532
10708
  let abortClass;
10709
+ /**
10710
+ * Set at a tool-budget expiry when limits.finalizationReserve is
10711
+ * configured (P1.1); the reserve turn itself runs at ONE site after
10712
+ * the loop ends (the pending-turn path trips before the dispatch
10713
+ * machinery below is even defined), inside the still-open loop phase.
10714
+ */
10715
+ let reserveRequest;
10533
10716
  const noProgress = new NoProgressDetector(limits.noProgressTurns);
10534
10717
  const guard = explorationTrackingEnabled(limits) ? new ExplorationGuard(limits) : void 0;
10718
+ /**
10719
+ * The exact limiter behind a tool-budget expiry, with its counts: the
10720
+ * wording rides the finalization-reserve instruction and the 'limit'
10721
+ * terminal's errorMessage (P1.1 criterion: the terminal names the
10722
+ * limiter, never a bare status).
10723
+ */
10724
+ const toolBudgetDetail = (limiter) => {
10725
+ if (limiter === "maxToolCalls") return `maxToolCalls (${String(toolCallsUsed)}/${String(limits.maxToolCalls ?? 0)})`;
10726
+ const max = limits.toolUnits?.max ?? 0;
10727
+ const used = guard === void 0 ? max : guard.summary(toolCallsUsed).toolUnitsUsed ?? max;
10728
+ return `toolUnits (${String(used)}/${String(max)})`;
10729
+ };
10535
10730
  if (limits.toolBudgetNotices === true && limits.maxToolCalls === void 0) events?.emit({
10536
10731
  type: "log",
10537
10732
  level: "warn",
@@ -10585,6 +10780,10 @@ async function runAgent(options) {
10585
10780
  addPhaseUsage(slice.role ?? primaryRole, slice.servedBy, sliceUsage);
10586
10781
  options.budget?.onUsage(sliceUsage, slice.servedBy);
10587
10782
  }
10783
+ for (const record of restored.providerCalls ?? []) providerCalls.push(usageViolations(record.usage).length === 0 ? record : {
10784
+ ...record,
10785
+ usage: sanitizeUsage(record.usage)
10786
+ });
10588
10787
  guard?.restore(messages);
10589
10788
  if (limits.toolBudgetNotices === true && limits.maxToolCalls !== void 0) for (const threshold of crossedNoticeThresholds(toolCallsUsed, limits.maxToolCalls)) firedNotices.add(threshold);
10590
10789
  }
@@ -10619,6 +10818,7 @@ async function runAgent(options) {
10619
10818
  toolCallsUsed,
10620
10819
  schemaAttempts,
10621
10820
  compaction: [...compactionPoints],
10821
+ ...providerCalls.length === 0 ? {} : { providerCalls: [...providerCalls] },
10622
10822
  ...pending === void 0 ? {} : { pending }
10623
10823
  });
10624
10824
  };
@@ -10653,15 +10853,42 @@ async function runAgent(options) {
10653
10853
  part.isError = true;
10654
10854
  return part;
10655
10855
  };
10856
+ /**
10857
+ * Closes the batch tail at a tool-budget expiry (P1.1): with the
10858
+ * finalization reserve configured every not-admitted call gets a
10859
+ * typed skipped-call error result naming the limiter, so the model
10860
+ * (and the transcript) sees exactly which calls never executed and
10861
+ * the summary turn's history stays well formed (providers reject
10862
+ * tool calls without matching results). Without the reserve the
10863
+ * tail stays unanswered, byte-identical to before.
10864
+ */
10865
+ const closeSkippedTail = (skippedCalls, limiter) => {
10866
+ if (limits.finalizationReserve === void 0) return;
10867
+ for (const call of skippedCalls) parts.push(errorPart(call, {
10868
+ error: "skipped: the tool budget is exhausted; the call was not executed",
10869
+ limiter,
10870
+ skipped: true
10871
+ }));
10872
+ };
10656
10873
  for (const [index, call] of calls.entries()) {
10657
- if (limits.maxToolCalls !== void 0 && toolCallsUsed >= limits.maxToolCalls) return {
10658
- parts,
10659
- limitHit: true
10660
- };
10661
- if (guard !== void 0 && guard.unitsExhausted()) return {
10662
- parts,
10663
- limitHit: true
10664
- };
10874
+ if (limits.maxToolCalls !== void 0 && toolCallsUsed >= limits.maxToolCalls) {
10875
+ closeSkippedTail(calls.slice(index), "maxToolCalls");
10876
+ return {
10877
+ parts,
10878
+ limitHit: true,
10879
+ limiter: "maxToolCalls",
10880
+ skipped: calls.length - index
10881
+ };
10882
+ }
10883
+ if (guard !== void 0 && guard.unitsExhausted()) {
10884
+ closeSkippedTail(calls.slice(index), "toolUnits");
10885
+ return {
10886
+ parts,
10887
+ limitHit: true,
10888
+ limiter: "toolUnits",
10889
+ skipped: calls.length - index
10890
+ };
10891
+ }
10665
10892
  const def = runtime.defs.find((candidate) => candidate.name === call.name);
10666
10893
  events?.emit({
10667
10894
  type: "tool:start",
@@ -10863,7 +11090,7 @@ async function runAgent(options) {
10863
11090
  if (record.isError === true) part.isError = true;
10864
11091
  return part;
10865
11092
  });
10866
- const { parts, limitHit, escalated, finished, guardTrip } = await runToolCalls([restored.pending.awaiting, ...restored.pending.remaining], priorParts);
11093
+ const { parts, limitHit, escalated, finished, guardTrip, limiter, skipped } = await runToolCalls([restored.pending.awaiting, ...restored.pending.remaining], priorParts);
10867
11094
  if (parts.length > 0) messages.push({
10868
11095
  role: "tool",
10869
11096
  parts
@@ -10884,6 +11111,16 @@ async function runAgent(options) {
10884
11111
  retryable: false
10885
11112
  };
10886
11113
  errorMessage = guard.describeTrip();
11114
+ } else if (limiter !== void 0 && limits.finalizationReserve !== void 0) {
11115
+ agentError = {
11116
+ kind: "terminal",
11117
+ retryable: false
11118
+ };
11119
+ errorMessage = `tool budget exhausted: ${toolBudgetDetail(limiter)}; skipped tool calls: ${String(skipped ?? 0)}`;
11120
+ reserveRequest = {
11121
+ limiter,
11122
+ skipped: skipped ?? 0
11123
+ };
10887
11124
  }
10888
11125
  } else {
10889
11126
  maybePushBudgetNotice();
@@ -10925,6 +11162,7 @@ async function runAgent(options) {
10925
11162
  const reasoningRemainder = Math.max(0, (safe.reasoningTokens ?? 0) - (reported.reasoningTokens ?? 0));
10926
11163
  if (reasoningRemainder > 0) remainder.reasoningTokens = reasoningRemainder;
10927
11164
  if (remainder.inputTokens > 0 || remainder.outputTokens > 0 || remainder.cacheReadTokens > 0 || remainder.cacheWriteTokens > 0) options.budget?.onUsage(remainder, ref);
11165
+ return safe;
10928
11166
  };
10929
11167
  const retryPolicy = options.retry?.policy ?? DEFAULT_RETRY_POLICY;
10930
11168
  const retryOn = retryPolicy.retryOn ?? DEFAULT_RETRY_POLICY.retryOn ?? [];
@@ -10939,7 +11177,8 @@ async function runAgent(options) {
10939
11177
  usage: ZERO_USAGE$1,
10940
11178
  reported: ZERO_USAGE$1,
10941
11179
  usageApprox: true,
10942
- aborted
11180
+ aborted,
11181
+ neverDispatched: true
10943
11182
  });
10944
11183
  const backoffWait = async (ms) => {
10945
11184
  const signals = [];
@@ -11055,7 +11294,23 @@ async function runAgent(options) {
11055
11294
  msg: `the shared quota limiter failed to reconcile a reservation: ${detail}`
11056
11295
  });
11057
11296
  }
11058
- if (outcome.quotaDenied !== true) recordUsage(outcome.usage, outcome.reported, target.adapter.id, target.resolved.ref, site.role, outcome.usageViolation);
11297
+ if (outcome.quotaDenied !== true && outcome.neverDispatched !== true) {
11298
+ const accounted = recordUsage(outcome.usage, outcome.reported, target.adapter.id, target.resolved.ref, site.role, outcome.usageViolation);
11299
+ const namespace = outcome.providerMetadata?.[target.adapter.id];
11300
+ const record = {
11301
+ ordinal: providerCalls.length + 1,
11302
+ role: site.role,
11303
+ servedBy: target.resolved.ref,
11304
+ attempt: tries + 1,
11305
+ outcome: outcome.aborted !== void 0 ? "aborted" : outcome.wireError !== void 0 ? "error" : "ok",
11306
+ usage: accounted
11307
+ };
11308
+ if (typeof namespace?.responseId === "string") record.responseId = namespace.responseId;
11309
+ if (outcome.usageApprox) record.usageApprox = true;
11310
+ if (outcome.aborted !== void 0) record.aborted = outcome.aborted;
11311
+ else if (outcome.wireError !== void 0) record.errorCode = outcome.wireError.code;
11312
+ providerCalls.push(record);
11313
+ }
11059
11314
  tries += 1;
11060
11315
  const retryClass = outcome.aborted === "idle" ? "transport" : outcome.wireError === void 0 ? void 0 : retryClassOf(outcome.wireError);
11061
11316
  if (retryClass === void 0) return {
@@ -11285,7 +11540,7 @@ async function runAgent(options) {
11285
11540
  }
11286
11541
  if (options.tools !== void 0 && outcome.turn.toolCalls.length > 0) {
11287
11542
  noProgress.recordTurn({ toolCalls: outcome.turn.toolCalls.length });
11288
- const { parts, limitHit, escalated, finished, guardTrip } = await runToolCalls(outcome.turn.toolCalls, []);
11543
+ const { parts, limitHit, escalated, finished, guardTrip, limiter, skipped } = await runToolCalls(outcome.turn.toolCalls, []);
11289
11544
  if (parts.length > 0) messages.push({
11290
11545
  role: "tool",
11291
11546
  parts
@@ -11310,6 +11565,16 @@ async function runAgent(options) {
11310
11565
  retryable: false
11311
11566
  };
11312
11567
  errorMessage = guard.describeTrip();
11568
+ } else if (limiter !== void 0 && limits.finalizationReserve !== void 0) {
11569
+ agentError = {
11570
+ kind: "terminal",
11571
+ retryable: false
11572
+ };
11573
+ errorMessage = `tool budget exhausted: ${toolBudgetDetail(limiter)}; skipped tool calls: ${String(skipped ?? 0)}`;
11574
+ reserveRequest = {
11575
+ limiter,
11576
+ skipped: skipped ?? 0
11577
+ };
11313
11578
  }
11314
11579
  break;
11315
11580
  }
@@ -11495,6 +11760,110 @@ async function runAgent(options) {
11495
11760
  await saveBoundary();
11496
11761
  continue loop;
11497
11762
  }
11763
+ if (status === "limit" && reserveRequest !== void 0) {
11764
+ const { limiter, skipped } = reserveRequest;
11765
+ let proceed = true;
11766
+ try {
11767
+ options.budget?.beforeTurn();
11768
+ } catch {
11769
+ events?.emit({
11770
+ type: "log",
11771
+ level: "warn",
11772
+ msg: "the finalization reserve turn was skipped: the budget blocks further turns"
11773
+ });
11774
+ proceed = false;
11775
+ }
11776
+ if (proceed) {
11777
+ turns += 1;
11778
+ const reserveMessages = [...messages, {
11779
+ role: "user",
11780
+ parts: [{
11781
+ type: "text",
11782
+ text: `The tool budget is exhausted (${toolBudgetDetail(limiter)}). Skipped tool calls: ${String(skipped)}; no further tool calls will execute. This is the final turn: produce your best final answer from the evidence already collected.`
11783
+ }]
11784
+ }];
11785
+ let reserveDispatch;
11786
+ try {
11787
+ reserveDispatch = await dispatchPhase({
11788
+ role: primaryRole,
11789
+ chain: loopChain,
11790
+ cursor: loopCursor,
11791
+ requestFor: (target) => {
11792
+ let req = buildRequest(target.resolved, projectHistory(reserveMessages, providerOf(target.adapter)), limits, options.tools?.contracts);
11793
+ if (options.schema !== void 0 && options.canonicalSchema !== void 0 && !separateExtract) req = applyStructuredOutputTier(req, rideTierFor(target), options.canonicalSchema);
11794
+ if (req.tools !== void 0) req = {
11795
+ ...req,
11796
+ toolChoice: "none"
11797
+ };
11798
+ const reserveMax = limits.finalizationReserve?.maxOutputTokens;
11799
+ if (reserveMax !== void 0) req = {
11800
+ ...req,
11801
+ maxOutputTokens: Math.min(req.maxOutputTokens ?? reserveMax, reserveMax)
11802
+ };
11803
+ return applyOutputBudget(req, target, options.budget);
11804
+ },
11805
+ streamOptionsFor: (target) => {
11806
+ const reserveStreamOptions = {
11807
+ idleTimeoutMs: limits.streamIdleTimeoutMs,
11808
+ signals: options.signal === void 0 ? [] : [options.signal],
11809
+ onUsage: (delta) => options.budget?.onUsage(delta, target.resolved.ref)
11810
+ };
11811
+ if (options.budget?.signal !== void 0) reserveStreamOptions.budgetSignal = options.budget.signal;
11812
+ if (options.stream === true) reserveStreamOptions.onDelta = (delta) => events?.emit({
11813
+ type: "agent:stream",
11814
+ delta
11815
+ });
11816
+ return reserveStreamOptions;
11817
+ }
11818
+ });
11819
+ } catch (thrown) {
11820
+ if (!(thrown instanceof BudgetExhaustedError)) throw thrown;
11821
+ events?.emit({
11822
+ type: "log",
11823
+ level: "warn",
11824
+ msg: `the finalization reserve turn was skipped: ${thrown.message}`
11825
+ });
11826
+ }
11827
+ if (reserveDispatch !== void 0) {
11828
+ const { outcome, target: reserveTarget } = reserveDispatch;
11829
+ servedBy = reserveTarget.resolved.ref;
11830
+ usageApprox = usageApprox || outcome.usageApprox;
11831
+ messages.push(assistantMsg(outcome.turn, liftRetainedParts(outcome.providerMetadata, reserveTarget.adapter)));
11832
+ if (invariantViolation !== void 0) {
11833
+ status = "error";
11834
+ agentError = {
11835
+ kind: "transport",
11836
+ retryable: false
11837
+ };
11838
+ errorMessage = invariantViolation;
11839
+ } else if (outcome.aborted === "external") status = "cancelled";
11840
+ else if (outcome.aborted === "budget") {
11841
+ status = "cancelled";
11842
+ agentError = {
11843
+ kind: "budget",
11844
+ retryable: false
11845
+ };
11846
+ } else {
11847
+ await saveBoundary();
11848
+ if (outcome.wireError !== void 0 || outcome.aborted === "idle") events?.emit({
11849
+ type: "log",
11850
+ level: "warn",
11851
+ msg: "the finalization reserve turn failed; the limit terminal stands" + (outcome.wireError === void 0 ? " (stream idle timeout)" : ` (${outcome.wireError.message})`)
11852
+ });
11853
+ else if (options.schema === void 0) {
11854
+ const summary = outcome.turn.text;
11855
+ if (summary.trim() !== "") output = summary;
11856
+ } else if (!separateExtract && options.canonicalSchema !== void 0) {
11857
+ const candidate = extractCandidate(outcome.turn, rideTierFor(reserveTarget));
11858
+ if (candidate !== void 0) {
11859
+ const validation = await validateSchemaSpec(options.schema, candidate.raw);
11860
+ if (validation.valid) output = validation.value;
11861
+ }
11862
+ }
11863
+ }
11864
+ }
11865
+ }
11866
+ }
11498
11867
  endPhase(loopPhase, phaseOutcome(), servedBy);
11499
11868
  if (status === "ok" && !finishedViaTool && options.finalize !== void 0) {
11500
11869
  const finalizeResolved = options.finalize.resolved;
@@ -11752,6 +12121,7 @@ async function runAgent(options) {
11752
12121
  transcriptRef
11753
12122
  };
11754
12123
  if (usageByPhaseModel.size > 1) result.usageByModel = usageSlices();
12124
+ if (providerCalls.length > 0) result.providerCalls = providerCalls;
11755
12125
  if (agentError !== void 0) result.error = agentError;
11756
12126
  if (escalationRequest !== void 0) result.escalationRequest = escalationRequest;
11757
12127
  if (abortClass !== void 0) result.abortClass = abortClass;
@@ -13638,6 +14008,7 @@ function createCtx(internals, rootWorkflow) {
13638
14008
  result.errorMessage = terminal.error.message;
13639
14009
  }
13640
14010
  if (terminal?.artifacts !== void 0) result.artifacts = terminal.artifacts;
14011
+ if (terminal?.providerCalls !== void 0) result.providerCalls = terminal.providerCalls;
13641
14012
  if (terminal?.status === "escalated" && terminal.escalation !== void 0) result.escalation = terminal.escalation;
13642
14013
  {
13643
14014
  const stampedData = terminal?.error?.data;
@@ -14199,6 +14570,7 @@ function createCtx(internals, rootWorkflow) {
14199
14570
  servedBy: result.servedBy,
14200
14571
  ...servedSemantics === void 0 ? {} : { usageSemantics: servedSemantics },
14201
14572
  ...result.usageByModel === void 0 ? {} : { usageByModel: result.usageByModel },
14573
+ ...result.providerCalls === void 0 ? {} : { providerCalls: result.providerCalls },
14202
14574
  costAttribution: {
14203
14575
  ...state.phase === void 0 ? {} : { phase: state.phase },
14204
14576
  agentType,
@@ -14209,7 +14581,7 @@ function createCtx(internals, rootWorkflow) {
14209
14581
  transcriptRef: result.transcriptRef
14210
14582
  };
14211
14583
  if (result.status === "escalated" && result.escalation !== void 0) terminalPatch.escalation = result.escalation;
14212
- if (result.output !== null && result.status === "ok") terminalPatch.value = result.output;
14584
+ if (result.output !== null && (result.status === "ok" || result.status === "limit")) terminalPatch.value = result.output;
14213
14585
  if (result.error !== void 0) terminalPatch.error = agentErrorToWire(result.error, result.errorMessage ?? `agent terminated with status ${result.status}`);
14214
14586
  const resultUsageApprox = result.usageApprox === true;
14215
14587
  if (resultUsageApprox) terminalPatch.usageApprox = true;
@@ -18068,4 +18440,4 @@ function createSandboxBridge(ctx, options) {
18068
18440
  };
18069
18441
  }
18070
18442
  //#endregion
18071
- 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_CHILD_RESULT_PAGE_CHARS, DEFAULT_CITATION_PATTERN, DEFAULT_COMPACTION_THRESHOLD, DEFAULT_ESCALATION_LIMITS, DEFAULT_EVIDENCE_MIN_SHARE, DEFAULT_FINISH_MAX_REPAIRS, 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, DEFAULT_SYNTHESIS_MAX_TURNS, DEFAULT_SYNTHESIS_NOTE_MAX_TURNS, DedupIndex, DeterminismError, EMIT_RESULT_TOOL, EMPTY_SCHEMA_HASH, EMPTY_TOOLSET_HASH, ESCALATE_TOOL_NAME, ESCALATION_REPORT_SCHEMA, ESCALATION_REQUEST_SCHEMA, EVENT_SEGMENT_STRIDE, EscalationDecisionAbortedError, EventBus, ExternalRegistry, FINALIZE_SYNTHESIS_INSTRUCTION, FINISH_SCHEMA, FINISH_TOOL_NAME, FailRunError, FileModelKnowledgeStore, FileTranscriptStore, GET_CHILD_RESULT_SCHEMA, GET_CHILD_RESULT_TOOL_NAME, GitWorktreeProvider, IMPLEMENTATION_PROFILE_LIMITS, INBOX_PROPOSAL_TTL_DAYS, InMemoryStore, InMemoryTranscriptStore, InProcessRunner, InvalidResolutionError, JOURNAL_ENVELOPE_MARKER, 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_CHILD_RESULT_PAGE_CHARS, MAX_DEPTH_CEILING, ModelRetry, NoProgressDetector, NonSerializableValueError, ORCHESTRATE_WORKFLOW_NAME, OrchestratorCapConfigError, PARALLEL_AGENTS_SCHEMA, PROGRESS_REPORT_TOOL_NAME, ParallelSiteCounter, PlanInvariantError, QUOTA_WINDOW_MS, READ_CHILD_ARTIFACT_SCHEMA, READ_CHILD_ARTIFACT_TOOL_NAME, RESEARCH_PROFILE_LIMITS, REVIEW_PROFILE_LIMITS, ROLE_EFFORT_DEFAULTS, ROOT_ACCOUNT, ROOT_SCOPE, RUN_PROFILES, RUN_SETTLE_DECISION_TYPE, ReplayPlanHashMismatch, Replayer, ResolutionArbiter, ResolutionFold, RulvarError, RunBudget, SANDBOX_AGENT_OPT_KEYS, 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, assertFencedWrites, atCompactionThreshold, auditRun, auditRuns, 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, compileSecretMasker, compileVerifiedLayer, constantTimeEqual, costReportFromJournal, countsAgainstLimit, createCanonicalIdMinter, createCtx, createEngine, createEnvelopeEncryption, createSandboxBridge, currentOnlyKeyRing, decodeCheckpoint, dedupeRepeatedClaims, defineWorkflow, deriveContentKey, deriverV1, deriverV2, digestOf, dispositionHook, emptyDigestBlocks, emptyToolset, encodeCheckpoint, entryUsageSlices, escalateTool, evaluatePermission, evaluateReuse, evidencePreservedValidator, executeWorkflow, exhaustionCodeOf, extractCandidate, failoverTriggerOf, fallbackTriggerOf, filterClaimsForRun, finalizeFires, foldTermination, formatRePrompt, formatScopePath, hasFencedWrites, hasMetaLookup, hashRunArgs, hashRunOutput, hashWorkflowBody, hashWorkflowSource, identityJcs, implementationAgentProfile, isEscalated, isSchemaPairSpec, isStandardSchemaSpec, isStrictCompatibleSchema, kMaxOf, knowledgeHash, ladderLengthOf, ladderRungChoice, lastRunSettle, latestProgressReport, lexShellCommand, liftRetainedParts, lineageWeightOf, localKeyProvider, makeOrchestratorWorkflow, maskSecrets, maskSecretsDeep, maskSecretsJson, matchArgvPattern, matchShellCommand, mcp, memoryQuotaLimiter, mergeQuotaDenial, mergeUsageLimits, metaMatchesFilter, minMatchesValidator, modelEpochOf, modelKnowledgeCard, modelSpecIdentity, needsSeparateExtract, nextFailover, nodeLinkKey, normalizeApproachTag, normalizeEntry, normalizeFallbacks, orchestrate, parallelScope, parseModelRef, parseScopePath, phiInitialOf, pipelineScope, planNodeScope, priceEntryUsage, priceUsdOf, profileCard, profileRegistrySnapshotHash, progressReportTool, projectHistory, projectIdentity, projectToJsonSchema, proposalStatement, providerOf, quotaActualTokens, quotaEstimateTokens, quotaRuleAdmission, quotaRuleMatches, readRunMeta, readTerminationInit, reconcileRunMeta, reduceAuditTrail, reduceCriticalPath, reduceInvocationTable, registryKeyRing, remeasureQueue, replayDisposition, repositoryResearchToolset, requiredFieldsValidator, requiredSectionsValidator, researchAgentProfile, resolveModelInvocation, resolvePricing, resolveToolset, retryClassOf, retryDelayMs, reviewAgentProfile, roleConfiguredInRouting, roundOneDisposition, runAgent, runProfile, sanitizeTerminalText, sanitizeTokenCount, sanitizeUsage, sanitizeUsageDelta, scanJournalCompatibility, schemaHash, schemaHashOfSpec, selectStructuredOutputTier, shouldCompact, snapshotUsage, spawnDepthOf, summarizeInstruction, summarizeOutput, terminationConfigDrift, tierWithinCaps, toApprovalDecision, toJournalValue, tool, toolContract, toolsetHash, ttlState, usageViolations, validateEditorialCommit, validateEngineQuotaConfig, validateEntryShape, validateEscalationLimits, validateEscalationReport, validateQuotaRules, validateRetryPolicy, validateSchemaSpec, validateTerminationLimits, validateUsageLimits, workflowScope, workflowSourceRef, wrapJournalStore, wrapTranscriptStore };
18443
+ 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_CHILD_RESULT_PAGE_CHARS, DEFAULT_CITATION_PATTERN, DEFAULT_COMPACTION_THRESHOLD, DEFAULT_ESCALATION_LIMITS, DEFAULT_EVIDENCE_MIN_SHARE, DEFAULT_FINISH_MAX_REPAIRS, 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, DEFAULT_SYNTHESIS_MAX_TURNS, DEFAULT_SYNTHESIS_NOTE_MAX_TURNS, DedupIndex, DeterminismError, EMIT_RESULT_TOOL, EMPTY_SCHEMA_HASH, EMPTY_TOOLSET_HASH, ESCALATE_TOOL_NAME, ESCALATION_REPORT_SCHEMA, ESCALATION_REQUEST_SCHEMA, EVENT_SEGMENT_STRIDE, EscalationDecisionAbortedError, EventBus, ExternalRegistry, FINALIZE_SYNTHESIS_INSTRUCTION, FINISH_SCHEMA, FINISH_TOOL_NAME, FailRunError, FileModelKnowledgeStore, FileTranscriptStore, GET_CHILD_RESULT_SCHEMA, GET_CHILD_RESULT_TOOL_NAME, GitWorktreeProvider, IMPLEMENTATION_PROFILE_LIMITS, INBOX_PROPOSAL_TTL_DAYS, InMemoryStore, InMemoryTranscriptStore, InProcessRunner, InvalidResolutionError, JOURNAL_ENVELOPE_MARKER, 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_CHILD_RESULT_PAGE_CHARS, MAX_DEPTH_CEILING, ModelRetry, NoProgressDetector, NonSerializableValueError, ORCHESTRATE_WORKFLOW_NAME, OrchestratorCapConfigError, PARALLEL_AGENTS_SCHEMA, PROGRESS_REPORT_TOOL_NAME, ParallelSiteCounter, PlanInvariantError, QUOTA_WINDOW_MS, READ_CHILD_ARTIFACT_SCHEMA, READ_CHILD_ARTIFACT_TOOL_NAME, RESEARCH_PROFILE_LIMITS, REVIEW_PROFILE_LIMITS, ROLE_EFFORT_DEFAULTS, ROOT_ACCOUNT, ROOT_SCOPE, RUN_PROFILES, RUN_SETTLE_DECISION_TYPE, ReplayPlanHashMismatch, Replayer, ResolutionArbiter, ResolutionFold, RulvarError, RunBudget, SANDBOX_AGENT_OPT_KEYS, 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, assertFencedWrites, atCompactionThreshold, auditRun, auditRuns, 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, compileSecretMasker, compileVerifiedLayer, constantTimeEqual, costReportFromJournal, countsAgainstLimit, createCanonicalIdMinter, createCtx, createEngine, createEnvelopeEncryption, createSandboxBridge, currentOnlyKeyRing, decodeCheckpoint, dedupeRepeatedClaims, defineWorkflow, deriveContentKey, deriverV1, deriverV2, digestOf, dispositionHook, emptyDigestBlocks, emptyToolset, encodeCheckpoint, entryUsageSlices, escalateTool, evaluatePermission, evaluateReuse, evidencePreservedValidator, executeWorkflow, exhaustionCodeOf, extractCandidate, failoverTriggerOf, fallbackTriggerOf, filterClaimsForRun, finalizeFires, foldTermination, formatRePrompt, formatScopePath, hasFencedWrites, hasMetaLookup, hashRunArgs, hashRunOutput, hashWorkflowBody, hashWorkflowSource, identityJcs, implementationAgentProfile, invoiceFromJournal, isEscalated, isSchemaPairSpec, isStandardSchemaSpec, isStrictCompatibleSchema, kMaxOf, knowledgeHash, ladderLengthOf, ladderRungChoice, lastRunSettle, latestProgressReport, lexShellCommand, liftRetainedParts, lineageWeightOf, localKeyProvider, makeOrchestratorWorkflow, maskSecrets, maskSecretsDeep, maskSecretsJson, matchArgvPattern, matchShellCommand, mcp, memoryQuotaLimiter, mergeQuotaDenial, mergeUsageLimits, metaMatchesFilter, minMatchesValidator, modelEpochOf, modelKnowledgeCard, modelSpecIdentity, needsSeparateExtract, nextFailover, nodeLinkKey, normalizeApproachTag, normalizeEntry, normalizeFallbacks, orchestrate, parallelScope, parseModelRef, parseScopePath, phiInitialOf, pipelineScope, planNodeScope, priceEntryUsage, priceUsdOf, profileCard, profileRegistrySnapshotHash, progressReportTool, projectHistory, projectIdentity, projectToJsonSchema, proposalStatement, providerOf, quotaActualTokens, quotaEstimateTokens, quotaRuleAdmission, quotaRuleMatches, readRunMeta, readTerminationInit, reconcileRunMeta, reduceAuditTrail, reduceCriticalPath, reduceInvocationTable, registryKeyRing, remeasureQueue, replayDisposition, repositoryResearchToolset, requiredFieldsValidator, requiredSectionsValidator, researchAgentProfile, resolveModelInvocation, resolvePricing, resolveToolset, retryClassOf, retryDelayMs, reviewAgentProfile, roleConfiguredInRouting, roundOneDisposition, runAgent, runProfile, sanitizeTerminalText, sanitizeTokenCount, sanitizeUsage, sanitizeUsageDelta, scanJournalCompatibility, schemaHash, schemaHashOfSpec, selectStructuredOutputTier, shouldCompact, snapshotUsage, spawnDepthOf, summarizeInstruction, summarizeOutput, terminationConfigDrift, tierWithinCaps, toApprovalDecision, toJournalValue, tool, toolContract, toolsetHash, ttlState, usageViolations, validateEditorialCommit, validateEngineQuotaConfig, validateEntryShape, validateEscalationLimits, validateEscalationReport, validateQuotaRules, validateRetryPolicy, validateSchemaSpec, validateTerminationLimits, validateUsageLimits, workflowScope, workflowSourceRef, wrapJournalStore, wrapTranscriptStore };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rulvar/core",
3
- "version": "1.59.4",
3
+ "version": "1.61.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",