{"version":3,"file":"evaluator.d.ts","sourceRoot":"","sources":["../../../src/core/governance/evaluator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAElB,yBAAyB,EACzB,gBAAgB,EAEhB,MAAM,YAAY,CAAC;AAoBpB,eAAO,MAAM,yBAAyB,EAAE,gBAQtC,CAAC;AAIH,wBAAgB,eAAe,CAAC,MAAM,EAAE,gBAAgB,GAAG,gBAAgB,CAS1E;AAqED,iFAAiF;AACjF,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,iBAAiB,EAAE,MAAM,EAAE,gBAAgB,GAAG,kBAAkB,CAmEvG;AACD,wBAAgB,sBAAsB,CACrC,MAAM,EAAE,gBAAgB,EACxB,SAAS,CAAC,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC7C,yBAAyB,CAyB3B;AACD,wBAAgB,uBAAuB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,gBAAgB,CA4B9F","sourcesContent":["import type {\n\tGovernanceBudget,\n\tGovernanceContext,\n\tGovernanceDecision,\n\tGovernanceModelMode,\n\tGovernanceModelResolution,\n\tGovernancePolicy,\n\tGovernanceStatus,\n} from \"./types.js\";\n\nconst CAP_FIELDS: readonly (keyof GovernanceBudget)[] = [\n\t\"maxTurns\",\n\t\"maxContextTokens\",\n\t\"maxGeneratedTokens\",\n\t\"maxToolCalls\",\n\t\"maxRetries\",\n\t\"maxWallClockMs\",\n\t\"maxInferenceRequests\",\n\t\"maxChildren\",\n\t\"maxLogicalAgents\",\n\t\"maxTotalRetries\",\n\t\"maxReplans\",\n\t\"maxFanOut\",\n\t\"maxDepth\",\n\t\"maxReadyChildren\",\n\t\"maxCloudSpendUsd\",\n\t\"maxModelEscalations\",\n];\nexport const DEFAULT_GOVERNANCE_POLICY: GovernancePolicy = Object.freeze({\n\tschemaVersion: 1,\n\tcloudAllowed: true,\n\tmodelMode: \"local_default\",\n\tlocalModel: { provider: \"llamacpp-qwen38-bucephalus\", model: \"qwen3.8-27b\" },\n\tsoftWallClockRatio: 0.8,\n\tstagnation: { maxNoProgressTurns: 60, maxRepeatedFailure: 3, maxOutputContractRetries: 2 },\n\tretryCaps: { tool: 3, output_contract: 2, execution: 2, planner: 2, replan: 2, remote_execution: 2, provider: 2 },\n});\nfunction finite(value: number | undefined): number | undefined {\n\treturn value !== undefined && Number.isFinite(value) && value >= 0 ? value : undefined;\n}\nexport function effectiveBudget(policy: GovernancePolicy): GovernanceBudget {\n\tconst result: GovernanceBudget = {};\n\tfor (const field of CAP_FIELDS) {\n\t\tconst values = [policy.operator, policy.mission, policy.orchestration, policy.child]\n\t\t\t.map((layer) => finite(layer?.[field]))\n\t\t\t.filter((v): v is number => v !== undefined);\n\t\tif (values.length) result[field] = Math.min(...values);\n\t}\n\treturn result;\n}\nfunction usageFor(ctx: GovernanceContext, field: keyof GovernanceBudget): number | undefined {\n\tconst map: Record<string, number> = {\n\t\tmaxTurns: ctx.usage.turns,\n\t\tmaxContextTokens: ctx.usage.contextTokens,\n\t\tmaxGeneratedTokens: ctx.usage.generatedTokens,\n\t\tmaxToolCalls: ctx.usage.toolCalls,\n\t\tmaxRetries: ctx.usage.retries,\n\t\tmaxWallClockMs: ctx.usage.wallClockMs,\n\t\tmaxInferenceRequests: ctx.usage.inferenceRequests,\n\t\tmaxChildren: ctx.usage.children,\n\t\tmaxLogicalAgents: ctx.usage.logicalAgents,\n\t\tmaxTotalRetries: ctx.usage.totalRetries,\n\t\tmaxReplans: ctx.usage.replans,\n\t\tmaxFanOut: ctx.usage.fanOut,\n\t\tmaxDepth: ctx.usage.depth,\n\t\tmaxReadyChildren: ctx.usage.readyChildren,\n\t\tmaxCloudSpendUsd: ctx.cost.knownUsd,\n\t\tmaxModelEscalations: ctx.usage.modelEscalations,\n\t};\n\treturn map[field];\n}\nfunction statusFor(ctx: GovernanceContext, policy: GovernancePolicy): GovernanceStatus {\n\tconst budget = effectiveBudget(policy);\n\tfor (const field of CAP_FIELDS) {\n\t\tconst limit = budget[field];\n\t\tconst used = usageFor(ctx, field);\n\t\tif (limit !== undefined && used !== undefined && used >= limit) return \"LIMIT_REACHED\";\n\t}\n\tconst wall = budget.maxWallClockMs;\n\treturn wall !== undefined &&\n\t\tctx.wallClockNowMs - ctx.wallClockStartedAtMs >= wall * (policy.softWallClockRatio ?? 0.8)\n\t\t? \"NEAR_LIMIT\"\n\t\t: \"NORMAL\";\n}\nfunction evidence(ctx: GovernanceContext, code: string) {\n\treturn {\n\t\tcode,\n\t\tobserved: {\n\t\t\telapsedMs: ctx.wallClockNowMs - ctx.wallClockStartedAtMs,\n\t\t\tprogressAgeMs:\n\t\t\t\tctx.progress?.lastProgressAtMs === undefined\n\t\t\t\t\t? undefined\n\t\t\t\t\t: ctx.wallClockNowMs - ctx.progress.lastProgressAtMs,\n\t\t\tretryCount: ctx.usage.retries,\n\t\t\tprovider: ctx.provider,\n\t\t\tmodel: ctx.model,\n\t\t},\n\t};\n}\nfunction makeDecision(\n\tctx: GovernanceContext,\n\tstatus: GovernanceStatus,\n\taction: GovernanceDecision[\"action\"],\n\treason: string,\n\tto?: { provider: string; model: string },\n): GovernanceDecision {\n\treturn {\n\t\taction,\n\t\tstatus,\n\t\treason,\n\t\tevidence: [evidence(ctx, reason)],\n\t\tfrom: { provider: ctx.provider, model: ctx.model },\n\t\tto,\n\t\tpreserveIdentity: true,\n\t\tatMs: ctx.wallClockNowMs,\n\t};\n}\n\n/** Pure policy evaluation. It cannot launch, assign, acquire, or commit work. */\nexport function evaluateGovernance(ctx: GovernanceContext, policy: GovernancePolicy): GovernanceDecision {\n\tconst budget = effectiveBudget(policy);\n\tconst status = statusFor(ctx, policy);\n\tif (ctx.resourceWait) return makeDecision(ctx, status, \"PARK\", \"RESOURCE_WAIT\");\n\tif (ctx.dependencyBlocked) return makeDecision(ctx, status, \"PARK\", \"BLOCKED_DEPENDENCY\");\n\tif (ctx.outputContractMissing) {\n\t\tconst cap = policy.stagnation?.maxOutputContractRetries ?? policy.retryCaps?.output_contract ?? 0;\n\t\treturn ctx.retries.output_contract < cap\n\t\t\t? makeDecision(ctx, status, \"RETRY_OUTPUT_CONTRACT\", \"MISSING_RESULT_ENVELOPE\")\n\t\t\t: makeDecision(ctx, \"LIMIT_REACHED\", \"TERMINATE_CHILD\", \"OUTPUT_CONTRACT_RETRY_LIMIT\");\n\t}\n\tif (\n\t\tctx.requestedChildren !== undefined &&\n\t\tbudget.maxFanOut !== undefined &&\n\t\tctx.requestedChildren > budget.maxFanOut\n\t)\n\t\treturn makeDecision(ctx, \"LIMIT_REACHED\", \"REQUEST_REPLAN\", \"FANOUT_HARD_LIMIT\");\n\tif (budget.maxDepth !== undefined && (ctx.orchestrationDepth ?? ctx.usage.depth) > budget.maxDepth)\n\t\treturn makeDecision(ctx, \"LIMIT_REACHED\", \"DENY_NEW_CHILD\", \"ORCHESTRATION_DEPTH_HARD_LIMIT\");\n\tconst elapsed = ctx.wallClockNowMs - ctx.wallClockStartedAtMs;\n\tif (budget.maxWallClockMs !== undefined && elapsed >= budget.maxWallClockMs)\n\t\treturn makeDecision(ctx, \"LIMIT_REACHED\", \"TERMINATE_MISSION\", \"WALL_CLOCK_HARD_LIMIT\");\n\tif (ctx.isPaidInference && !policy.cloudAllowed)\n\t\treturn makeDecision(ctx, status, \"DENY_INFERENCE\", \"CLOUD_PROHIBITED\");\n\tif (ctx.isPaidInference && budget.maxCloudSpendUsd !== undefined && ctx.cost.unknownPaidEvents > 0)\n\t\treturn makeDecision(ctx, \"UNKNOWN\", \"DENY_INFERENCE\", \"UNKNOWN_CLOUD_COST\");\n\tif (ctx.isPaidInference && budget.maxCloudSpendUsd !== undefined && ctx.cost.knownUsd >= budget.maxCloudSpendUsd)\n\t\treturn makeDecision(ctx, \"LIMIT_REACHED\", \"DENY_INFERENCE\", \"CLOUD_COST_HARD_LIMIT\");\n\tconst stagnant =\n\t\tctx.progress?.state === \"STAGNATING\" ||\n\t\t(ctx.progress !== undefined &&\n\t\t\tctx.progress.noProgressTurns >= (policy.stagnation?.maxNoProgressTurns ?? Number.MAX_SAFE_INTEGER)) ||\n\t\t(ctx.progress !== undefined &&\n\t\t\tctx.progress.repeatedFailureCount >= (policy.stagnation?.maxRepeatedFailure ?? Number.MAX_SAFE_INTEGER));\n\tconst nearWall =\n\t\tbudget.maxWallClockMs !== undefined && elapsed >= budget.maxWallClockMs * (policy.softWallClockRatio ?? 0.8);\n\tif (\n\t\t(stagnant || nearWall) &&\n\t\tctx.provider === policy.localModel.provider &&\n\t\tctx.model === policy.localModel.model &&\n\t\tpolicy.cloudEscalation\n\t) {\n\t\tif (!policy.cloudAllowed) return makeDecision(ctx, status, \"REQUEST_REPLAN\", \"CLOUD_ESCALATION_BLOCKED\");\n\t\tif (budget.maxModelEscalations !== undefined && ctx.usage.modelEscalations >= budget.maxModelEscalations)\n\t\t\treturn makeDecision(ctx, \"LIMIT_REACHED\", \"TERMINATE_CHILD\", \"MODEL_ESCALATION_LIMIT\");\n\t\treturn makeDecision(\n\t\t\tctx,\n\t\t\t\"NEAR_LIMIT\",\n\t\t\t\"ESCALATE_MODEL\",\n\t\t\tstagnant ? \"STAGNATION\" : \"WALL_CLOCK_SOFT_LIMIT\",\n\t\t\tpolicy.cloudEscalation,\n\t\t);\n\t}\n\tfor (const field of CAP_FIELDS) {\n\t\tconst limit = budget[field];\n\t\tconst used = usageFor(ctx, field);\n\t\tif (limit !== undefined && used !== undefined && used >= limit)\n\t\t\treturn makeDecision(\n\t\t\t\tctx,\n\t\t\t\t\"LIMIT_REACHED\",\n\t\t\t\tfield === \"maxChildren\" || field === \"maxFanOut\" || field === \"maxDepth\"\n\t\t\t\t\t? \"DENY_NEW_CHILD\"\n\t\t\t\t\t: \"TERMINATE_CHILD\",\n\t\t\t\t`${field.toUpperCase()}_HARD_LIMIT`,\n\t\t\t);\n\t}\n\treturn makeDecision(ctx, status, \"CONTINUE\", status === \"NEAR_LIMIT\" ? \"SOFT_LIMIT_APPROACHING\" : \"WITHIN_POLICY\");\n}\nexport function resolveGovernanceModel(\n\tpolicy: GovernancePolicy,\n\trequested?: { provider: string; model: string },\n): GovernanceModelResolution {\n\tif (policy.modelMode === \"fixed\")\n\t\treturn {\n\t\t\tmode: \"fixed\",\n\t\t\tselected: policy.fixedModel ?? policy.localModel,\n\t\t\tfallbackChain: [],\n\t\t\treason: \"FIXED_POLICY\",\n\t\t};\n\tif (policy.modelMode === \"cloud_prohibited\")\n\t\treturn { mode: \"cloud_prohibited\", selected: policy.localModel, fallbackChain: [], reason: \"LOCAL_ONLY\" };\n\tif (!policy.cloudAllowed)\n\t\treturn { mode: \"cloud_prohibited\", selected: policy.localModel, fallbackChain: [], reason: \"LOCAL_ONLY\" };\n\tif (policy.modelMode === \"cloud_preferred\" && policy.cloudEscalation)\n\t\treturn {\n\t\t\tmode: \"cloud_preferred\",\n\t\t\tselected: policy.cloudEscalation,\n\t\t\tfallbackChain: [policy.localModel],\n\t\t\treason: \"CLOUD_PREFERRED\",\n\t\t};\n\treturn {\n\t\tmode: policy.modelMode,\n\t\tselected: requested ?? policy.localModel,\n\t\tfallbackChain: policy.fallbackChain ?? (policy.cloudEscalation ? [policy.cloudEscalation] : []),\n\t\treason: requested ? \"REQUESTED_WITHIN_DEFAULT_POLICY\" : \"LOCAL_DEFAULT\",\n\t};\n}\nexport function governancePolicyFromEnv(env: NodeJS.ProcessEnv = process.env): GovernancePolicy {\n\tconst parse = (key: string): number | undefined => {\n\t\tconst value = env[key];\n\t\tif (value === undefined || value.trim() === \"\") return undefined;\n\t\tconst n = Number(value);\n\t\treturn Number.isFinite(n) && n >= 0 ? n : undefined;\n\t};\n\tconst cloudProvider = env.JENSEN_GOVERNANCE_CLOUD_PROVIDER;\n\tconst cloudModel = env.JENSEN_GOVERNANCE_CLOUD_MODEL;\n\treturn {\n\t\t...DEFAULT_GOVERNANCE_POLICY,\n\t\tcloudAllowed: env.JENSEN_GOVERNANCE_CLOUD_ALLOWED !== \"0\",\n\t\tmodelMode:\n\t\t\t(env.JENSEN_GOVERNANCE_MODEL_MODE as GovernanceModelMode | undefined) ?? DEFAULT_GOVERNANCE_POLICY.modelMode,\n\t\tlocalModel: {\n\t\t\tprovider: env.JENSEN_GOVERNANCE_LOCAL_PROVIDER ?? DEFAULT_GOVERNANCE_POLICY.localModel.provider,\n\t\t\tmodel: env.JENSEN_GOVERNANCE_LOCAL_MODEL ?? DEFAULT_GOVERNANCE_POLICY.localModel.model,\n\t\t},\n\t\tcloudEscalation: cloudProvider && cloudModel ? { provider: cloudProvider, model: cloudModel } : undefined,\n\t\toperator: {\n\t\t\tmaxCloudSpendUsd: parse(\"JENSEN_GOVERNANCE_MAX_CLOUD_SPEND_USD\"),\n\t\t\tmaxWallClockMs: parse(\"JENSEN_GOVERNANCE_MAX_WALL_CLOCK_MS\"),\n\t\t\tmaxChildren: parse(\"JENSEN_GOVERNANCE_MAX_CHILDREN\"),\n\t\t\tmaxDepth: parse(\"JENSEN_GOVERNANCE_MAX_DEPTH\"),\n\t\t\tmaxRetries: parse(\"JENSEN_GOVERNANCE_MAX_RETRIES\"),\n\t\t\tmaxReplans: parse(\"JENSEN_GOVERNANCE_MAX_REPLANS\"),\n\t\t},\n\t};\n}\n"]}