{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../src/core/routing/engine.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Evidence-driven orchestration decision engine.\n *\n * Encapsulates the full decision flow:\n *   task & runtime context → feature extraction → candidate generation →\n *   hard policy filtering → evidence lookup → candidate scoring →\n *   uncertainty assessment → orchestration decision → outcome capture.\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport { applyHardPolicy, generateCandidates, type HardPolicyInput } from \"./candidates.js\";\nimport { extractFeatures, type TaskContext, taskFingerprint } from \"./features.js\";\nimport { type SelectionOptions, scoreCandidate, selectBest } from \"./scoring.js\";\nimport { appendEvent, readDecision, writeDecision } from \"./store.js\";\nimport type {\n\tCandidateEvidence,\n\tExecutionTopology,\n\tOrchestrationCandidate,\n\tOrchestrationCandidateScore,\n\tOrchestrationConfidence,\n\tOrchestrationDecision,\n} from \"./types.js\";\n\nexport interface RoutingPolicyContext {\n\tpolicyId: string;\n\tpolicyVersion: number;\n\t/** Deterministic baseline candidate preferences. */\n\tpreferences?: { candidateId: string; quality: number }[];\n\t/** Dominated candidate IDs the policy will not select. */\n\tdominatedCandidateIds?: string[];\n}\n\n/** Outcome capture for evaluation linkage. */\nexport interface DecisionOutcome {\n\tdecisionId: string;\n\tsuccess: boolean;\n\tcorrectnessRate?: number;\n\tsafetyRate?: number;\n\tmedianLatencyMs?: number;\n\tavgCostUsd?: number;\n\ttoolFailureRate?: number;\n\tflakyRate?: number;\n}\n\nexport interface EngineOptions {\n\trunId?: string;\n\tpolicyOverride?: RoutingPolicyContext;\n\thardPolicy?: Partial<HardPolicyInput>;\n\tselection?: Partial<SelectionOptions>;\n\toperatorOverride?: OrchestrationOperatorOverride;\n}\n\nexport interface OrchestrationOperatorOverride {\n\tauthorizedBy: string;\n\tcandidateId?: string;\n\treason?: string;\n}\n\n/** Context describing all configured candidate sources (canonical registries). */\nexport interface CandidateRegistryContext {\n\tproviderProfiles: string[];\n\tmodels: { provider: string; model: string }[];\n\ttopologies: ExecutionTopology[];\n\tskills: string[];\n\tsubagents: string[];\n\tretrievalPolicies: string[];\n\tbudgetClasses: string[];\n\tfallbackPolicies: string[];\n}\n\nconst DEFAULT_HARD_POLICY: HardPolicyInput = {\n\tworkspaceBoundary: true,\n\trequiredLocalOnly: false,\n\tproviderAllowlist: [],\n\tmodelAllowlist: [],\n\tmaxSubagents: 4,\n\tnetworkPolicy: \"allow_all\",\n\tallowLiveProviders: false,\n};\n\nconst DEFAULT_REGISTRY: CandidateRegistryContext = {\n\tproviderProfiles: [\"fixture\", \"local\"],\n\tmodels: [\n\t\t{ provider: \"fixture\", model: \"fixture/deterministic\" },\n\t\t{ provider: \"local\", model: \"local/readonly\" },\n\t],\n\ttopologies: [\"single_agent\", \"single_agent_with_reviewer\", \"cavecrew\", \"custom_skill\"],\n\tskills: [],\n\tsubagents: [\"reviewer\", \"investigator\", \"planner\", \"builder\"],\n\tretrievalPolicies: [\"none\", \"lexical\", \"symbolic\", \"semantic\", \"hybrid\", \"hybrid_reranked\"],\n\tbudgetClasses: [\"tiny\", \"small\", \"standard\", \"large\", \"high_assurance\", \"release\"],\n\tfallbackPolicies: [\"rigid\", \"validated_policy\", \"deterministic_baseline\", \"degraded\", \"blocked\"],\n};\n\nexport interface DecideInput {\n\ttask: string | TaskContext;\n\tregistry?: Partial<CandidateRegistryContext>;\n\thardPolicy?: Partial<HardPolicyInput>;\n\tselectionPolicy?: SelectionOptions[\"policy\"];\n\toperatorOverride?: OrchestrationOperatorOverride;\n\tevidence?: Record<string, CandidateEvidence>;\n\tpolicyContext?: RoutingPolicyContext;\n\trunId?: string;\n}\n\nexport interface DecideResult {\n\tdecision: OrchestrationDecision;\n\tselectedCandidate?: OrchestrationCandidate;\n\tevidenceById: Record<string, CandidateEvidence>;\n}\n\n/**\n * Execute the full decision flow for a task.\n * Returns the decision (durable) and the selected candidate (if any).\n */\nexport function decide(input: DecideInput): DecideResult {\n\tconst runId = input.runId ?? randomUUID();\n\tconst ctx: TaskContext = typeof input.task === \"string\" ? { task: input.task } : input.task;\n\tconst taskText = ctx.task ?? \"\";\n\n\t// 1. Feature extraction (deterministic).\n\tconst features = extractFeatures(ctx);\n\n\t// 2. Candidate generation from canonical registries.\n\tconst registry: CandidateRegistryContext = { ...DEFAULT_REGISTRY, ...input.registry };\n\tconst { candidates, warnings } = generateCandidates({\n\t\tproviderProfiles: registry.providerProfiles,\n\t\tmodels: registry.models,\n\t\ttopologies: registry.topologies,\n\t\tskills: registry.skills,\n\t\tsubagents: registry.subagents,\n\t\tretrievalPolicies: registry.retrievalPolicies,\n\t\tbudgetClasses: registry.budgetClasses,\n\t\tfallbackPolicies: registry.fallbackPolicies,\n\t\toperatorSelectionPolicy: input.selectionPolicy ?? \"balanced\",\n\t});\n\tvoid warnings;\n\n\t// 3. Hard policy filtering.\n\tconst hardPolicy: HardPolicyInput = { ...DEFAULT_HARD_POLICY, ...input.hardPolicy };\n\tconst { accepted, rejected } = applyHardPolicy(candidates, hardPolicy);\n\n\t// 4. Evidence lookup + scoring.\n\tconst evidenceStore = input.evidence ?? {};\n\tconst scored: OrchestrationCandidateScore[] = accepted.map((candidate) => {\n\t\tconst ev = evidenceStore[candidate.candidateId];\n\t\treturn scoreCandidate(candidate, ev, ev ? ev.sampleCount : 0);\n\t});\n\n\t// 5. Uncertainty assessment + multi-objective selection.\n\tconst selectionOptions: SelectionOptions = {\n\t\tpolicy: input.selectionPolicy ?? \"balanced\",\n\t};\n\tconst selection = selectBest(scored, selectionOptions);\n\tconst policyContext: RoutingPolicyContext = input.policyContext ?? {\n\t\tpolicyId: \"deterministic-baseline\",\n\t\tpolicyVersion: 1,\n\t};\n\n\t// 6. Apply policy preferences (only among accepted candidates).\n\tlet selected = selection.selected;\n\tif (policyContext.preferences && policyContext.preferences.length > 0 && selected) {\n\t\tconst prefId = policyContext.preferences[0]?.candidateId;\n\t\tconst prefCandidate = scored.find((s) => s.candidateId === prefId && !isDominated(policyContext, prefId));\n\t\tif (prefCandidate && selected.candidateId !== prefCandidate.candidateId) {\n\t\t\tselected = prefCandidate;\n\t\t}\n\t}\n\n\t// 7. Operator override (highest authority below safety policy).\n\tif (input.operatorOverride?.candidateId) {\n\t\tconst overrideCandidate = scored.find((s) => s.candidateId === input.operatorOverride?.candidateId);\n\t\tif (overrideCandidate) {\n\t\t\tselected = overrideCandidate;\n\t\t}\n\t}\n\n\tconst confidence = assessConfidence(scored, selected, input.selectionPolicy ?? \"balanced\");\n\n\tconst reasonCodes: string[] = [\n\t\t...selection.reasonCodes,\n\t\t...(selected ? [`selected:${selected.candidateId}`] : []),\n\t\t...(input.operatorOverride ? [\"operator_override\"] : []),\n\t\t...(hardPolicy.requiredLocalOnly ? [\"local_only_enforced\"] : []),\n\t];\n\n\tconst evidenceIds = (selected?.evidenceIds ?? []).concat(rejected.length > 0 ? [] : []);\n\n\tconst decision: OrchestrationDecision = {\n\t\tdecisionId: randomUUID(),\n\t\tpolicyId: policyContext.policyId,\n\t\tpolicyVersion: policyContext.policyVersion,\n\t\trunId,\n\t\ttaskFingerprint: taskFingerprint(taskText),\n\t\tfeatures,\n\t\tcandidates: scored,\n\t\trejections: rejected,\n\t\tselectedCandidateId: selected?.candidateId,\n\t\tselectedAt: new Date().toISOString(),\n\t\tconfidence,\n\t\treasonCodes,\n\t\tevidenceIds: [...new Set(evidenceIds)],\n\t\toperatorOverride: input.operatorOverride\n\t\t\t? {\n\t\t\t\t\toverrideId: randomUUID(),\n\t\t\t\t\tauthorizedBy: input.operatorOverride.authorizedBy,\n\t\t\t\t\treason: input.operatorOverride.reason,\n\t\t\t\t\tcandidateId: input.operatorOverride.candidateId,\n\t\t\t\t\trecordedAt: new Date().toISOString(),\n\t\t\t\t}\n\t\t\t: undefined,\n\t};\n\n\twriteDecision(decision);\n\tappendEvent({\n\t\ttype: \"ORCHESTRATION_DECISION_SELECTED\",\n\t\trunId,\n\t\tdecisionId: decision.decisionId,\n\t\tpolicyId: decision.policyId,\n\t\tpolicyVersion: decision.policyVersion,\n\t\tevidenceIds: decision.evidenceIds,\n\t});\n\n\tconst selectedFull = selected ? candidates.find((c) => c.candidateId === selected.candidateId) : undefined;\n\n\treturn { decision, selectedCandidate: selectedFull, evidenceById: evidenceStore };\n}\n\nfunction isDominated(policy: RoutingPolicyContext, candidateId: string): boolean {\n\treturn Boolean(policy.dominatedCandidateIds?.includes(candidateId));\n}\n\n/** Assess decision confidence deterministically. */\nexport function assessConfidence(\n\t_scored: OrchestrationCandidateScore[],\n\tselected: OrchestrationCandidateScore | undefined,\n\tpolicy: SelectionOptions[\"policy\"],\n): OrchestrationConfidence {\n\tif (!selected) return \"insufficient_evidence\";\n\tif (selected.sampleCount === 0 && selected.reasonCodes.includes(\"no_evidence\")) {\n\t\treturn \"insufficient_evidence\";\n\t}\n\tconst hasEvidence =\n\t\t(selected.correctnessScore ??\n\t\t\tselected.safetyScore ??\n\t\t\tselected.reliabilityScore ??\n\t\t\tselected.costScore ??\n\t\t\tselected.latencyScore) !== undefined;\n\tif (!hasEvidence) return \"insufficient_evidence\";\n\t// For local_only or high_assurance, require stronger evidence.\n\tif (policy === \"local_only\" || policy === \"high_assurance\") {\n\t\tif (selected.sampleCount < 10) return \"low\";\n\t}\n\tif (selected.sampleCount < 5) return \"low\";\n\tif (selected.uncertainty > 0.5) return \"low\";\n\treturn \"medium\";\n}\n\nexport { buildCandidateId } from \"./baseline.js\";\nexport function replayDecision(decisionId: string): OrchestrationDecision | undefined {\n\treturn readDecision(decisionId);\n}\n"]}