@rulvar/core 1.42.0 → 1.43.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
@@ -3242,9 +3242,24 @@ interface RunAgentOptions<S extends SchemaSpec = JsonSchema> {
3242
3242
  * tool ends the loop with status ok; the call's validated `result`
3243
3243
  * argument becomes the agent output (the orchestrator finish
3244
3244
  * tool). The tool's execute never runs, mirroring escalate.
3245
+ * `validate` is the optional host judgment over a schema valid call
3246
+ * (the RV-204 finish validators): ok finishes as before; a rejection
3247
+ * becomes the call's error tool result and the turn continues, so the
3248
+ * model can repair and call the terminal tool again. The hook owns
3249
+ * bounding and journaling; the loop stays policy only and never
3250
+ * throws.
3245
3251
  */
3246
3252
  terminalTool?: {
3247
3253
  name: string;
3254
+ validate?: (call: {
3255
+ id: string;
3256
+ result: unknown;
3257
+ }) => Promise<{
3258
+ ok: true;
3259
+ } | {
3260
+ ok: false;
3261
+ feedback: Record<string, unknown>;
3262
+ }>;
3248
3263
  };
3249
3264
  agentType?: string;
3250
3265
  /** The primary invocation role of the tool loop; default 'loop' (M6-T05). */
@@ -4995,6 +5010,75 @@ declare function workflowSourceRef(runId: string): string;
4995
5010
  declare function hashRunArgs(args: unknown): string | undefined;
4996
5011
  declare function createEngine(options: CreateEngineOptions): Engine;
4997
5012
  //#endregion
5013
+ //#region src/orchestrator/finish-validators.d.ts
5014
+ /** What a {@link FinishValidator} judges. */
5015
+ interface FinishValidationInput {
5016
+ /** The finish call's `result` argument exactly as the model passed it. */
5017
+ readonly result: Json | null;
5018
+ /**
5019
+ * The result as text: a string result verbatim, anything else its JSON
5020
+ * serialization (the same convention the child result evidence tools
5021
+ * use), so textual validators never re-implement serialization.
5022
+ */
5023
+ readonly text: string;
5024
+ }
5025
+ /** The verdict of one validator over one finish attempt. */
5026
+ type FinishValidationVerdict = {
5027
+ ok: true;
5028
+ } | {
5029
+ ok: false;
5030
+ reasons: string[];
5031
+ };
5032
+ /**
5033
+ * A deterministic host validator of the orchestrator finish result.
5034
+ * `validate` must be pure, synchronous host code: no model calls, no
5035
+ * clock, no filesystem, because a verdict must reproduce on replay and a
5036
+ * throwing validator is a host defect that fails the run as ConfigError
5037
+ * (never journaled, never granted a repair turn).
5038
+ */
5039
+ interface FinishValidator {
5040
+ /**
5041
+ * Unique within one orchestrate call; appears in the journaled
5042
+ * verdicts, the repair feedback, and the orchestrator prompt.
5043
+ */
5044
+ readonly name: string;
5045
+ validate(input: FinishValidationInput): FinishValidationVerdict;
5046
+ }
5047
+ /**
5048
+ * Requires every named section to appear LITERALLY in the result text
5049
+ * (a heading like 'FINDINGS' or any marker the goal demands). Default
5050
+ * name 'required-sections'; pass `name` to run several instances.
5051
+ */
5052
+ declare function requiredSectionsValidator(options: {
5053
+ sections: string[];
5054
+ name?: string;
5055
+ }): FinishValidator;
5056
+ /**
5057
+ * Requires the result to be a JSON object carrying every named field
5058
+ * with a substantial value: present, not null, and not an empty or
5059
+ * whitespace only string (empty arrays, zero, and false COUNT as
5060
+ * present; emptiness rules beyond strings belong to a custom
5061
+ * validator). Default name 'required-fields'.
5062
+ */
5063
+ declare function requiredFieldsValidator(options: {
5064
+ fields: string[];
5065
+ name?: string;
5066
+ }): FinishValidator;
5067
+ /**
5068
+ * Requires at least `min` matches of `pattern` in the result text (the
5069
+ * plan's citation and source count checks: a file:line pattern, a URL
5070
+ * pattern). The pattern compiles at construction (invalid patterns are a
5071
+ * ConfigError before any run exists) and matches globally; `min` is a
5072
+ * positive integer. Default name 'min-matches'; pass `name` to run
5073
+ * several instances, because names must be unique per orchestrate call.
5074
+ */
5075
+ declare function minMatchesValidator(options: {
5076
+ pattern: string;
5077
+ flags?: string;
5078
+ min: number;
5079
+ name?: string;
5080
+ }): FinishValidator;
5081
+ //#endregion
4998
5082
  //#region src/orchestrator/handles.d.ts
4999
5083
  /** The per-child digest handed to the orchestrator. */
5000
5084
  interface TaskDigest {
@@ -5495,6 +5579,47 @@ interface OrchestrateAcceptance {
5495
5579
  minSuccessful: number;
5496
5580
  };
5497
5581
  }
5582
+ /** How many rejected finishes are repaired by default: the plan's repair once. */
5583
+ declare const DEFAULT_FINISH_MAX_REPAIRS = 1;
5584
+ /**
5585
+ * The opt in deterministic validation of the orchestrator finish result
5586
+ * (the v1.40.0 improvement plan's RV-204 slice). Every SCHEMA valid
5587
+ * finish({ result }) call first passes the configured host validators;
5588
+ * a rejection returns the failure reasons to the model as the call's
5589
+ * error tool result and the turn continues (a repair turn: the model
5590
+ * fixes the result and calls finish again), bounded by maxRepairs. A
5591
+ * rejection past the bound fails the run with the typed FailRunError
5592
+ * (code 'fail_run', data.source 'orchestrator_finish_validation'),
5593
+ * BEFORE the acceptance settle, so acceptance never judges a finish the
5594
+ * validators rejected. Every verdict journals as ONE decision entry
5595
+ * keyed by the finish call id (decisionType
5596
+ * 'orchestrator_finish_validation'), so a resume rolls the SAME
5597
+ * verdicts forward without re-running validator code, and the whole
5598
+ * exchange replays without new paid calls. The toolset never changes
5599
+ * (the contract rides the orchestrator prompt), zero configuration adds
5600
+ * zero journal entries, and the budget cap paths keep their posture:
5601
+ * the reserved finalize dispatch is never validated, exactly as
5602
+ * acceptance never judges it. Repair turns spend from the
5603
+ * orchestrator's ordinary limits and ceilings (maxTurns, budget caps,
5604
+ * the root budgetUsd); maxRepairs is the explicit bound, and a
5605
+ * dedicated repair budget reserve is deliberately out of scope here.
5606
+ */
5607
+ interface FinishValidationSpec {
5608
+ /**
5609
+ * Run in configuration order on every schema valid finish call; names
5610
+ * must be unique (pass `name` to a factory to run several instances).
5611
+ * A validator that THROWS is a host defect: the run fails as
5612
+ * ConfigError, nothing journals, and no repair turn is granted.
5613
+ */
5614
+ validators: FinishValidator[];
5615
+ /**
5616
+ * How many rejected finishes are returned to the model for repair
5617
+ * before the run fails; a nonnegative integer, default
5618
+ * {@link DEFAULT_FINISH_MAX_REPAIRS}. Zero means the first rejected
5619
+ * finish fails the run.
5620
+ */
5621
+ maxRepairs?: number;
5622
+ }
5498
5623
  interface OrchestrateOptions {
5499
5624
  model?: ModelSpec;
5500
5625
  /** Registered profile names to advertise; default: every profile. */
@@ -5529,6 +5654,11 @@ interface OrchestrateOptions {
5529
5654
  /** The opt in child completion policy; see {@link OrchestrateAcceptance}. */
5530
5655
  acceptance?: OrchestrateAcceptance;
5531
5656
  /**
5657
+ * The opt in deterministic host validation of the finish result, with
5658
+ * bounded repair; see {@link FinishValidationSpec}.
5659
+ */
5660
+ finishValidation?: FinishValidationSpec;
5661
+ /**
5532
5662
  * Opt in to the evidence tools `get_child_result` and
5533
5663
  * `read_child_artifact` (the v1.40.0 improvement plan's narrow RV-201
5534
5664
  * slice). The digest an await returns is a wake signal truncated to 400
@@ -7039,4 +7169,4 @@ interface SandboxBridge {
7039
7169
  declare const SANDBOX_AGENT_OPT_KEYS: readonly string[];
7040
7170
  declare function createSandboxBridge(ctx: Ctx<never>, options: SandboxBridgeOptions): SandboxBridge;
7041
7171
  //#endregion
7042
- 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, 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, Ctx, DEFAULT_CHILD_BUDGET_FRACTION, DEFAULT_CHILD_RESULT_PAGE_CHARS, 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, EVENT_SEGMENT_STRIDE, EffectiveUsageLimits, Effort, Engine, EngineDefaults, EntryKind, EntryRef, EntryStatus, ErrorClass, ErrorCode, ErrorPolicy, EscalatedResult, EscalationDecision, EscalationDecisionAbortedError, EscalationDigest, EscalationKind, EscalationLimits, EscalationOptions, EscalationReport, EscalationRequest, EventBus, type EvidenceRef, ExtensionAppendInput, ExtensionDispatchSpec, ExternalIdentityInput, ExternalRegistry, ExtractNecessityInput, FINALIZE_SYNTHESIS_INSTRUCTION, FINISH_SCHEMA, FINISH_TOOL_NAME, FailRunError, FailoverTarget, FailoverTrigger, FallbackField, FallbackTrigger, FileModelKnowledgeStore, FileModelKnowledgeStoreOptions, FileTranscriptStore, FinishInfo, GET_CHILD_RESULT_SCHEMA, GET_CHILD_RESULT_TOOL_NAME, 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_CHILD_RESULT_PAGE_CHARS, MAX_DEPTH_CEILING, MatchResult, McpConfig, McpToolSource, MechanicalGateProfile, MechanicalGateVerdict, 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, 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, READ_CHILD_ARTIFACT_SCHEMA, READ_CHILD_ARTIFACT_TOOL_NAME, 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, SANDBOX_AGENT_OPT_KEYS, 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, hasMetaLookup, hashRunArgs, hashWorkflowBody, hashWorkflowSource, identityJcs, isEscalated, isSchemaPairSpec, isStandardSchemaSpec, isStrictCompatibleSchema, kMaxOf, knowledgeHash, ladderLengthOf, ladderRungChoice, lexShellCommand, liftRetainedParts, lineageWeightOf, makeOrchestratorWorkflow, maskSecrets, maskSecretsDeep, maskSecretsJson, matchArgvPattern, matchShellCommand, mcp, mergeUsageLimits, metaMatchesFilter, 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, readRunMeta, readTerminationInit, registryKeyRing, remeasureQueue, replayDisposition, resolveModelInvocation, resolvePricing, resolveToolset, retryClassOf, retryDelayMs, 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, validateEntryShape, validateEscalationLimits, validateEscalationReport, validateRetryPolicy, validateSchemaSpec, validateTerminationLimits, validateUsageLimits, workflowScope, workflowSourceRef, wrapJournalStore, wrapTranscriptStore };
7172
+ 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, 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, Ctx, DEFAULT_CHILD_BUDGET_FRACTION, DEFAULT_CHILD_RESULT_PAGE_CHARS, DEFAULT_COMPACTION_THRESHOLD, DEFAULT_ESCALATION_LIMITS, 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, 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, EVENT_SEGMENT_STRIDE, EffectiveUsageLimits, Effort, Engine, EngineDefaults, EntryKind, EntryRef, EntryStatus, ErrorClass, ErrorCode, ErrorPolicy, EscalatedResult, EscalationDecision, EscalationDecisionAbortedError, EscalationDigest, EscalationKind, EscalationLimits, EscalationOptions, EscalationReport, EscalationRequest, EventBus, type EvidenceRef, ExtensionAppendInput, ExtensionDispatchSpec, ExternalIdentityInput, ExternalRegistry, ExtractNecessityInput, FINALIZE_SYNTHESIS_INSTRUCTION, FINISH_SCHEMA, FINISH_TOOL_NAME, FailRunError, FailoverTarget, FailoverTrigger, FallbackField, FallbackTrigger, FileModelKnowledgeStore, FileModelKnowledgeStoreOptions, FileTranscriptStore, FinishInfo, FinishValidationInput, FinishValidationSpec, FinishValidationVerdict, FinishValidator, GET_CHILD_RESULT_SCHEMA, GET_CHILD_RESULT_TOOL_NAME, 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_CHILD_RESULT_PAGE_CHARS, MAX_DEPTH_CEILING, MatchResult, McpConfig, McpToolSource, MechanicalGateProfile, MechanicalGateVerdict, 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, 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, READ_CHILD_ARTIFACT_SCHEMA, READ_CHILD_ARTIFACT_TOOL_NAME, 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, SANDBOX_AGENT_OPT_KEYS, 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, hasMetaLookup, hashRunArgs, hashWorkflowBody, hashWorkflowSource, identityJcs, isEscalated, isSchemaPairSpec, isStandardSchemaSpec, isStrictCompatibleSchema, kMaxOf, knowledgeHash, ladderLengthOf, ladderRungChoice, lexShellCommand, liftRetainedParts, lineageWeightOf, makeOrchestratorWorkflow, maskSecrets, maskSecretsDeep, maskSecretsJson, matchArgvPattern, matchShellCommand, mcp, mergeUsageLimits, metaMatchesFilter, minMatchesValidator, 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, readRunMeta, readTerminationInit, registryKeyRing, remeasureQueue, replayDisposition, requiredFieldsValidator, requiredSectionsValidator, resolveModelInvocation, resolvePricing, resolveToolset, retryClassOf, retryDelayMs, 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, validateEntryShape, validateEscalationLimits, validateEscalationReport, validateRetryPolicy, validateSchemaSpec, validateTerminationLimits, validateUsageLimits, workflowScope, workflowSourceRef, wrapJournalStore, wrapTranscriptStore };
package/dist/index.js CHANGED
@@ -8920,6 +8920,21 @@ async function runAgent(options) {
8920
8920
  }));
8921
8921
  continue;
8922
8922
  }
8923
+ const finishArgs = validation.value;
8924
+ const hostVerdict = options.terminalTool.validate === void 0 ? void 0 : await options.terminalTool.validate({
8925
+ id: call.id,
8926
+ result: finishArgs.result ?? null
8927
+ });
8928
+ if (hostVerdict !== void 0 && !hostVerdict.ok) {
8929
+ events?.emit({
8930
+ type: "tool:end",
8931
+ toolName: gatedCall.name,
8932
+ outcome: "error",
8933
+ durationMs: now() - gateStartedAt
8934
+ });
8935
+ parts.push(errorPart(call, hostVerdict.feedback));
8936
+ continue;
8937
+ }
8923
8938
  events?.emit({
8924
8939
  type: "tool:end",
8925
8940
  toolName: gatedCall.name,
@@ -8935,7 +8950,7 @@ async function runAgent(options) {
8935
8950
  return {
8936
8951
  parts,
8937
8952
  limitHit: false,
8938
- finished: validation.value.result ?? null
8953
+ finished: finishArgs.result ?? null
8939
8954
  };
8940
8955
  }
8941
8956
  toolCallsUsed += 1;
@@ -10569,6 +10584,102 @@ var AdmissionController = class {
10569
10584
  }
10570
10585
  };
10571
10586
  //#endregion
10587
+ //#region src/orchestrator/finish-validators.ts
10588
+ /**
10589
+ * Deterministic host validation of the orchestrator finish result (the
10590
+ * v1.40.0 improvement plan's RV-204 slice). A validator is plain
10591
+ * synchronous host code judging the finish({ result }) argument; the
10592
+ * orchestrator runtime runs the configured set on every schema valid
10593
+ * finish call, returns the failure reasons to the model as the call's
10594
+ * error tool result (a bounded repair turn), and fails the run with a
10595
+ * typed error when the repair bound is exhausted. Verdicts journal as
10596
+ * decision entries, so a resume rolls the SAME verdicts forward without
10597
+ * re-running validator code.
10598
+ */
10599
+ const ok = { ok: true };
10600
+ function requireNonEmptyStrings(values, what) {
10601
+ if (!Array.isArray(values) || values.length === 0) throw new ConfigError(`${what} must be a non empty array of strings`);
10602
+ for (const value of values) if (typeof value !== "string" || value.length === 0) throw new ConfigError(`${what} must contain only non empty strings`);
10603
+ return values;
10604
+ }
10605
+ /**
10606
+ * Requires every named section to appear LITERALLY in the result text
10607
+ * (a heading like 'FINDINGS' or any marker the goal demands). Default
10608
+ * name 'required-sections'; pass `name` to run several instances.
10609
+ */
10610
+ function requiredSectionsValidator(options) {
10611
+ const sections = requireNonEmptyStrings(options.sections, "requiredSectionsValidator sections");
10612
+ return {
10613
+ name: options.name ?? "required-sections",
10614
+ validate: (input) => {
10615
+ const missing = sections.filter((section) => !input.text.includes(section));
10616
+ return missing.length === 0 ? ok : {
10617
+ ok: false,
10618
+ reasons: missing.map((section) => `required section '${section}' is missing`)
10619
+ };
10620
+ }
10621
+ };
10622
+ }
10623
+ /**
10624
+ * Requires the result to be a JSON object carrying every named field
10625
+ * with a substantial value: present, not null, and not an empty or
10626
+ * whitespace only string (empty arrays, zero, and false COUNT as
10627
+ * present; emptiness rules beyond strings belong to a custom
10628
+ * validator). Default name 'required-fields'.
10629
+ */
10630
+ function requiredFieldsValidator(options) {
10631
+ const fields = requireNonEmptyStrings(options.fields, "requiredFieldsValidator fields");
10632
+ return {
10633
+ name: options.name ?? "required-fields",
10634
+ validate: (input) => {
10635
+ const result = input.result;
10636
+ if (typeof result !== "object" || result === null || Array.isArray(result)) return {
10637
+ ok: false,
10638
+ reasons: ["the finish result is not a JSON object"]
10639
+ };
10640
+ const record = result;
10641
+ const reasons = [];
10642
+ for (const field of fields) {
10643
+ const value = record[field];
10644
+ if (value === void 0 || value === null) reasons.push(`required field '${field}' is missing`);
10645
+ else if (typeof value === "string" && value.trim().length === 0) reasons.push(`required field '${field}' is empty`);
10646
+ }
10647
+ return reasons.length === 0 ? ok : {
10648
+ ok: false,
10649
+ reasons
10650
+ };
10651
+ }
10652
+ };
10653
+ }
10654
+ /**
10655
+ * Requires at least `min` matches of `pattern` in the result text (the
10656
+ * plan's citation and source count checks: a file:line pattern, a URL
10657
+ * pattern). The pattern compiles at construction (invalid patterns are a
10658
+ * ConfigError before any run exists) and matches globally; `min` is a
10659
+ * positive integer. Default name 'min-matches'; pass `name` to run
10660
+ * several instances, because names must be unique per orchestrate call.
10661
+ */
10662
+ function minMatchesValidator(options) {
10663
+ const flags = options.flags ?? "";
10664
+ const globalFlags = flags.includes("g") ? flags : `${flags}g`;
10665
+ try {
10666
+ new RegExp(options.pattern, globalFlags);
10667
+ } catch (thrown) {
10668
+ throw new ConfigError(`minMatchesValidator pattern does not compile: ${thrown instanceof Error ? thrown.message : String(thrown)}`);
10669
+ }
10670
+ if (!Number.isInteger(options.min) || options.min < 1) throw new ConfigError(`minMatchesValidator min must be a positive integer; got ${String(options.min)}`);
10671
+ return {
10672
+ name: options.name ?? "min-matches",
10673
+ validate: (input) => {
10674
+ const found = input.text.match(new RegExp(options.pattern, globalFlags))?.length ?? 0;
10675
+ return found >= options.min ? ok : {
10676
+ ok: false,
10677
+ reasons: [`expected at least ${String(options.min)} matches of /${options.pattern}/${flags}; found ${String(found)}`]
10678
+ };
10679
+ }
10680
+ };
10681
+ }
10682
+ //#endregion
10572
10683
  //#region src/orchestrator/handles.ts
10573
10684
  /**
10574
10685
  * The committed WakeDigest render budget (Appendix A: 400
@@ -10929,7 +11040,9 @@ const kOnRunning = Symbol("rulvar.onRunning");
10929
11040
  /**
10930
11041
  * Internal AgentOpts channel (M6-T07): names the terminal tool whose
10931
11042
  * accepted call ends the loop with status ok (the orchestrator finish
10932
- * tool). Never part of the public AgentOpts surface.
11043
+ * tool), plus the optional host validation hook over the accepted call
11044
+ * (the RV-204 finish validators). Never part of the public AgentOpts
11045
+ * surface.
10933
11046
  */
10934
11047
  const kTerminalTool = Symbol("rulvar.terminalTool");
10935
11048
  /**
@@ -12549,6 +12662,8 @@ async function executeWorkflow(internals, wf, args) {
12549
12662
  * cap, maxDepth, and the budget layers apply; no termination.init is
12550
12663
  * written; escalated children simply settle into their digests.
12551
12664
  */
12665
+ /** How many rejected finishes are repaired by default: the plan's repair once. */
12666
+ const DEFAULT_FINISH_MAX_REPAIRS = 1;
12552
12667
  const ORCHESTRATE_WORKFLOW_NAME = "rulvar-orchestrate";
12553
12668
  /**
12554
12669
  * One page of a string, for the child result evidence tools: maxChars is
@@ -12593,6 +12708,19 @@ function validateOrchestrateOptions(opts) {
12593
12708
  if (policy !== "all-ok" && minSuccessful === void 0) throw new ConfigError(`orchestrate acceptance.childPolicy must be 'all-ok' or { minSuccessful: N }; got ${JSON.stringify(policy)}`);
12594
12709
  if (policy !== "all-ok") requirePositiveInteger(minSuccessful, "orchestrate acceptance.childPolicy.minSuccessful");
12595
12710
  }
12711
+ if (opts.finishValidation !== void 0) {
12712
+ const fv = opts.finishValidation;
12713
+ if (!Array.isArray(fv.validators) || fv.validators.length === 0) throw new ConfigError("orchestrate finishValidation.validators must be a non empty array of validators");
12714
+ const seen = /* @__PURE__ */ new Set();
12715
+ for (const candidate of fv.validators) {
12716
+ const validator = candidate;
12717
+ if (typeof validator.name !== "string" || validator.name.length === 0) throw new ConfigError("every orchestrate finish validator must carry a non empty string name");
12718
+ if (typeof validator.validate !== "function") throw new ConfigError(`orchestrate finish validator '${validator.name}' has no validate function`);
12719
+ if (seen.has(validator.name)) throw new ConfigError(`orchestrate finishValidation.validators names must be unique; '${validator.name}' repeats (pass name to the factory to run several instances)`);
12720
+ seen.add(validator.name);
12721
+ }
12722
+ if (fv.maxRepairs !== void 0) requireNonNegativeInteger(fv.maxRepairs, "orchestrate finishValidation.maxRepairs");
12723
+ }
12596
12724
  const spec = opts.budget;
12597
12725
  if (spec === void 0) return;
12598
12726
  if (spec.capUsd !== void 0) requireNonNegativeNumber(spec.capUsd, "orchestrate budget.capUsd");
@@ -12614,6 +12742,18 @@ function orchestratorPrompt(goal, maxSpawns, extensionLines) {
12614
12742
  ].join("\n");
12615
12743
  }
12616
12744
  /**
12745
+ * The finish validation contract rides the PROMPT, never the toolset:
12746
+ * the finish tool definition stays byte identical in every
12747
+ * configuration, so the orchestrator toolset hash never moves (stricter
12748
+ * than the evidence tools opt in, which changes it by design).
12749
+ */
12750
+ function finishValidationPromptLines(spec) {
12751
+ if (spec === void 0) return [];
12752
+ const names = spec.validators.map((validator) => validator.name).join(", ");
12753
+ const repairs = spec.maxRepairs ?? 1;
12754
+ return [`The host validates every finish({ result }) with deterministic validators: ${names}.`, "A rejected finish returns the failure reasons as the tool error result; repair the result and call finish again. " + (repairs === 0 ? "No repair attempt is granted: the first rejected finish fails the run." : repairs === 1 ? "At most one repair attempt is granted before the run fails." : `At most ${String(repairs)} repair attempts are granted before the run fails.`)];
12755
+ }
12756
+ /**
12617
12757
  * Resolves per-spawn dispatch options against the engine registries
12618
12758
  * (registered SchemaSpec and tool profile names; M7-T05). An
12619
12759
  * unknown ref is a typed ConfigError, surfaced as a tool error to the
@@ -13448,10 +13588,109 @@ function makeOrchestratorWorkflow(goal, opts) {
13448
13588
  }
13449
13589
  });
13450
13590
  }
13591
+ const tools = [...buildOrchestratorTools(orchestratorRuntime, fullCardText, { childResultTools: opts?.exposeChildResultTools === true }), ...extension?.tools(io) ?? []];
13592
+ /**
13593
+ * The RV-204 finish validation hook, installed on the terminal tool
13594
+ * channel only when validators are configured (zero configuration =
13595
+ * zero new journal entries and byte identical loop behavior; the
13596
+ * toolset never changes either way). Verdicts are decision entries
13597
+ * keyed by the finish call id: a replayed call returns the JOURNALED
13598
+ * verdict without re-running validator code, so the accepted result,
13599
+ * every repair exchange, and the final rejection reproduce on resume
13600
+ * even when the live validators drifted (the acceptance precedent).
13601
+ * The final rejection journals verdict 'rejected', arms the typed
13602
+ * FailRunError, and aborts the loop; the settle path throws it
13603
+ * BEFORE the acceptance settle (and the boot scan covers the crash
13604
+ * window between the entry and the run terminal), so acceptance
13605
+ * never judges a finish the validators rejected. A THROWING
13606
+ * validator is a host defect: the run fails as ConfigError, nothing
13607
+ * journals, and no repair turn is granted, so a fixed validator
13608
+ * re-runs live on the next resume.
13609
+ */
13610
+ const validationSpec = opts?.finishValidation;
13611
+ const validationAbort = new AbortController();
13612
+ let validationTermination;
13613
+ const finishValidationError = (decision) => new FailRunError(`the orchestrator finish failed host validation with all ${String(decision.maxRepairs)} repair attempts spent: ` + decision.failed.map((f) => `validator '${f.name}' rejected: ${f.reasons.join("; ")}`).join("; "), { data: {
13614
+ source: "orchestrator_finish_validation",
13615
+ callId: decision.callId,
13616
+ failed: decision.failed,
13617
+ repairsUsed: decision.repairsUsed,
13618
+ maxRepairs: decision.maxRepairs
13619
+ } });
13620
+ const validationDecisions = () => internals.replayer.snapshot().filter((entry) => entry.kind === "decision" && entry.scope === callingState.scope && entry.value?.decisionType === "orchestrator_finish_validation").map((entry) => entry.value);
13621
+ const validateFinish = async (call) => {
13622
+ if (validationSpec === void 0) return { ok: true };
13623
+ const maxRepairs = validationSpec.maxRepairs ?? 1;
13624
+ const known = validationDecisions();
13625
+ let decision = known.find((candidate) => candidate.callId === call.id);
13626
+ if (decision === void 0) {
13627
+ const result = call.result ?? null;
13628
+ const input = {
13629
+ result,
13630
+ text: typeof result === "string" ? result : JSON.stringify(result)
13631
+ };
13632
+ const failed = [];
13633
+ for (const validator of validationSpec.validators) {
13634
+ let verdict;
13635
+ try {
13636
+ verdict = validator.validate(input);
13637
+ } catch (thrown) {
13638
+ validationTermination = new ConfigError(`finish validator '${validator.name}' threw instead of returning a verdict: ` + (thrown instanceof Error ? thrown.message : String(thrown)));
13639
+ validationAbort.abort("rulvar:finish-validation");
13640
+ return {
13641
+ ok: false,
13642
+ feedback: { error: `finish validator '${validator.name}' is defective; the run fails` }
13643
+ };
13644
+ }
13645
+ if (!verdict.ok) failed.push({
13646
+ name: validator.name,
13647
+ reasons: verdict.reasons
13648
+ });
13649
+ }
13650
+ const repairsUsed = known.filter((candidate) => candidate.verdict !== "accepted").length;
13651
+ decision = {
13652
+ decisionType: "orchestrator_finish_validation",
13653
+ callId: call.id,
13654
+ verdict: failed.length === 0 ? "accepted" : repairsUsed < maxRepairs ? "repair" : "rejected",
13655
+ failed,
13656
+ repairsUsed,
13657
+ maxRepairs
13658
+ };
13659
+ await internals.replayer.appendSinglePhase({
13660
+ scope: callingState.scope,
13661
+ key: `finish-validation:${call.id}`,
13662
+ kind: "decision",
13663
+ status: "ok",
13664
+ spanId: internals.spans.mint(callingState.spanId),
13665
+ site: "orchestrator-finish-validation",
13666
+ value: decision
13667
+ });
13668
+ }
13669
+ if (decision.verdict === "accepted") return { ok: true };
13670
+ if (decision.verdict === "rejected") {
13671
+ validationTermination = finishValidationError(decision);
13672
+ validationAbort.abort("rulvar:finish-validation");
13673
+ return {
13674
+ ok: false,
13675
+ feedback: {
13676
+ error: "the finish result failed host validation and the repair bound is exhausted; the run fails",
13677
+ failed: decision.failed
13678
+ }
13679
+ };
13680
+ }
13681
+ return {
13682
+ ok: false,
13683
+ feedback: {
13684
+ error: "the finish result failed host validation; repair the result and call finish again",
13685
+ failed: decision.failed,
13686
+ repairsRemaining: decision.maxRepairs - decision.repairsUsed - 1
13687
+ }
13688
+ };
13689
+ };
13451
13690
  const agentOpts = {
13452
13691
  role: "orchestrate",
13453
13692
  result: "full",
13454
- tools: [...buildOrchestratorTools(orchestratorRuntime, fullCardText, { childResultTools: opts?.exposeChildResultTools === true }), ...extension?.tools(io) ?? []],
13693
+ tools,
13455
13694
  ...capState === void 0 ? {} : { estCost: capState.effectiveCapUsd - (orchestratorAccount === void 0 ? 0 : internals.budget.accountView(orchestratorAccount)?.finalizeReserveUsd ?? 0) },
13456
13695
  ...opts?.model === void 0 ? {} : { model: opts.model },
13457
13696
  ...opts?.limits === void 0 ? {} : { limits: opts.limits },
@@ -13460,7 +13699,10 @@ function makeOrchestratorWorkflow(goal, opts) {
13460
13699
  orchSeq = seq;
13461
13700
  recover().then(releaseRecovery, releaseRecovery);
13462
13701
  },
13463
- [kTerminalTool]: { name: FINISH_TOOL_NAME },
13702
+ [kTerminalTool]: {
13703
+ name: FINISH_TOOL_NAME,
13704
+ ...validationSpec === void 0 ? {} : { validate: validateFinish }
13705
+ },
13464
13706
  ...(() => {
13465
13707
  const priorCancelledRoot = internals.replayer.snapshot().filter((entry) => entry.kind === "agent" && entry.scope === callingState.scope && entry.status === "cancelled" && entry.checkpointRef !== void 0).at(-1);
13466
13708
  return priorCancelledRoot?.checkpointRef === void 0 ? {} : { [kBootCheckpoint]: priorCancelledRoot.checkpointRef };
@@ -13468,7 +13710,8 @@ function makeOrchestratorWorkflow(goal, opts) {
13468
13710
  };
13469
13711
  const orchestratorState = { ...callingState };
13470
13712
  if (orchestratorAccount !== void 0) orchestratorState.budgetScope = orchestratorAccount;
13471
- orchestratorState.signal = callingState.signal === void 0 ? forcedFinishController.signal : AbortSignal.any([callingState.signal, forcedFinishController.signal]);
13713
+ const loopBreakSignal = validationSpec === void 0 ? forcedFinishController.signal : AbortSignal.any([forcedFinishController.signal, validationAbort.signal]);
13714
+ orchestratorState.signal = callingState.signal === void 0 ? loopBreakSignal : AbortSignal.any([callingState.signal, loopBreakSignal]);
13472
13715
  /**
13473
13716
  * The reserved final wake: a FRESH agent entry on
13474
13717
  * the restricted single-tool toolset (a different toolsetHash), a
@@ -13556,10 +13799,16 @@ function makeOrchestratorWorkflow(goal, opts) {
13556
13799
  const bootTermination = extensionTermination;
13557
13800
  if (bootTermination !== void 0) throw bootTermination;
13558
13801
  if (capDecisionRef !== void 0) return await settleCapOutcome();
13559
- const result = await runtime.runInScope(orchestratorState, () => ctx.agent(orchestratorPrompt(goal, opts?.maxSpawns, extension?.promptLines?.()), agentOpts));
13802
+ if (validationSpec !== void 0) {
13803
+ const priorRejection = validationDecisions().find((decision) => decision.verdict === "rejected");
13804
+ if (priorRejection !== void 0) throw finishValidationError(priorRejection);
13805
+ }
13806
+ const promptLines = [...extension?.promptLines?.() ?? [], ...finishValidationPromptLines(validationSpec)];
13807
+ const result = await runtime.runInScope(orchestratorState, () => ctx.agent(orchestratorPrompt(goal, opts?.maxSpawns, promptLines.length === 0 ? void 0 : promptLines), agentOpts));
13560
13808
  const liveTermination = extensionTermination;
13561
13809
  if (liveTermination !== void 0) throw liveTermination;
13562
13810
  if (capDecisionRef !== void 0) return await settleCapOutcome();
13811
+ if (validationTermination !== void 0) throw validationTermination;
13563
13812
  if (orchestratorAccount !== void 0) internals.cost.orchestrator.spentUsd = internals.budget.accountView(orchestratorAccount)?.spentUsd ?? 0;
13564
13813
  if (result.status !== "ok") throw new ConfigError(`the orchestrator agent terminated with status '${result.status}'` + (result.errorMessage === void 0 ? "" : `: ${result.errorMessage}`));
13565
13814
  if (opts?.acceptance === void 0) return result.output;
@@ -14782,4 +15031,4 @@ function createSandboxBridge(ctx, options) {
14782
15031
  };
14783
15032
  }
14784
15033
  //#endregion
14785
- 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_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, 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, 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_CHILD_RESULT_PAGE_CHARS, MAX_DEPTH_CEILING, ModelRetry, NoProgressDetector, NonSerializableValueError, ORCHESTRATE_WORKFLOW_NAME, OrchestratorCapConfigError, PARALLEL_AGENTS_SCHEMA, ParallelSiteCounter, PlanInvariantError, READ_CHILD_ARTIFACT_SCHEMA, READ_CHILD_ARTIFACT_TOOL_NAME, ROLE_EFFORT_DEFAULTS, ROOT_ACCOUNT, ROOT_SCOPE, RUN_PROFILES, 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, 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, hasMetaLookup, hashRunArgs, hashWorkflowBody, hashWorkflowSource, identityJcs, isEscalated, isSchemaPairSpec, isStandardSchemaSpec, isStrictCompatibleSchema, kMaxOf, knowledgeHash, ladderLengthOf, ladderRungChoice, lexShellCommand, liftRetainedParts, lineageWeightOf, makeOrchestratorWorkflow, maskSecrets, maskSecretsDeep, maskSecretsJson, matchArgvPattern, matchShellCommand, mcp, mergeUsageLimits, metaMatchesFilter, 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, readRunMeta, readTerminationInit, registryKeyRing, remeasureQueue, replayDisposition, resolveModelInvocation, resolvePricing, resolveToolset, retryClassOf, retryDelayMs, 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, validateEntryShape, validateEscalationLimits, validateEscalationReport, validateRetryPolicy, validateSchemaSpec, validateTerminationLimits, validateUsageLimits, workflowScope, workflowSourceRef, wrapJournalStore, wrapTranscriptStore };
15034
+ 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_COMPACTION_THRESHOLD, DEFAULT_ESCALATION_LIMITS, 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, DedupIndex, 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, 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_CHILD_RESULT_PAGE_CHARS, MAX_DEPTH_CEILING, ModelRetry, NoProgressDetector, NonSerializableValueError, ORCHESTRATE_WORKFLOW_NAME, OrchestratorCapConfigError, PARALLEL_AGENTS_SCHEMA, ParallelSiteCounter, PlanInvariantError, READ_CHILD_ARTIFACT_SCHEMA, READ_CHILD_ARTIFACT_TOOL_NAME, ROLE_EFFORT_DEFAULTS, ROOT_ACCOUNT, ROOT_SCOPE, RUN_PROFILES, 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, 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, hasMetaLookup, hashRunArgs, hashWorkflowBody, hashWorkflowSource, identityJcs, isEscalated, isSchemaPairSpec, isStandardSchemaSpec, isStrictCompatibleSchema, kMaxOf, knowledgeHash, ladderLengthOf, ladderRungChoice, lexShellCommand, liftRetainedParts, lineageWeightOf, makeOrchestratorWorkflow, maskSecrets, maskSecretsDeep, maskSecretsJson, matchArgvPattern, matchShellCommand, mcp, mergeUsageLimits, metaMatchesFilter, minMatchesValidator, 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, readRunMeta, readTerminationInit, registryKeyRing, remeasureQueue, replayDisposition, requiredFieldsValidator, requiredSectionsValidator, resolveModelInvocation, resolvePricing, resolveToolset, retryClassOf, retryDelayMs, 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, validateEntryShape, validateEscalationLimits, validateEscalationReport, 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.42.0",
3
+ "version": "1.43.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",