open-multi-agent-kit 0.99.0 → 1.2.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/CHANGELOG.md +30 -1
- package/README.md +3 -3
- package/dist/bun/cli.d.ts.map +1 -1
- package/dist/bun/cli.js +1 -0
- package/dist/bun/cli.js.map +1 -1
- package/dist/bun/register-bundled-coding-agent.d.ts +10 -0
- package/dist/bun/register-bundled-coding-agent.d.ts.map +1 -0
- package/dist/bun/register-bundled-coding-agent.js +12 -0
- package/dist/bun/register-bundled-coding-agent.js.map +1 -0
- package/dist/cli/args.d.ts +1 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +1 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +2 -1
- package/dist/cli/help.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +14 -2
- package/dist/cli.js.map +1 -1
- package/dist/commands/neo-cli.d.ts +9 -0
- package/dist/commands/neo-cli.d.ts.map +1 -0
- package/dist/commands/neo-cli.js +61 -0
- package/dist/commands/neo-cli.js.map +1 -0
- package/dist/coordination/awareness.d.ts +32 -0
- package/dist/coordination/awareness.d.ts.map +1 -0
- package/dist/coordination/awareness.js +55 -0
- package/dist/coordination/awareness.js.map +1 -0
- package/dist/coordination/broker.d.ts +79 -0
- package/dist/coordination/broker.d.ts.map +1 -0
- package/dist/coordination/broker.js +195 -0
- package/dist/coordination/broker.js.map +1 -0
- package/dist/coordination/index.d.ts +16 -0
- package/dist/coordination/index.d.ts.map +1 -0
- package/dist/coordination/index.js +16 -0
- package/dist/coordination/index.js.map +1 -0
- package/dist/coordination/integration.d.ts +59 -0
- package/dist/coordination/integration.d.ts.map +1 -0
- package/dist/coordination/integration.js +126 -0
- package/dist/coordination/integration.js.map +1 -0
- package/dist/coordination/operation.d.ts +106 -0
- package/dist/coordination/operation.d.ts.map +1 -0
- package/dist/coordination/operation.js +179 -0
- package/dist/coordination/operation.js.map +1 -0
- package/dist/coordination/resource.d.ts +33 -0
- package/dist/coordination/resource.d.ts.map +1 -0
- package/dist/coordination/resource.js +89 -0
- package/dist/coordination/resource.js.map +1 -0
- package/dist/coordination/session.d.ts +74 -0
- package/dist/coordination/session.d.ts.map +1 -0
- package/dist/coordination/session.js +143 -0
- package/dist/coordination/session.js.map +1 -0
- package/dist/coordination/types.d.ts +68 -0
- package/dist/coordination/types.d.ts.map +1 -0
- package/dist/coordination/types.js +26 -0
- package/dist/coordination/types.js.map +1 -0
- package/dist/core/agent-session.d.ts +29 -2
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +135 -37
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/bundled-skills.d.ts +4 -0
- package/dist/core/bundled-skills.d.ts.map +1 -0
- package/dist/core/bundled-skills.js +32 -0
- package/dist/core/bundled-skills.js.map +1 -0
- package/dist/core/cli-diagnostics.d.ts +6 -0
- package/dist/core/cli-diagnostics.d.ts.map +1 -0
- package/dist/core/cli-diagnostics.js +20 -0
- package/dist/core/cli-diagnostics.js.map +1 -0
- package/dist/core/compaction/control-state.d.ts +41 -0
- package/dist/core/compaction/control-state.d.ts.map +1 -0
- package/dist/core/compaction/control-state.js +85 -0
- package/dist/core/compaction/control-state.js.map +1 -0
- package/dist/core/compaction/fallback.d.ts +60 -0
- package/dist/core/compaction/fallback.d.ts.map +1 -0
- package/dist/core/compaction/fallback.js +117 -0
- package/dist/core/compaction/fallback.js.map +1 -0
- package/dist/core/compaction/index.d.ts +2 -0
- package/dist/core/compaction/index.d.ts.map +1 -1
- package/dist/core/compaction/index.js +2 -0
- package/dist/core/compaction/index.js.map +1 -1
- package/dist/core/context-budget-headroom-candidates.d.ts +16 -1
- package/dist/core/context-budget-headroom-candidates.d.ts.map +1 -1
- package/dist/core/context-budget-headroom-candidates.js +31 -13
- package/dist/core/context-budget-headroom-candidates.js.map +1 -1
- package/dist/core/context-budget-headroom-types.d.ts +7 -1
- package/dist/core/context-budget-headroom-types.d.ts.map +1 -1
- package/dist/core/context-budget-headroom-types.js +0 -1
- package/dist/core/context-budget-headroom-types.js.map +1 -1
- package/dist/core/context-budget-headroom.d.ts +22 -0
- package/dist/core/context-budget-headroom.d.ts.map +1 -1
- package/dist/core/context-budget-headroom.js +46 -2
- package/dist/core/context-budget-headroom.js.map +1 -1
- package/dist/core/context-budget-v2-global-pass.d.ts +21 -0
- package/dist/core/context-budget-v2-global-pass.d.ts.map +1 -0
- package/dist/core/context-budget-v2-global-pass.js +203 -0
- package/dist/core/context-budget-v2-global-pass.js.map +1 -0
- package/dist/core/context-budget-v2-input-validation.d.ts +4 -0
- package/dist/core/context-budget-v2-input-validation.d.ts.map +1 -0
- package/dist/core/context-budget-v2-input-validation.js +79 -0
- package/dist/core/context-budget-v2-input-validation.js.map +1 -0
- package/dist/core/context-budget-v2-observability.d.ts +15 -0
- package/dist/core/context-budget-v2-observability.d.ts.map +1 -0
- package/dist/core/context-budget-v2-observability.js +35 -0
- package/dist/core/context-budget-v2-observability.js.map +1 -0
- package/dist/core/context-budget-v2-planned-items.d.ts +17 -0
- package/dist/core/context-budget-v2-planned-items.d.ts.map +1 -0
- package/dist/core/context-budget-v2-planned-items.js +59 -0
- package/dist/core/context-budget-v2-planned-items.js.map +1 -0
- package/dist/core/context-budget-v2-planner.d.ts.map +1 -1
- package/dist/core/context-budget-v2-planner.js +69 -51
- package/dist/core/context-budget-v2-planner.js.map +1 -1
- package/dist/core/context-budget-v2-scoring.d.ts +7 -1
- package/dist/core/context-budget-v2-scoring.d.ts.map +1 -1
- package/dist/core/context-budget-v2-scoring.js.map +1 -1
- package/dist/core/context-budget-v2-selection.d.ts +22 -3
- package/dist/core/context-budget-v2-selection.d.ts.map +1 -1
- package/dist/core/context-budget-v2-selection.js +41 -59
- package/dist/core/context-budget-v2-selection.js.map +1 -1
- package/dist/core/context-budget-v2-tiers.d.ts.map +1 -1
- package/dist/core/context-budget-v2-tiers.js +9 -42
- package/dist/core/context-budget-v2-tiers.js.map +1 -1
- package/dist/core/context-budget-v2-types.d.ts +14 -2
- package/dist/core/context-budget-v2-types.d.ts.map +1 -1
- package/dist/core/context-budget-v2-types.js +6 -1
- package/dist/core/context-budget-v2-types.js.map +1 -1
- package/dist/core/extensions/bundled-virtual-modules.d.ts +15 -0
- package/dist/core/extensions/bundled-virtual-modules.d.ts.map +1 -0
- package/dist/core/extensions/bundled-virtual-modules.js +63 -0
- package/dist/core/extensions/bundled-virtual-modules.js.map +1 -0
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +2 -42
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +1 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +6 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +10 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/index.d.ts +2 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +2 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/loadout-runtime.d.ts +2 -8
- package/dist/core/loadout-runtime.d.ts.map +1 -1
- package/dist/core/loadout-runtime.js.map +1 -1
- package/dist/core/mcp/client.d.ts +27 -6
- package/dist/core/mcp/client.d.ts.map +1 -1
- package/dist/core/mcp/client.js +80 -20
- package/dist/core/mcp/client.js.map +1 -1
- package/dist/core/mcp/manager.d.ts +10 -1
- package/dist/core/mcp/manager.d.ts.map +1 -1
- package/dist/core/mcp/manager.js +68 -9
- package/dist/core/mcp/manager.js.map +1 -1
- package/dist/core/mcp/protocol.d.ts +9 -3
- package/dist/core/mcp/protocol.d.ts.map +1 -1
- package/dist/core/mcp/protocol.js +61 -15
- package/dist/core/mcp/protocol.js.map +1 -1
- package/dist/core/mcp/stdio-transport.d.ts +12 -1
- package/dist/core/mcp/stdio-transport.d.ts.map +1 -1
- package/dist/core/mcp/stdio-transport.js +30 -2
- package/dist/core/mcp/stdio-transport.js.map +1 -1
- package/dist/core/mcp-descriptor-injection.d.ts +26 -0
- package/dist/core/mcp-descriptor-injection.d.ts.map +1 -0
- package/dist/core/mcp-descriptor-injection.js +25 -0
- package/dist/core/mcp-descriptor-injection.js.map +1 -0
- package/dist/core/mcp-public-presets.d.ts +1 -3
- package/dist/core/mcp-public-presets.d.ts.map +1 -1
- package/dist/core/mcp-public-presets.js +3 -15
- package/dist/core/mcp-public-presets.js.map +1 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +24 -3
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/neo/catalog.d.ts +20 -0
- package/dist/core/neo/catalog.d.ts.map +1 -0
- package/dist/core/neo/catalog.js +50 -0
- package/dist/core/neo/catalog.js.map +1 -0
- package/dist/core/neo/setup.d.ts +3 -0
- package/dist/core/neo/setup.d.ts.map +1 -0
- package/dist/core/neo/setup.js +47 -0
- package/dist/core/neo/setup.js.map +1 -0
- package/dist/core/provider-default-models.d.ts +2 -0
- package/dist/core/provider-default-models.d.ts.map +1 -1
- package/dist/core/provider-default-models.js +2 -0
- package/dist/core/provider-default-models.js.map +1 -1
- package/dist/core/provider-display-names.d.ts.map +1 -1
- package/dist/core/provider-display-names.js +2 -0
- package/dist/core/provider-display-names.js.map +1 -1
- package/dist/core/provider-error-classification.d.ts +57 -0
- package/dist/core/provider-error-classification.d.ts.map +1 -0
- package/dist/core/provider-error-classification.js +103 -0
- package/dist/core/provider-error-classification.js.map +1 -0
- package/dist/core/provider-resilience.d.ts +10 -0
- package/dist/core/provider-resilience.d.ts.map +1 -1
- package/dist/core/provider-resilience.js +36 -3
- package/dist/core/provider-resilience.js.map +1 -1
- package/dist/core/provider-usage-commandcode.d.ts +9 -0
- package/dist/core/provider-usage-commandcode.d.ts.map +1 -0
- package/dist/core/provider-usage-commandcode.js +198 -0
- package/dist/core/provider-usage-commandcode.js.map +1 -0
- package/dist/core/provider-usage-devin.d.ts +5 -3
- package/dist/core/provider-usage-devin.d.ts.map +1 -1
- package/dist/core/provider-usage-devin.js +15 -5
- package/dist/core/provider-usage-devin.js.map +1 -1
- package/dist/core/provider-usage-types.d.ts +1 -1
- package/dist/core/provider-usage-types.d.ts.map +1 -1
- package/dist/core/provider-usage-types.js.map +1 -1
- package/dist/core/provider-usage.d.ts.map +1 -1
- package/dist/core/provider-usage.js +6 -0
- package/dist/core/provider-usage.js.map +1 -1
- package/dist/core/reasoning-router-resolver.d.ts +7 -0
- package/dist/core/reasoning-router-resolver.d.ts.map +1 -1
- package/dist/core/reasoning-router-resolver.js +21 -3
- package/dist/core/reasoning-router-resolver.js.map +1 -1
- package/dist/core/reasoning-router-v4.d.ts +8 -5
- package/dist/core/reasoning-router-v4.d.ts.map +1 -1
- package/dist/core/reasoning-router-v4.js +8 -5
- package/dist/core/reasoning-router-v4.js.map +1 -1
- package/dist/core/resource-admission.d.ts +36 -0
- package/dist/core/resource-admission.d.ts.map +1 -1
- package/dist/core/resource-admission.js +59 -0
- package/dist/core/resource-admission.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +2 -2
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/run-usage-ledger.d.ts +47 -0
- package/dist/core/run-usage-ledger.d.ts.map +1 -0
- package/dist/core/run-usage-ledger.js +162 -0
- package/dist/core/run-usage-ledger.js.map +1 -0
- package/dist/core/run-usage-operation.d.ts +8 -0
- package/dist/core/run-usage-operation.d.ts.map +1 -0
- package/dist/core/run-usage-operation.js +12 -0
- package/dist/core/run-usage-operation.js.map +1 -0
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +5 -6
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-compaction-service.d.ts +15 -0
- package/dist/core/session-compaction-service.d.ts.map +1 -1
- package/dist/core/session-compaction-service.js +17 -4
- package/dist/core/session-compaction-service.js.map +1 -1
- package/dist/core/session-failure-cause.d.ts.map +1 -1
- package/dist/core/session-failure-cause.js +14 -5
- package/dist/core/session-failure-cause.js.map +1 -1
- package/dist/core/session-prompt-lifecycle.d.ts +6 -0
- package/dist/core/session-prompt-lifecycle.d.ts.map +1 -1
- package/dist/core/session-prompt-lifecycle.js +47 -2
- package/dist/core/session-prompt-lifecycle.js.map +1 -1
- package/dist/core/session-termination.d.ts.map +1 -1
- package/dist/core/session-termination.js +4 -2
- package/dist/core/session-termination.js.map +1 -1
- package/dist/core/subagent-lane-authority.d.ts +28 -0
- package/dist/core/subagent-lane-authority.d.ts.map +1 -0
- package/dist/core/subagent-lane-authority.js +119 -0
- package/dist/core/subagent-lane-authority.js.map +1 -0
- package/dist/core/subagent-lane-contract.d.ts +114 -0
- package/dist/core/subagent-lane-contract.d.ts.map +1 -0
- package/dist/core/subagent-lane-contract.js +18 -0
- package/dist/core/subagent-lane-contract.js.map +1 -0
- package/dist/core/subagent-lane-launcher.d.ts +3 -6
- package/dist/core/subagent-lane-launcher.d.ts.map +1 -1
- package/dist/core/subagent-lane-launcher.js +53 -12
- package/dist/core/subagent-lane-launcher.js.map +1 -1
- package/dist/core/subagent-orchestration.d.ts +4 -17
- package/dist/core/subagent-orchestration.d.ts.map +1 -1
- package/dist/core/subagent-orchestration.js.map +1 -1
- package/dist/core/todo-runtime-state.d.ts +12 -0
- package/dist/core/todo-runtime-state.d.ts.map +1 -1
- package/dist/core/todo-runtime-state.js +23 -0
- package/dist/core/todo-runtime-state.js.map +1 -1
- package/dist/core/verified-run/broker.d.ts.map +1 -1
- package/dist/core/verified-run/broker.js +4 -1
- package/dist/core/verified-run/broker.js.map +1 -1
- package/dist/core/workload-permit-pool.d.ts +1 -1
- package/dist/core/workload-permit-pool.d.ts.map +1 -1
- package/dist/core/workload-permit-pool.js +3 -0
- package/dist/core/workload-permit-pool.js.map +1 -1
- package/dist/guardrails/strict-evidence-approval-adapter.d.ts +34 -0
- package/dist/guardrails/strict-evidence-approval-adapter.d.ts.map +1 -0
- package/dist/guardrails/strict-evidence-approval-adapter.js +70 -0
- package/dist/guardrails/strict-evidence-approval-adapter.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +11 -18
- package/dist/main.js.map +1 -1
- package/dist/metacognition/calibration-selective.d.ts +78 -0
- package/dist/metacognition/calibration-selective.d.ts.map +1 -0
- package/dist/metacognition/calibration-selective.js +161 -0
- package/dist/metacognition/calibration-selective.js.map +1 -0
- package/dist/metacognition/calibration.d.ts +62 -0
- package/dist/metacognition/calibration.d.ts.map +1 -0
- package/dist/metacognition/calibration.js +122 -0
- package/dist/metacognition/calibration.js.map +1 -0
- package/dist/metacognition/checkpoint.d.ts +60 -0
- package/dist/metacognition/checkpoint.d.ts.map +1 -0
- package/dist/metacognition/checkpoint.js +57 -0
- package/dist/metacognition/checkpoint.js.map +1 -0
- package/dist/metacognition/context7.d.ts +48 -0
- package/dist/metacognition/context7.d.ts.map +1 -0
- package/dist/metacognition/context7.js +154 -0
- package/dist/metacognition/context7.js.map +1 -0
- package/dist/metacognition/decision.d.ts +44 -0
- package/dist/metacognition/decision.d.ts.map +1 -0
- package/dist/metacognition/decision.js +111 -0
- package/dist/metacognition/decision.js.map +1 -0
- package/dist/metacognition/evaluation.d.ts +73 -0
- package/dist/metacognition/evaluation.d.ts.map +1 -0
- package/dist/metacognition/evaluation.js +97 -0
- package/dist/metacognition/evaluation.js.map +1 -0
- package/dist/metacognition/index.d.ts +31 -0
- package/dist/metacognition/index.d.ts.map +1 -0
- package/dist/metacognition/index.js +31 -0
- package/dist/metacognition/index.js.map +1 -0
- package/dist/metacognition/knowledge-action.d.ts +43 -0
- package/dist/metacognition/knowledge-action.d.ts.map +1 -0
- package/dist/metacognition/knowledge-action.js +60 -0
- package/dist/metacognition/knowledge-action.js.map +1 -0
- package/dist/metacognition/knowledge.d.ts +84 -0
- package/dist/metacognition/knowledge.d.ts.map +1 -0
- package/dist/metacognition/knowledge.js +165 -0
- package/dist/metacognition/knowledge.js.map +1 -0
- package/dist/metacognition/obligations.d.ts +82 -0
- package/dist/metacognition/obligations.d.ts.map +1 -0
- package/dist/metacognition/obligations.js +139 -0
- package/dist/metacognition/obligations.js.map +1 -0
- package/dist/metacognition/observation-validity.d.ts +83 -0
- package/dist/metacognition/observation-validity.d.ts.map +1 -0
- package/dist/metacognition/observation-validity.js +118 -0
- package/dist/metacognition/observation-validity.js.map +1 -0
- package/dist/metacognition/observe.d.ts +45 -0
- package/dist/metacognition/observe.d.ts.map +1 -0
- package/dist/metacognition/observe.js +59 -0
- package/dist/metacognition/observe.js.map +1 -0
- package/dist/metacognition/policy.d.ts +53 -0
- package/dist/metacognition/policy.d.ts.map +1 -0
- package/dist/metacognition/policy.js +155 -0
- package/dist/metacognition/policy.js.map +1 -0
- package/dist/metacognition/predictions.d.ts +78 -0
- package/dist/metacognition/predictions.d.ts.map +1 -0
- package/dist/metacognition/predictions.js +181 -0
- package/dist/metacognition/predictions.js.map +1 -0
- package/dist/metacognition/retrieval.d.ts +53 -0
- package/dist/metacognition/retrieval.d.ts.map +1 -0
- package/dist/metacognition/retrieval.js +170 -0
- package/dist/metacognition/retrieval.js.map +1 -0
- package/dist/metacognition/risk.d.ts +48 -0
- package/dist/metacognition/risk.d.ts.map +1 -0
- package/dist/metacognition/risk.js +165 -0
- package/dist/metacognition/risk.js.map +1 -0
- package/dist/metacognition/route-economics.d.ts +95 -0
- package/dist/metacognition/route-economics.d.ts.map +1 -0
- package/dist/metacognition/route-economics.js +110 -0
- package/dist/metacognition/route-economics.js.map +1 -0
- package/dist/metacognition/runtime-bridge.d.ts +54 -0
- package/dist/metacognition/runtime-bridge.d.ts.map +1 -0
- package/dist/metacognition/runtime-bridge.js +140 -0
- package/dist/metacognition/runtime-bridge.js.map +1 -0
- package/dist/metacognition/skills.d.ts +42 -0
- package/dist/metacognition/skills.d.ts.map +1 -0
- package/dist/metacognition/skills.js +220 -0
- package/dist/metacognition/skills.js.map +1 -0
- package/dist/metacognition/state.d.ts +110 -0
- package/dist/metacognition/state.d.ts.map +1 -0
- package/dist/metacognition/state.js +52 -0
- package/dist/metacognition/state.js.map +1 -0
- package/dist/metacognition/validation.d.ts +19 -0
- package/dist/metacognition/validation.d.ts.map +1 -0
- package/dist/metacognition/validation.js +58 -0
- package/dist/metacognition/validation.js.map +1 -0
- package/dist/metacognition/verification.d.ts +93 -0
- package/dist/metacognition/verification.d.ts.map +1 -0
- package/dist/metacognition/verification.js +132 -0
- package/dist/metacognition/verification.js.map +1 -0
- package/dist/metacognition/verifier.d.ts +49 -0
- package/dist/metacognition/verifier.d.ts.map +1 -0
- package/dist/metacognition/verifier.js +88 -0
- package/dist/metacognition/verifier.js.map +1 -0
- package/dist/modes/acp/acp-agent.d.ts +24 -0
- package/dist/modes/acp/acp-agent.d.ts.map +1 -0
- package/dist/modes/acp/acp-agent.js +133 -0
- package/dist/modes/acp/acp-agent.js.map +1 -0
- package/dist/modes/acp/acp-mode.d.ts +4 -0
- package/dist/modes/acp/acp-mode.d.ts.map +1 -0
- package/dist/modes/acp/acp-mode.js +34 -0
- package/dist/modes/acp/acp-mode.js.map +1 -0
- package/dist/modes/acp/acp-session.d.ts +4 -0
- package/dist/modes/acp/acp-session.d.ts.map +1 -0
- package/dist/modes/acp/acp-session.js +76 -0
- package/dist/modes/acp/acp-session.js.map +1 -0
- package/dist/modes/acp/acp-transport.d.ts +5 -0
- package/dist/modes/acp/acp-transport.d.ts.map +1 -0
- package/dist/modes/acp/acp-transport.js +90 -0
- package/dist/modes/acp/acp-transport.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +1 -0
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/observation/identity.d.ts +14 -0
- package/dist/observation/identity.d.ts.map +1 -0
- package/dist/observation/identity.js +29 -0
- package/dist/observation/identity.js.map +1 -0
- package/dist/observation/index.d.ts +13 -0
- package/dist/observation/index.d.ts.map +1 -0
- package/dist/observation/index.js +13 -0
- package/dist/observation/index.js.map +1 -0
- package/dist/observation/observe-mode.d.ts +46 -0
- package/dist/observation/observe-mode.d.ts.map +1 -0
- package/dist/observation/observe-mode.js +83 -0
- package/dist/observation/observe-mode.js.map +1 -0
- package/dist/observation/store.d.ts +53 -0
- package/dist/observation/store.d.ts.map +1 -0
- package/dist/observation/store.js +126 -0
- package/dist/observation/store.js.map +1 -0
- package/dist/observation/types.d.ts +72 -0
- package/dist/observation/types.d.ts.map +1 -0
- package/dist/observation/types.js +9 -0
- package/dist/observation/types.js.map +1 -0
- package/dist/observation/view.d.ts +39 -0
- package/dist/observation/view.d.ts.map +1 -0
- package/dist/observation/view.js +173 -0
- package/dist/observation/view.js.map +1 -0
- package/docs/audit-revalidation-2026-09-17.md +77 -0
- package/docs/devin-harness.md +33 -4
- package/docs/ecraf-normalization.md +83 -0
- package/docs/metacognition.md +51 -0
- package/docs/model-catalog-refresh.md +110 -1
- package/docs/models.md +1 -1
- package/docs/neo.md +134 -0
- package/docs/providers.md +125 -6
- package/docs/run-usage-ledger.md +56 -0
- package/docs/runtime-algorithms.md +151 -3
- package/docs/skills.md +1 -1
- package/docs/usage.md +2 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/subagent/adaptive-agent-runtime.ts +14 -1
- package/examples/extensions/subagent/graph-result.ts +48 -0
- package/examples/extensions/subagent/index.ts +246 -111
- package/examples/extensions/subagent/managed-process-tree.ts +42 -0
- package/examples/extensions/subagent/managed-process.test.ts +24 -0
- package/examples/extensions/subagent/managed-process.ts +93 -112
- package/examples/extensions/subagent/subagent-runtime-types.ts +17 -1
- package/examples/extensions/subagent/subagent-stream.ts +161 -0
- package/examples/extensions/terminal-browser/README.md +54 -0
- package/examples/extensions/terminal-browser/bridge-protocol.ts +29 -0
- package/examples/extensions/terminal-browser/bridge.ts +219 -0
- package/examples/extensions/terminal-browser/browser-surface.ts +288 -0
- package/examples/extensions/terminal-browser/index.ts +215 -0
- package/examples/extensions/terminal-browser/placeholders.ts +49 -0
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +18 -18
- package/package.json +8 -7
- package/resources/neo/skills/omk-browser/SKILL.md +32 -0
- package/resources/neo/skills/omk-code-review/SKILL.md +24 -0
- package/resources/neo/skills/omk-computeruse/SKILL.md +34 -0
- package/resources/neo/skills/omk-mcp-setup/SKILL.md +48 -0
- package/resources/neo/skills/omk-research/SKILL.md +24 -0
- package/resources/neo/skills/omk-site/SKILL.md +28 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded local BM25 retrieval and the acquisition pool that owns every
|
|
3
|
+
* started promise until actual settlement.
|
|
4
|
+
*
|
|
5
|
+
* Ported from docs/OMK_skill_knowledge_control_2026-09-19.zip
|
|
6
|
+
* (src/retrieval.ts). Search hits are `candidate-only`, never auto-promoted
|
|
7
|
+
* to observations.
|
|
8
|
+
*/
|
|
9
|
+
import { ensure, integer, lexical, text, unique } from "./validation.js";
|
|
10
|
+
/** Retrieval tokens, not a semantic-knowledge detector. Short language names survive. */
|
|
11
|
+
export function retrievalTokens(value) {
|
|
12
|
+
return (value
|
|
13
|
+
.normalize("NFKC")
|
|
14
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1 $2")
|
|
15
|
+
.toLowerCase()
|
|
16
|
+
.match(/[\p{L}\p{N}]+(?:\+\+|#)?/gu) ?? []);
|
|
17
|
+
}
|
|
18
|
+
/** BM25 with positive IDF; bounded local corpus, no I/O or model call. */
|
|
19
|
+
export function searchCorpus(query, corpus, limit = 8) {
|
|
20
|
+
text(query, "query", 4096);
|
|
21
|
+
integer(limit, "limit", 64);
|
|
22
|
+
ensure(corpus.length <= 5000, "corpus too large");
|
|
23
|
+
unique(corpus.map((d) => d.id), "document ids", 5000);
|
|
24
|
+
let totalChars = 0;
|
|
25
|
+
const documents = corpus.map((d) => {
|
|
26
|
+
text(d.uri, "uri");
|
|
27
|
+
ensure(typeof d.body === "string" && d.body.length <= 100_000, "document too large");
|
|
28
|
+
totalChars += d.body.length;
|
|
29
|
+
ensure(totalChars <= 10_000_000, "corpus byte/character policy exceeded");
|
|
30
|
+
const tokens = retrievalTokens(d.body);
|
|
31
|
+
const frequencies = new Map();
|
|
32
|
+
for (const token of tokens)
|
|
33
|
+
frequencies.set(token, (frequencies.get(token) ?? 0) + 1);
|
|
34
|
+
return { d, length: tokens.length, frequencies };
|
|
35
|
+
});
|
|
36
|
+
const terms = [...new Set(retrievalTokens(query))];
|
|
37
|
+
if (!terms.length || !documents.length || limit === 0)
|
|
38
|
+
return [];
|
|
39
|
+
const avgLength = Math.max(1, documents.reduce((s, d) => s + d.length, 0) / documents.length);
|
|
40
|
+
const idf = new Map(terms.map((term) => {
|
|
41
|
+
const frequency = documents.filter((d) => d.frequencies.has(term)).length;
|
|
42
|
+
return [term, Math.log(1 + (documents.length - frequency + 0.5) / (frequency + 0.5))];
|
|
43
|
+
}));
|
|
44
|
+
return documents
|
|
45
|
+
.map(({ d, length, frequencies }) => {
|
|
46
|
+
let score = 0;
|
|
47
|
+
for (const term of terms) {
|
|
48
|
+
const tf = frequencies.get(term) ?? 0;
|
|
49
|
+
score += (idf.get(term) * tf * 2.2) / (tf + 1.2 * (0.25 + (0.75 * length) / avgLength));
|
|
50
|
+
}
|
|
51
|
+
return { ...d, score, trust: "candidate-only" };
|
|
52
|
+
})
|
|
53
|
+
.filter((d) => d.score > 0)
|
|
54
|
+
.sort((a, b) => b.score - a.score || lexical(a.id, b.id))
|
|
55
|
+
.slice(0, limit);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Owns every started promise until actual settlement, including noncooperative requests.
|
|
59
|
+
* The scope is per host-approved run. It is not a billing or process-isolation boundary.
|
|
60
|
+
*/
|
|
61
|
+
export class AcquisitionPool {
|
|
62
|
+
now;
|
|
63
|
+
deadline;
|
|
64
|
+
maxRequests;
|
|
65
|
+
maxInFlight;
|
|
66
|
+
perRequestMs;
|
|
67
|
+
nextId = 0;
|
|
68
|
+
epoch = 0;
|
|
69
|
+
requests = 0;
|
|
70
|
+
active = new Map();
|
|
71
|
+
constructor(options) {
|
|
72
|
+
integer(options.maxRequests, "maxRequests", 100_000);
|
|
73
|
+
integer(options.maxInFlight, "maxInFlight", 64);
|
|
74
|
+
integer(options.durationMs, "durationMs", 86_400_000);
|
|
75
|
+
integer(options.perRequestMs, "perRequestMs", 86_400_000);
|
|
76
|
+
this.now = options.monotonicNow ?? (() => performance.now());
|
|
77
|
+
const start = this.now();
|
|
78
|
+
ensure(Number.isFinite(start) && start >= 0, "invalid monotonic clock");
|
|
79
|
+
this.deadline = start + options.durationMs;
|
|
80
|
+
this.maxRequests = options.maxRequests;
|
|
81
|
+
this.maxInFlight = options.maxInFlight;
|
|
82
|
+
this.perRequestMs = options.perRequestMs;
|
|
83
|
+
}
|
|
84
|
+
snapshot() {
|
|
85
|
+
return {
|
|
86
|
+
requests: this.requests,
|
|
87
|
+
active: this.active.size,
|
|
88
|
+
quarantined: [...this.active.values()].filter((e) => e.quarantined).length,
|
|
89
|
+
remainingMs: Math.max(0, Math.floor(this.deadline - this.now())),
|
|
90
|
+
epoch: this.epoch,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/** Invalidation requests cancellation but never resets outstanding ownership or budget. */
|
|
94
|
+
invalidate() {
|
|
95
|
+
this.epoch++;
|
|
96
|
+
for (const entry of this.active.values()) {
|
|
97
|
+
entry.quarantined = true;
|
|
98
|
+
entry.controller.abort();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
async run(operation, parent) {
|
|
102
|
+
if (parent?.aborted)
|
|
103
|
+
return { status: "aborted" };
|
|
104
|
+
const remaining = this.deadline - this.now();
|
|
105
|
+
if (this.requests >= this.maxRequests || remaining <= 0 || this.perRequestMs === 0) {
|
|
106
|
+
return { status: "budget-exhausted" };
|
|
107
|
+
}
|
|
108
|
+
if (this.active.size >= this.maxInFlight)
|
|
109
|
+
return { status: "busy" };
|
|
110
|
+
const id = ++this.nextId, epoch = this.epoch, controller = new AbortController();
|
|
111
|
+
const entry = { controller, quarantined: false };
|
|
112
|
+
this.active.set(id, entry);
|
|
113
|
+
this.requests++;
|
|
114
|
+
const expires = this.now() + Math.min(remaining, this.perRequestMs);
|
|
115
|
+
let resolveStop;
|
|
116
|
+
const stopped = new Promise((resolve) => {
|
|
117
|
+
resolveStop = resolve;
|
|
118
|
+
});
|
|
119
|
+
const stop = (status) => {
|
|
120
|
+
if (this.active.has(id))
|
|
121
|
+
entry.quarantined = true;
|
|
122
|
+
resolveStop({ status });
|
|
123
|
+
controller.abort();
|
|
124
|
+
};
|
|
125
|
+
const onParent = () => stop("aborted");
|
|
126
|
+
const onInternal = () => {
|
|
127
|
+
if (epoch !== this.epoch)
|
|
128
|
+
resolveStop({ status: "stale" });
|
|
129
|
+
};
|
|
130
|
+
parent?.addEventListener("abort", onParent, { once: true });
|
|
131
|
+
controller.signal.addEventListener("abort", onInternal, { once: true });
|
|
132
|
+
const timer = setTimeout(() => stop("timeout"), Math.max(1, Math.ceil(expires - this.now())));
|
|
133
|
+
// Both fulfillment and rejection are owned. Late results are never promoted.
|
|
134
|
+
const task = Promise.resolve()
|
|
135
|
+
.then(() => {
|
|
136
|
+
if (controller.signal.aborted || parent?.aborted)
|
|
137
|
+
throw new Error("cancelled-before-dispatch");
|
|
138
|
+
return operation(controller.signal);
|
|
139
|
+
})
|
|
140
|
+
.then((value) => {
|
|
141
|
+
if (epoch !== this.epoch)
|
|
142
|
+
return { status: "stale" };
|
|
143
|
+
if (parent?.aborted)
|
|
144
|
+
return { status: "aborted" };
|
|
145
|
+
if (controller.signal.aborted || this.now() >= expires)
|
|
146
|
+
return { status: "timeout" };
|
|
147
|
+
return { status: "ok", value };
|
|
148
|
+
}, () => ({
|
|
149
|
+
status: epoch !== this.epoch
|
|
150
|
+
? "stale"
|
|
151
|
+
: parent?.aborted
|
|
152
|
+
? "aborted"
|
|
153
|
+
: controller.signal.aborted
|
|
154
|
+
? "timeout"
|
|
155
|
+
: "error",
|
|
156
|
+
}))
|
|
157
|
+
.finally(() => {
|
|
158
|
+
this.active.delete(id);
|
|
159
|
+
});
|
|
160
|
+
try {
|
|
161
|
+
return await Promise.race([task, stopped]);
|
|
162
|
+
}
|
|
163
|
+
finally {
|
|
164
|
+
clearTimeout(timer);
|
|
165
|
+
parent?.removeEventListener("abort", onParent);
|
|
166
|
+
controller.signal.removeEventListener("abort", onInternal);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=retrieval.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retrieval.js","sourceRoot":"","sources":["../../src/metacognition/retrieval.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Bounded local BM25 retrieval and the acquisition pool that owns every\n * started promise until actual settlement.\n *\n * Ported from docs/OMK_skill_knowledge_control_2026-09-19.zip\n * (src/retrieval.ts). Search hits are `candidate-only`, never auto-promoted\n * to observations.\n */\nimport { ensure, integer, lexical, text, unique } from \"./validation.ts\";\n\nexport interface CorpusDocument {\n\treadonly id: string;\n\treadonly uri: string;\n\treadonly body: string;\n}\nexport interface SearchHit extends CorpusDocument {\n\treadonly score: number;\n\treadonly trust: \"candidate-only\";\n}\n/** Retrieval tokens, not a semantic-knowledge detector. Short language names survive. */\nexport function retrievalTokens(value: string): string[] {\n\treturn (\n\t\tvalue\n\t\t\t.normalize(\"NFKC\")\n\t\t\t.replace(/([a-z0-9])([A-Z])/g, \"$1 $2\")\n\t\t\t.toLowerCase()\n\t\t\t.match(/[\\p{L}\\p{N}]+(?:\\+\\+|#)?/gu) ?? []\n\t);\n}\n/** BM25 with positive IDF; bounded local corpus, no I/O or model call. */\nexport function searchCorpus(query: string, corpus: readonly CorpusDocument[], limit = 8): SearchHit[] {\n\ttext(query, \"query\", 4096);\n\tinteger(limit, \"limit\", 64);\n\tensure(corpus.length <= 5000, \"corpus too large\");\n\tunique(\n\t\tcorpus.map((d) => d.id),\n\t\t\"document ids\",\n\t\t5000,\n\t);\n\tlet totalChars = 0;\n\tconst documents = corpus.map((d) => {\n\t\ttext(d.uri, \"uri\");\n\t\tensure(typeof d.body === \"string\" && d.body.length <= 100_000, \"document too large\");\n\t\ttotalChars += d.body.length;\n\t\tensure(totalChars <= 10_000_000, \"corpus byte/character policy exceeded\");\n\t\tconst tokens = retrievalTokens(d.body);\n\t\tconst frequencies = new Map<string, number>();\n\t\tfor (const token of tokens) frequencies.set(token, (frequencies.get(token) ?? 0) + 1);\n\t\treturn { d, length: tokens.length, frequencies };\n\t});\n\tconst terms = [...new Set(retrievalTokens(query))];\n\tif (!terms.length || !documents.length || limit === 0) return [];\n\tconst avgLength = Math.max(1, documents.reduce((s, d) => s + d.length, 0) / documents.length);\n\tconst idf = new Map(\n\t\tterms.map((term) => {\n\t\t\tconst frequency = documents.filter((d) => d.frequencies.has(term)).length;\n\t\t\treturn [term, Math.log(1 + (documents.length - frequency + 0.5) / (frequency + 0.5))] as const;\n\t\t}),\n\t);\n\treturn documents\n\t\t.map(({ d, length, frequencies }): SearchHit => {\n\t\t\tlet score = 0;\n\t\t\tfor (const term of terms) {\n\t\t\t\tconst tf = frequencies.get(term) ?? 0;\n\t\t\t\tscore += (idf.get(term)! * tf * 2.2) / (tf + 1.2 * (0.25 + (0.75 * length) / avgLength));\n\t\t\t}\n\t\t\treturn { ...d, score, trust: \"candidate-only\" };\n\t\t})\n\t\t.filter((d) => d.score > 0)\n\t\t.sort((a, b) => b.score - a.score || lexical(a.id, b.id))\n\t\t.slice(0, limit);\n}\n\nexport type AcquisitionResult<T> =\n\t| { readonly status: \"ok\"; readonly value: T }\n\t| { readonly status: \"budget-exhausted\" | \"busy\" | \"timeout\" | \"aborted\" | \"stale\" | \"error\" };\nexport interface AcquisitionOptions {\n\treadonly maxRequests: number;\n\treadonly maxInFlight: number;\n\treadonly durationMs: number;\n\treadonly perRequestMs: number;\n\treadonly monotonicNow?: () => number;\n}\n/**\n * Owns every started promise until actual settlement, including noncooperative requests.\n * The scope is per host-approved run. It is not a billing or process-isolation boundary.\n */\nexport class AcquisitionPool {\n\tprivate readonly now: () => number;\n\tprivate readonly deadline: number;\n\tprivate readonly maxRequests: number;\n\tprivate readonly maxInFlight: number;\n\tprivate readonly perRequestMs: number;\n\tprivate nextId = 0;\n\tprivate epoch = 0;\n\tprivate requests = 0;\n\tprivate readonly active = new Map<number, { controller: AbortController; quarantined: boolean }>();\n\tconstructor(options: AcquisitionOptions) {\n\t\tinteger(options.maxRequests, \"maxRequests\", 100_000);\n\t\tinteger(options.maxInFlight, \"maxInFlight\", 64);\n\t\tinteger(options.durationMs, \"durationMs\", 86_400_000);\n\t\tinteger(options.perRequestMs, \"perRequestMs\", 86_400_000);\n\t\tthis.now = options.monotonicNow ?? (() => performance.now());\n\t\tconst start = this.now();\n\t\tensure(Number.isFinite(start) && start >= 0, \"invalid monotonic clock\");\n\t\tthis.deadline = start + options.durationMs;\n\t\tthis.maxRequests = options.maxRequests;\n\t\tthis.maxInFlight = options.maxInFlight;\n\t\tthis.perRequestMs = options.perRequestMs;\n\t}\n\tsnapshot(): { requests: number; active: number; quarantined: number; remainingMs: number; epoch: number } {\n\t\treturn {\n\t\t\trequests: this.requests,\n\t\t\tactive: this.active.size,\n\t\t\tquarantined: [...this.active.values()].filter((e) => e.quarantined).length,\n\t\t\tremainingMs: Math.max(0, Math.floor(this.deadline - this.now())),\n\t\t\tepoch: this.epoch,\n\t\t};\n\t}\n\t/** Invalidation requests cancellation but never resets outstanding ownership or budget. */\n\tinvalidate(): void {\n\t\tthis.epoch++;\n\t\tfor (const entry of this.active.values()) {\n\t\t\tentry.quarantined = true;\n\t\t\tentry.controller.abort();\n\t\t}\n\t}\n\tasync run<T>(operation: (signal: AbortSignal) => Promise<T>, parent?: AbortSignal): Promise<AcquisitionResult<T>> {\n\t\tif (parent?.aborted) return { status: \"aborted\" };\n\t\tconst remaining = this.deadline - this.now();\n\t\tif (this.requests >= this.maxRequests || remaining <= 0 || this.perRequestMs === 0) {\n\t\t\treturn { status: \"budget-exhausted\" };\n\t\t}\n\t\tif (this.active.size >= this.maxInFlight) return { status: \"busy\" };\n\t\tconst id = ++this.nextId,\n\t\t\tepoch = this.epoch,\n\t\t\tcontroller = new AbortController();\n\t\tconst entry = { controller, quarantined: false };\n\t\tthis.active.set(id, entry);\n\t\tthis.requests++;\n\t\tconst expires = this.now() + Math.min(remaining, this.perRequestMs);\n\t\tlet resolveStop!: (result: AcquisitionResult<T>) => void;\n\t\tconst stopped = new Promise<AcquisitionResult<T>>((resolve) => {\n\t\t\tresolveStop = resolve;\n\t\t});\n\t\tconst stop = (status: \"aborted\" | \"timeout\" | \"stale\"): void => {\n\t\t\tif (this.active.has(id)) entry.quarantined = true;\n\t\t\tresolveStop({ status });\n\t\t\tcontroller.abort();\n\t\t};\n\t\tconst onParent = (): void => stop(\"aborted\");\n\t\tconst onInternal = (): void => {\n\t\t\tif (epoch !== this.epoch) resolveStop({ status: \"stale\" });\n\t\t};\n\t\tparent?.addEventListener(\"abort\", onParent, { once: true });\n\t\tcontroller.signal.addEventListener(\"abort\", onInternal, { once: true });\n\t\tconst timer = setTimeout(() => stop(\"timeout\"), Math.max(1, Math.ceil(expires - this.now())));\n\t\t// Both fulfillment and rejection are owned. Late results are never promoted.\n\t\tconst task = Promise.resolve()\n\t\t\t.then(() => {\n\t\t\t\tif (controller.signal.aborted || parent?.aborted) throw new Error(\"cancelled-before-dispatch\");\n\t\t\t\treturn operation(controller.signal);\n\t\t\t})\n\t\t\t.then(\n\t\t\t\t(value): AcquisitionResult<T> => {\n\t\t\t\t\tif (epoch !== this.epoch) return { status: \"stale\" };\n\t\t\t\t\tif (parent?.aborted) return { status: \"aborted\" };\n\t\t\t\t\tif (controller.signal.aborted || this.now() >= expires) return { status: \"timeout\" };\n\t\t\t\t\treturn { status: \"ok\", value };\n\t\t\t\t},\n\t\t\t\t(): AcquisitionResult<T> => ({\n\t\t\t\t\tstatus:\n\t\t\t\t\t\tepoch !== this.epoch\n\t\t\t\t\t\t\t? \"stale\"\n\t\t\t\t\t\t\t: parent?.aborted\n\t\t\t\t\t\t\t\t? \"aborted\"\n\t\t\t\t\t\t\t\t: controller.signal.aborted\n\t\t\t\t\t\t\t\t\t? \"timeout\"\n\t\t\t\t\t\t\t\t\t: \"error\",\n\t\t\t\t}),\n\t\t\t)\n\t\t\t.finally(() => {\n\t\t\t\tthis.active.delete(id);\n\t\t\t});\n\t\ttry {\n\t\t\treturn await Promise.race([task, stopped]);\n\t\t} finally {\n\t\t\tclearTimeout(timer);\n\t\t\tparent?.removeEventListener(\"abort\", onParent);\n\t\t\tcontroller.signal.removeEventListener(\"abort\", onInternal);\n\t\t}\n\t}\n}\n"]}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finite-sample risk bounds for automation gating (Jev audit algorithm A4).
|
|
3
|
+
*
|
|
4
|
+
* A point estimate must never widen automation scope. Two failures in a
|
|
5
|
+
* hundred is not "a 2% error rate" — its one-sided 95% Clopper–Pearson upper
|
|
6
|
+
* bound is about 6.2%, and that bound is what a gate reads.
|
|
7
|
+
*
|
|
8
|
+
* Scope: this bounds the failure probability of samples drawn under the stated
|
|
9
|
+
* conditions. It is not a safety guarantee for the next action, and it assumes
|
|
10
|
+
* a fixed policy, a consistent failure event, and adequately independent
|
|
11
|
+
* samples. Three hundred repeated clicks inside one task are not three hundred
|
|
12
|
+
* independent trials; cluster by task or environment instance before using it.
|
|
13
|
+
*/
|
|
14
|
+
/** Regularized incomplete beta I_x(a,b). */
|
|
15
|
+
export declare function regularizedIncompleteBeta(a: number, b: number, x: number): number;
|
|
16
|
+
/**
|
|
17
|
+
* One-sided Clopper–Pearson upper bound on the failure probability.
|
|
18
|
+
*
|
|
19
|
+
* `U(k,n) = Beta⁻¹(1−α; k+1, n−k)` for `0 ≤ k < n`, and `1` when every trial
|
|
20
|
+
* failed. Zero trials is not zero risk: it is absent evidence, so it throws.
|
|
21
|
+
*/
|
|
22
|
+
export declare function clopperPearsonUpperBound(failures: number, trials: number, alpha: number): number;
|
|
23
|
+
/** Closed form of {@link clopperPearsonUpperBound} when no trial failed. */
|
|
24
|
+
export declare function zeroFailureUpperBound(trials: number, alpha: number): number;
|
|
25
|
+
/**
|
|
26
|
+
* Smallest failure-free sample size whose upper bound meets `targetEpsilon`.
|
|
27
|
+
*
|
|
28
|
+
* `n ≥ ⌈log α / log(1−ε)⌉`, then nudged against the bound itself so a
|
|
29
|
+
* floating-point boundary cannot return a sample size that misses the target.
|
|
30
|
+
*/
|
|
31
|
+
export declare function minimumZeroFailureSamples(targetEpsilon: number, alpha: number): number;
|
|
32
|
+
/**
|
|
33
|
+
* Bonferroni split for `thresholds × groups` comparisons on one validation set.
|
|
34
|
+
*
|
|
35
|
+
* Searching many thresholds and reporting the best keeps none of a single
|
|
36
|
+
* interval's nominal guarantee; this is the conservative correction, and it
|
|
37
|
+
* raises the required sample size on purpose.
|
|
38
|
+
*/
|
|
39
|
+
export declare function bonferroniAlpha(alpha: number, thresholds: number, groups: number): number;
|
|
40
|
+
/**
|
|
41
|
+
* Union bound over per-step failure risks.
|
|
42
|
+
*
|
|
43
|
+
* Holds without any independence assumption, which is the point: step risks in
|
|
44
|
+
* one task are usually correlated, so multiplying them would understate the
|
|
45
|
+
* whole-task risk.
|
|
46
|
+
*/
|
|
47
|
+
export declare function unionBoundRisk(stepRisks: readonly number[]): number;
|
|
48
|
+
//# sourceMappingURL=risk.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"risk.d.ts","sourceRoot":"","sources":["../../src/metacognition/risk.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAyDH,4CAA4C;AAC5C,wBAAgB,yBAAyB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAOjF;AAqBD;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAShG;AAED,4EAA4E;AAC5E,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAI3E;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,aAAa,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAUtF;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAKzF;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAWnE","sourcesContent":["/**\n * Finite-sample risk bounds for automation gating (Jev audit algorithm A4).\n *\n * A point estimate must never widen automation scope. Two failures in a\n * hundred is not \"a 2% error rate\" — its one-sided 95% Clopper–Pearson upper\n * bound is about 6.2%, and that bound is what a gate reads.\n *\n * Scope: this bounds the failure probability of samples drawn under the stated\n * conditions. It is not a safety guarantee for the next action, and it assumes\n * a fixed policy, a consistent failure event, and adequately independent\n * samples. Three hundred repeated clicks inside one task are not three hundred\n * independent trials; cluster by task or environment instance before using it.\n */\n\nimport { ensure } from \"./validation.ts\";\n\nconst LANCZOS_G = 7;\nconst LANCZOS_COEFFICIENTS = [\n\t0.999_999_999_999_809_93, 676.520_368_121_885_1, -1259.139_216_722_402_8, 771.323_428_777_653_13,\n\t-176.615_029_162_140_59, 12.507_343_278_686_905, -0.138_571_095_265_720_12, 9.984_369_578_019_571_6e-6,\n\t1.505_632_735_149_311_6e-7,\n] as const;\n\nfunction logGamma(x: number): number {\n\tif (x < 0.5) return Math.log(Math.PI / Math.sin(Math.PI * x)) - logGamma(1 - x);\n\tconst z = x - 1;\n\tlet a = LANCZOS_COEFFICIENTS[0];\n\tconst t = z + LANCZOS_G + 0.5;\n\tfor (const [index, coefficient] of LANCZOS_COEFFICIENTS.entries()) {\n\t\tif (index > 0) a += coefficient / (z + index);\n\t}\n\treturn 0.5 * Math.log(2 * Math.PI) + (z + 0.5) * Math.log(t) - t + Math.log(a);\n}\n\n/** Continued-fraction expansion for the incomplete beta (Lentz's method). */\nfunction betaContinuedFraction(a: number, b: number, x: number): number {\n\tconst maxIterations = 300;\n\tconst epsilon = 3e-16;\n\tconst tiny = 1e-300;\n\tconst qab = a + b;\n\tconst qap = a + 1;\n\tconst qam = a - 1;\n\tlet c = 1;\n\tlet d = 1 - (qab * x) / qap;\n\tif (Math.abs(d) < tiny) d = tiny;\n\td = 1 / d;\n\tlet h = d;\n\tfor (let m = 1; m <= maxIterations; m += 1) {\n\t\tconst m2 = 2 * m;\n\t\tlet aa = (m * (b - m) * x) / ((qam + m2) * (a + m2));\n\t\td = 1 + aa * d;\n\t\tif (Math.abs(d) < tiny) d = tiny;\n\t\tc = 1 + aa / c;\n\t\tif (Math.abs(c) < tiny) c = tiny;\n\t\td = 1 / d;\n\t\th *= d * c;\n\t\taa = (-(a + m) * (qab + m) * x) / ((a + m2) * (qap + m2));\n\t\td = 1 + aa * d;\n\t\tif (Math.abs(d) < tiny) d = tiny;\n\t\tc = 1 + aa / c;\n\t\tif (Math.abs(c) < tiny) c = tiny;\n\t\td = 1 / d;\n\t\tconst delta = d * c;\n\t\th *= delta;\n\t\tif (Math.abs(delta - 1) < epsilon) break;\n\t}\n\treturn h;\n}\n\n/** Regularized incomplete beta I_x(a,b). */\nexport function regularizedIncompleteBeta(a: number, b: number, x: number): number {\n\tif (x <= 0) return 0;\n\tif (x >= 1) return 1;\n\tconst front = Math.exp(logGamma(a + b) - logGamma(a) - logGamma(b) + a * Math.log(x) + b * Math.log1p(-x));\n\treturn x < (a + 1) / (a + b + 2)\n\t\t? (front * betaContinuedFraction(a, b, x)) / a\n\t\t: 1 - (front * betaContinuedFraction(b, a, 1 - x)) / b;\n}\n\n/** Inverse of {@link regularizedIncompleteBeta} by bisection; I_x is monotone in x. */\nfunction betaQuantile(p: number, a: number, b: number): number {\n\tlet low = 0;\n\tlet high = 1;\n\tfor (let i = 0; i < 200 && high - low > 1e-15; i += 1) {\n\t\tconst mid = (low + high) / 2;\n\t\tif (regularizedIncompleteBeta(a, b, mid) < p) low = mid;\n\t\telse high = mid;\n\t}\n\treturn (low + high) / 2;\n}\n\nfunction assertAlpha(alpha: number): void {\n\tensure(\n\t\ttypeof alpha === \"number\" && Number.isFinite(alpha) && alpha > 0 && alpha < 1,\n\t\t\"alpha must be a probability strictly between 0 and 1\",\n\t);\n}\n\n/**\n * One-sided Clopper–Pearson upper bound on the failure probability.\n *\n * `U(k,n) = Beta⁻¹(1−α; k+1, n−k)` for `0 ≤ k < n`, and `1` when every trial\n * failed. Zero trials is not zero risk: it is absent evidence, so it throws.\n */\nexport function clopperPearsonUpperBound(failures: number, trials: number, alpha: number): number {\n\tensure(Number.isSafeInteger(trials) && trials > 0, \"insufficient evidence: trials must be a positive integer\");\n\tensure(\n\t\tNumber.isSafeInteger(failures) && failures >= 0 && failures <= trials,\n\t\t\"failures must be an integer in [0, trials]\",\n\t);\n\tassertAlpha(alpha);\n\tif (failures === trials) return 1;\n\treturn betaQuantile(1 - alpha, failures + 1, trials - failures);\n}\n\n/** Closed form of {@link clopperPearsonUpperBound} when no trial failed. */\nexport function zeroFailureUpperBound(trials: number, alpha: number): number {\n\tensure(Number.isSafeInteger(trials) && trials > 0, \"insufficient evidence: trials must be a positive integer\");\n\tassertAlpha(alpha);\n\treturn -Math.expm1(Math.log(alpha) / trials);\n}\n\n/**\n * Smallest failure-free sample size whose upper bound meets `targetEpsilon`.\n *\n * `n ≥ ⌈log α / log(1−ε)⌉`, then nudged against the bound itself so a\n * floating-point boundary cannot return a sample size that misses the target.\n */\nexport function minimumZeroFailureSamples(targetEpsilon: number, alpha: number): number {\n\tensure(\n\t\ttypeof targetEpsilon === \"number\" && Number.isFinite(targetEpsilon) && targetEpsilon > 0 && targetEpsilon < 1,\n\t\t\"targetEpsilon must be strictly between 0 and 1\",\n\t);\n\tassertAlpha(alpha);\n\tlet n = Math.max(1, Math.ceil(Math.log(alpha) / Math.log1p(-targetEpsilon)));\n\twhile (zeroFailureUpperBound(n, alpha) > targetEpsilon) n += 1;\n\twhile (n > 1 && zeroFailureUpperBound(n - 1, alpha) <= targetEpsilon) n -= 1;\n\treturn n;\n}\n\n/**\n * Bonferroni split for `thresholds × groups` comparisons on one validation set.\n *\n * Searching many thresholds and reporting the best keeps none of a single\n * interval's nominal guarantee; this is the conservative correction, and it\n * raises the required sample size on purpose.\n */\nexport function bonferroniAlpha(alpha: number, thresholds: number, groups: number): number {\n\tassertAlpha(alpha);\n\tensure(Number.isSafeInteger(thresholds) && thresholds > 0, \"thresholds must be a positive integer\");\n\tensure(Number.isSafeInteger(groups) && groups > 0, \"groups must be a positive integer\");\n\treturn alpha / (thresholds * groups);\n}\n\n/**\n * Union bound over per-step failure risks.\n *\n * Holds without any independence assumption, which is the point: step risks in\n * one task are usually correlated, so multiplying them would understate the\n * whole-task risk.\n */\nexport function unionBoundRisk(stepRisks: readonly number[]): number {\n\tensure(Array.isArray(stepRisks) && stepRisks.length > 0, \"stepRisks must be a non-empty array\");\n\tlet total = 0;\n\tfor (const risk of stepRisks) {\n\t\tensure(\n\t\t\ttypeof risk === \"number\" && Number.isFinite(risk) && risk >= 0 && risk <= 1,\n\t\t\t\"each step risk must be a probability in [0, 1]\",\n\t\t);\n\t\ttotal += risk;\n\t}\n\treturn Math.min(1, total);\n}\n"]}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finite-sample risk bounds for automation gating (Jev audit algorithm A4).
|
|
3
|
+
*
|
|
4
|
+
* A point estimate must never widen automation scope. Two failures in a
|
|
5
|
+
* hundred is not "a 2% error rate" — its one-sided 95% Clopper–Pearson upper
|
|
6
|
+
* bound is about 6.2%, and that bound is what a gate reads.
|
|
7
|
+
*
|
|
8
|
+
* Scope: this bounds the failure probability of samples drawn under the stated
|
|
9
|
+
* conditions. It is not a safety guarantee for the next action, and it assumes
|
|
10
|
+
* a fixed policy, a consistent failure event, and adequately independent
|
|
11
|
+
* samples. Three hundred repeated clicks inside one task are not three hundred
|
|
12
|
+
* independent trials; cluster by task or environment instance before using it.
|
|
13
|
+
*/
|
|
14
|
+
import { ensure } from "./validation.js";
|
|
15
|
+
const LANCZOS_G = 7;
|
|
16
|
+
const LANCZOS_COEFFICIENTS = [
|
|
17
|
+
0.999_999_999_999_809_93, 676.520_368_121_885_1, -1259.139_216_722_402_8, 771.323_428_777_653_13,
|
|
18
|
+
-176.615_029_162_140_59, 12.507_343_278_686_905, -0.138_571_095_265_720_12, 9.984_369_578_019_571_6e-6,
|
|
19
|
+
1.505_632_735_149_311_6e-7,
|
|
20
|
+
];
|
|
21
|
+
function logGamma(x) {
|
|
22
|
+
if (x < 0.5)
|
|
23
|
+
return Math.log(Math.PI / Math.sin(Math.PI * x)) - logGamma(1 - x);
|
|
24
|
+
const z = x - 1;
|
|
25
|
+
let a = LANCZOS_COEFFICIENTS[0];
|
|
26
|
+
const t = z + LANCZOS_G + 0.5;
|
|
27
|
+
for (const [index, coefficient] of LANCZOS_COEFFICIENTS.entries()) {
|
|
28
|
+
if (index > 0)
|
|
29
|
+
a += coefficient / (z + index);
|
|
30
|
+
}
|
|
31
|
+
return 0.5 * Math.log(2 * Math.PI) + (z + 0.5) * Math.log(t) - t + Math.log(a);
|
|
32
|
+
}
|
|
33
|
+
/** Continued-fraction expansion for the incomplete beta (Lentz's method). */
|
|
34
|
+
function betaContinuedFraction(a, b, x) {
|
|
35
|
+
const maxIterations = 300;
|
|
36
|
+
const epsilon = 3e-16;
|
|
37
|
+
const tiny = 1e-300;
|
|
38
|
+
const qab = a + b;
|
|
39
|
+
const qap = a + 1;
|
|
40
|
+
const qam = a - 1;
|
|
41
|
+
let c = 1;
|
|
42
|
+
let d = 1 - (qab * x) / qap;
|
|
43
|
+
if (Math.abs(d) < tiny)
|
|
44
|
+
d = tiny;
|
|
45
|
+
d = 1 / d;
|
|
46
|
+
let h = d;
|
|
47
|
+
for (let m = 1; m <= maxIterations; m += 1) {
|
|
48
|
+
const m2 = 2 * m;
|
|
49
|
+
let aa = (m * (b - m) * x) / ((qam + m2) * (a + m2));
|
|
50
|
+
d = 1 + aa * d;
|
|
51
|
+
if (Math.abs(d) < tiny)
|
|
52
|
+
d = tiny;
|
|
53
|
+
c = 1 + aa / c;
|
|
54
|
+
if (Math.abs(c) < tiny)
|
|
55
|
+
c = tiny;
|
|
56
|
+
d = 1 / d;
|
|
57
|
+
h *= d * c;
|
|
58
|
+
aa = (-(a + m) * (qab + m) * x) / ((a + m2) * (qap + m2));
|
|
59
|
+
d = 1 + aa * d;
|
|
60
|
+
if (Math.abs(d) < tiny)
|
|
61
|
+
d = tiny;
|
|
62
|
+
c = 1 + aa / c;
|
|
63
|
+
if (Math.abs(c) < tiny)
|
|
64
|
+
c = tiny;
|
|
65
|
+
d = 1 / d;
|
|
66
|
+
const delta = d * c;
|
|
67
|
+
h *= delta;
|
|
68
|
+
if (Math.abs(delta - 1) < epsilon)
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
return h;
|
|
72
|
+
}
|
|
73
|
+
/** Regularized incomplete beta I_x(a,b). */
|
|
74
|
+
export function regularizedIncompleteBeta(a, b, x) {
|
|
75
|
+
if (x <= 0)
|
|
76
|
+
return 0;
|
|
77
|
+
if (x >= 1)
|
|
78
|
+
return 1;
|
|
79
|
+
const front = Math.exp(logGamma(a + b) - logGamma(a) - logGamma(b) + a * Math.log(x) + b * Math.log1p(-x));
|
|
80
|
+
return x < (a + 1) / (a + b + 2)
|
|
81
|
+
? (front * betaContinuedFraction(a, b, x)) / a
|
|
82
|
+
: 1 - (front * betaContinuedFraction(b, a, 1 - x)) / b;
|
|
83
|
+
}
|
|
84
|
+
/** Inverse of {@link regularizedIncompleteBeta} by bisection; I_x is monotone in x. */
|
|
85
|
+
function betaQuantile(p, a, b) {
|
|
86
|
+
let low = 0;
|
|
87
|
+
let high = 1;
|
|
88
|
+
for (let i = 0; i < 200 && high - low > 1e-15; i += 1) {
|
|
89
|
+
const mid = (low + high) / 2;
|
|
90
|
+
if (regularizedIncompleteBeta(a, b, mid) < p)
|
|
91
|
+
low = mid;
|
|
92
|
+
else
|
|
93
|
+
high = mid;
|
|
94
|
+
}
|
|
95
|
+
return (low + high) / 2;
|
|
96
|
+
}
|
|
97
|
+
function assertAlpha(alpha) {
|
|
98
|
+
ensure(typeof alpha === "number" && Number.isFinite(alpha) && alpha > 0 && alpha < 1, "alpha must be a probability strictly between 0 and 1");
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* One-sided Clopper–Pearson upper bound on the failure probability.
|
|
102
|
+
*
|
|
103
|
+
* `U(k,n) = Beta⁻¹(1−α; k+1, n−k)` for `0 ≤ k < n`, and `1` when every trial
|
|
104
|
+
* failed. Zero trials is not zero risk: it is absent evidence, so it throws.
|
|
105
|
+
*/
|
|
106
|
+
export function clopperPearsonUpperBound(failures, trials, alpha) {
|
|
107
|
+
ensure(Number.isSafeInteger(trials) && trials > 0, "insufficient evidence: trials must be a positive integer");
|
|
108
|
+
ensure(Number.isSafeInteger(failures) && failures >= 0 && failures <= trials, "failures must be an integer in [0, trials]");
|
|
109
|
+
assertAlpha(alpha);
|
|
110
|
+
if (failures === trials)
|
|
111
|
+
return 1;
|
|
112
|
+
return betaQuantile(1 - alpha, failures + 1, trials - failures);
|
|
113
|
+
}
|
|
114
|
+
/** Closed form of {@link clopperPearsonUpperBound} when no trial failed. */
|
|
115
|
+
export function zeroFailureUpperBound(trials, alpha) {
|
|
116
|
+
ensure(Number.isSafeInteger(trials) && trials > 0, "insufficient evidence: trials must be a positive integer");
|
|
117
|
+
assertAlpha(alpha);
|
|
118
|
+
return -Math.expm1(Math.log(alpha) / trials);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Smallest failure-free sample size whose upper bound meets `targetEpsilon`.
|
|
122
|
+
*
|
|
123
|
+
* `n ≥ ⌈log α / log(1−ε)⌉`, then nudged against the bound itself so a
|
|
124
|
+
* floating-point boundary cannot return a sample size that misses the target.
|
|
125
|
+
*/
|
|
126
|
+
export function minimumZeroFailureSamples(targetEpsilon, alpha) {
|
|
127
|
+
ensure(typeof targetEpsilon === "number" && Number.isFinite(targetEpsilon) && targetEpsilon > 0 && targetEpsilon < 1, "targetEpsilon must be strictly between 0 and 1");
|
|
128
|
+
assertAlpha(alpha);
|
|
129
|
+
let n = Math.max(1, Math.ceil(Math.log(alpha) / Math.log1p(-targetEpsilon)));
|
|
130
|
+
while (zeroFailureUpperBound(n, alpha) > targetEpsilon)
|
|
131
|
+
n += 1;
|
|
132
|
+
while (n > 1 && zeroFailureUpperBound(n - 1, alpha) <= targetEpsilon)
|
|
133
|
+
n -= 1;
|
|
134
|
+
return n;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Bonferroni split for `thresholds × groups` comparisons on one validation set.
|
|
138
|
+
*
|
|
139
|
+
* Searching many thresholds and reporting the best keeps none of a single
|
|
140
|
+
* interval's nominal guarantee; this is the conservative correction, and it
|
|
141
|
+
* raises the required sample size on purpose.
|
|
142
|
+
*/
|
|
143
|
+
export function bonferroniAlpha(alpha, thresholds, groups) {
|
|
144
|
+
assertAlpha(alpha);
|
|
145
|
+
ensure(Number.isSafeInteger(thresholds) && thresholds > 0, "thresholds must be a positive integer");
|
|
146
|
+
ensure(Number.isSafeInteger(groups) && groups > 0, "groups must be a positive integer");
|
|
147
|
+
return alpha / (thresholds * groups);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Union bound over per-step failure risks.
|
|
151
|
+
*
|
|
152
|
+
* Holds without any independence assumption, which is the point: step risks in
|
|
153
|
+
* one task are usually correlated, so multiplying them would understate the
|
|
154
|
+
* whole-task risk.
|
|
155
|
+
*/
|
|
156
|
+
export function unionBoundRisk(stepRisks) {
|
|
157
|
+
ensure(Array.isArray(stepRisks) && stepRisks.length > 0, "stepRisks must be a non-empty array");
|
|
158
|
+
let total = 0;
|
|
159
|
+
for (const risk of stepRisks) {
|
|
160
|
+
ensure(typeof risk === "number" && Number.isFinite(risk) && risk >= 0 && risk <= 1, "each step risk must be a probability in [0, 1]");
|
|
161
|
+
total += risk;
|
|
162
|
+
}
|
|
163
|
+
return Math.min(1, total);
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=risk.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"risk.js","sourceRoot":"","sources":["../../src/metacognition/risk.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Finite-sample risk bounds for automation gating (Jev audit algorithm A4).\n *\n * A point estimate must never widen automation scope. Two failures in a\n * hundred is not \"a 2% error rate\" — its one-sided 95% Clopper–Pearson upper\n * bound is about 6.2%, and that bound is what a gate reads.\n *\n * Scope: this bounds the failure probability of samples drawn under the stated\n * conditions. It is not a safety guarantee for the next action, and it assumes\n * a fixed policy, a consistent failure event, and adequately independent\n * samples. Three hundred repeated clicks inside one task are not three hundred\n * independent trials; cluster by task or environment instance before using it.\n */\n\nimport { ensure } from \"./validation.ts\";\n\nconst LANCZOS_G = 7;\nconst LANCZOS_COEFFICIENTS = [\n\t0.999_999_999_999_809_93, 676.520_368_121_885_1, -1259.139_216_722_402_8, 771.323_428_777_653_13,\n\t-176.615_029_162_140_59, 12.507_343_278_686_905, -0.138_571_095_265_720_12, 9.984_369_578_019_571_6e-6,\n\t1.505_632_735_149_311_6e-7,\n] as const;\n\nfunction logGamma(x: number): number {\n\tif (x < 0.5) return Math.log(Math.PI / Math.sin(Math.PI * x)) - logGamma(1 - x);\n\tconst z = x - 1;\n\tlet a = LANCZOS_COEFFICIENTS[0];\n\tconst t = z + LANCZOS_G + 0.5;\n\tfor (const [index, coefficient] of LANCZOS_COEFFICIENTS.entries()) {\n\t\tif (index > 0) a += coefficient / (z + index);\n\t}\n\treturn 0.5 * Math.log(2 * Math.PI) + (z + 0.5) * Math.log(t) - t + Math.log(a);\n}\n\n/** Continued-fraction expansion for the incomplete beta (Lentz's method). */\nfunction betaContinuedFraction(a: number, b: number, x: number): number {\n\tconst maxIterations = 300;\n\tconst epsilon = 3e-16;\n\tconst tiny = 1e-300;\n\tconst qab = a + b;\n\tconst qap = a + 1;\n\tconst qam = a - 1;\n\tlet c = 1;\n\tlet d = 1 - (qab * x) / qap;\n\tif (Math.abs(d) < tiny) d = tiny;\n\td = 1 / d;\n\tlet h = d;\n\tfor (let m = 1; m <= maxIterations; m += 1) {\n\t\tconst m2 = 2 * m;\n\t\tlet aa = (m * (b - m) * x) / ((qam + m2) * (a + m2));\n\t\td = 1 + aa * d;\n\t\tif (Math.abs(d) < tiny) d = tiny;\n\t\tc = 1 + aa / c;\n\t\tif (Math.abs(c) < tiny) c = tiny;\n\t\td = 1 / d;\n\t\th *= d * c;\n\t\taa = (-(a + m) * (qab + m) * x) / ((a + m2) * (qap + m2));\n\t\td = 1 + aa * d;\n\t\tif (Math.abs(d) < tiny) d = tiny;\n\t\tc = 1 + aa / c;\n\t\tif (Math.abs(c) < tiny) c = tiny;\n\t\td = 1 / d;\n\t\tconst delta = d * c;\n\t\th *= delta;\n\t\tif (Math.abs(delta - 1) < epsilon) break;\n\t}\n\treturn h;\n}\n\n/** Regularized incomplete beta I_x(a,b). */\nexport function regularizedIncompleteBeta(a: number, b: number, x: number): number {\n\tif (x <= 0) return 0;\n\tif (x >= 1) return 1;\n\tconst front = Math.exp(logGamma(a + b) - logGamma(a) - logGamma(b) + a * Math.log(x) + b * Math.log1p(-x));\n\treturn x < (a + 1) / (a + b + 2)\n\t\t? (front * betaContinuedFraction(a, b, x)) / a\n\t\t: 1 - (front * betaContinuedFraction(b, a, 1 - x)) / b;\n}\n\n/** Inverse of {@link regularizedIncompleteBeta} by bisection; I_x is monotone in x. */\nfunction betaQuantile(p: number, a: number, b: number): number {\n\tlet low = 0;\n\tlet high = 1;\n\tfor (let i = 0; i < 200 && high - low > 1e-15; i += 1) {\n\t\tconst mid = (low + high) / 2;\n\t\tif (regularizedIncompleteBeta(a, b, mid) < p) low = mid;\n\t\telse high = mid;\n\t}\n\treturn (low + high) / 2;\n}\n\nfunction assertAlpha(alpha: number): void {\n\tensure(\n\t\ttypeof alpha === \"number\" && Number.isFinite(alpha) && alpha > 0 && alpha < 1,\n\t\t\"alpha must be a probability strictly between 0 and 1\",\n\t);\n}\n\n/**\n * One-sided Clopper–Pearson upper bound on the failure probability.\n *\n * `U(k,n) = Beta⁻¹(1−α; k+1, n−k)` for `0 ≤ k < n`, and `1` when every trial\n * failed. Zero trials is not zero risk: it is absent evidence, so it throws.\n */\nexport function clopperPearsonUpperBound(failures: number, trials: number, alpha: number): number {\n\tensure(Number.isSafeInteger(trials) && trials > 0, \"insufficient evidence: trials must be a positive integer\");\n\tensure(\n\t\tNumber.isSafeInteger(failures) && failures >= 0 && failures <= trials,\n\t\t\"failures must be an integer in [0, trials]\",\n\t);\n\tassertAlpha(alpha);\n\tif (failures === trials) return 1;\n\treturn betaQuantile(1 - alpha, failures + 1, trials - failures);\n}\n\n/** Closed form of {@link clopperPearsonUpperBound} when no trial failed. */\nexport function zeroFailureUpperBound(trials: number, alpha: number): number {\n\tensure(Number.isSafeInteger(trials) && trials > 0, \"insufficient evidence: trials must be a positive integer\");\n\tassertAlpha(alpha);\n\treturn -Math.expm1(Math.log(alpha) / trials);\n}\n\n/**\n * Smallest failure-free sample size whose upper bound meets `targetEpsilon`.\n *\n * `n ≥ ⌈log α / log(1−ε)⌉`, then nudged against the bound itself so a\n * floating-point boundary cannot return a sample size that misses the target.\n */\nexport function minimumZeroFailureSamples(targetEpsilon: number, alpha: number): number {\n\tensure(\n\t\ttypeof targetEpsilon === \"number\" && Number.isFinite(targetEpsilon) && targetEpsilon > 0 && targetEpsilon < 1,\n\t\t\"targetEpsilon must be strictly between 0 and 1\",\n\t);\n\tassertAlpha(alpha);\n\tlet n = Math.max(1, Math.ceil(Math.log(alpha) / Math.log1p(-targetEpsilon)));\n\twhile (zeroFailureUpperBound(n, alpha) > targetEpsilon) n += 1;\n\twhile (n > 1 && zeroFailureUpperBound(n - 1, alpha) <= targetEpsilon) n -= 1;\n\treturn n;\n}\n\n/**\n * Bonferroni split for `thresholds × groups` comparisons on one validation set.\n *\n * Searching many thresholds and reporting the best keeps none of a single\n * interval's nominal guarantee; this is the conservative correction, and it\n * raises the required sample size on purpose.\n */\nexport function bonferroniAlpha(alpha: number, thresholds: number, groups: number): number {\n\tassertAlpha(alpha);\n\tensure(Number.isSafeInteger(thresholds) && thresholds > 0, \"thresholds must be a positive integer\");\n\tensure(Number.isSafeInteger(groups) && groups > 0, \"groups must be a positive integer\");\n\treturn alpha / (thresholds * groups);\n}\n\n/**\n * Union bound over per-step failure risks.\n *\n * Holds without any independence assumption, which is the point: step risks in\n * one task are usually correlated, so multiplying them would understate the\n * whole-task risk.\n */\nexport function unionBoundRisk(stepRisks: readonly number[]): number {\n\tensure(Array.isArray(stepRisks) && stepRisks.length > 0, \"stepRisks must be a non-empty array\");\n\tlet total = 0;\n\tfor (const risk of stepRisks) {\n\t\tensure(\n\t\t\ttypeof risk === \"number\" && Number.isFinite(risk) && risk >= 0 && risk <= 1,\n\t\t\t\"each step risk must be a probability in [0, 1]\",\n\t\t);\n\t\ttotal += risk;\n\t}\n\treturn Math.min(1, total);\n}\n"]}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cost- and latency-aware route selection (Jev audit algorithm A5).
|
|
3
|
+
*
|
|
4
|
+
* Adding a selector call only pays if it *replaces* work. Inserting one in
|
|
5
|
+
* front of an existing free-text step adds a semantic inference instead of
|
|
6
|
+
* removing one, so routes are compared on a single utility:
|
|
7
|
+
*
|
|
8
|
+
* U_r = q_r − λ_C·(C_r/C_0) − λ_L·(L_r/L_0)
|
|
9
|
+
*
|
|
10
|
+
* Safety and permission are deliberately not terms in that utility. They are a
|
|
11
|
+
* hard filter, because a cheap unsafe route must never win on weights.
|
|
12
|
+
*
|
|
13
|
+
* Latency is measured over the whole step, not the model call: when operator
|
|
14
|
+
* approval dominates, a faster decision step barely moves the total. Amdahl's
|
|
15
|
+
* bound is included so that limit is explicit rather than assumed away.
|
|
16
|
+
*/
|
|
17
|
+
export interface RouteCandidate {
|
|
18
|
+
readonly id: string;
|
|
19
|
+
/** Probability this route completes the step correctly. */
|
|
20
|
+
readonly completionProbability: number;
|
|
21
|
+
readonly costUsd: number;
|
|
22
|
+
readonly latencyMs: number;
|
|
23
|
+
/** Policy and permission verdict. A false value is a veto, not a penalty. */
|
|
24
|
+
readonly approved: boolean;
|
|
25
|
+
}
|
|
26
|
+
export interface RouteUnits {
|
|
27
|
+
readonly costUnit: number;
|
|
28
|
+
readonly latencyUnit: number;
|
|
29
|
+
readonly costWeight: number;
|
|
30
|
+
readonly latencyWeight: number;
|
|
31
|
+
}
|
|
32
|
+
/** Dimensionless utility; cost and latency are normalized before weighting. */
|
|
33
|
+
export declare function routeUtility(route: RouteCandidate, units: RouteUnits): number;
|
|
34
|
+
/**
|
|
35
|
+
* Highest-utility approved route, or null when nothing is approved.
|
|
36
|
+
*
|
|
37
|
+
* Returning null rather than the best unapproved route keeps "we may not do
|
|
38
|
+
* this" distinct from "this is expensive".
|
|
39
|
+
*/
|
|
40
|
+
export declare function selectRoute(routes: readonly RouteCandidate[], units: RouteUnits): RouteCandidate | null;
|
|
41
|
+
export interface StepPhases {
|
|
42
|
+
readonly queueMs: number;
|
|
43
|
+
readonly observeMs: number;
|
|
44
|
+
readonly packMs: number;
|
|
45
|
+
readonly decideMs: number;
|
|
46
|
+
readonly approvalMs: number;
|
|
47
|
+
readonly executeMs: number;
|
|
48
|
+
readonly verifyMs: number;
|
|
49
|
+
readonly recoveryMs: number;
|
|
50
|
+
}
|
|
51
|
+
/** Whole-step duration. Model response time is one term among eight. */
|
|
52
|
+
export declare function stepDuration(phases: StepPhases): number;
|
|
53
|
+
/**
|
|
54
|
+
* Amdahl bound: S = 1 / ((1−f) + f/s).
|
|
55
|
+
*
|
|
56
|
+
* `speedup` may be Infinity to ask what an instantaneous step would buy — the
|
|
57
|
+
* answer is still capped by the fraction it occupies, which is the point.
|
|
58
|
+
*/
|
|
59
|
+
export declare function overallSpeedup(improvableFraction: number, speedup: number): number;
|
|
60
|
+
export interface FallbackCosts {
|
|
61
|
+
readonly selectorCost: number;
|
|
62
|
+
readonly verificationCost: number;
|
|
63
|
+
readonly fallbackProbability: number;
|
|
64
|
+
readonly fallbackCost: number;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* E[C] = c_J + c_V + p_F·c_L.
|
|
68
|
+
*
|
|
69
|
+
* A cost decomposition, not an independence claim. Compare it against the
|
|
70
|
+
* incumbent path's cost under the same success and safety conditions; if it is
|
|
71
|
+
* larger, the cheap path is not cheap.
|
|
72
|
+
*/
|
|
73
|
+
export declare function fallbackExpectedCost(costs: FallbackCosts): number;
|
|
74
|
+
export interface ReselectionInput {
|
|
75
|
+
/** Attempts already spent on this observation fingerprint. */
|
|
76
|
+
readonly attemptsForFingerprint: number;
|
|
77
|
+
readonly maxAttempts: number;
|
|
78
|
+
/** True when recovery changed the cause, not merely retried the same question. */
|
|
79
|
+
readonly causeChanged: boolean;
|
|
80
|
+
}
|
|
81
|
+
export type ReselectionDecision = {
|
|
82
|
+
readonly allowed: true;
|
|
83
|
+
} | {
|
|
84
|
+
readonly allowed: false;
|
|
85
|
+
readonly reason: "attempt-budget-exhausted";
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Damp selector/model ping-pong on one observation generation.
|
|
89
|
+
*
|
|
90
|
+
* Re-asking the same question about the same state only adds calls. A further
|
|
91
|
+
* attempt is admitted when the budget remains, or when recovery genuinely
|
|
92
|
+
* changed the cause. The budget is a configured value, not a claimed optimum.
|
|
93
|
+
*/
|
|
94
|
+
export declare function reselectionAllowed(input: ReselectionInput): ReselectionDecision;
|
|
95
|
+
//# sourceMappingURL=route-economics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-economics.d.ts","sourceRoot":"","sources":["../../src/metacognition/route-economics.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,2DAA2D;IAC3D,QAAQ,CAAC,qBAAqB,EAAE,MAAM,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,6EAA6E;IAC7E,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAC/B;AASD,+EAA+E;AAC/E,wBAAgB,YAAY,CAAC,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,UAAU,GAAG,MAAM,CAe7E;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,SAAS,cAAc,EAAE,EAAE,KAAK,EAAE,UAAU,GAAG,cAAc,GAAG,IAAI,CAcvG;AAED,MAAM,WAAW,UAAU;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC5B;AAED,wEAAwE;AACxE,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAOvD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,kBAAkB,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CASlF;AAED,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAYjE;AAED,MAAM,WAAW,gBAAgB;IAChC,8DAA8D;IAC9D,QAAQ,CAAC,sBAAsB,EAAE,MAAM,CAAC;IACxC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,kFAAkF;IAClF,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;CAC/B;AAED,MAAM,MAAM,mBAAmB,GAC5B;IAAE,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAA;CAAE,GAC1B;IAAE,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,0BAA0B,CAAA;CAAE,CAAC;AAE5E;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,gBAAgB,GAAG,mBAAmB,CAS/E","sourcesContent":["/**\n * Cost- and latency-aware route selection (Jev audit algorithm A5).\n *\n * Adding a selector call only pays if it *replaces* work. Inserting one in\n * front of an existing free-text step adds a semantic inference instead of\n * removing one, so routes are compared on a single utility:\n *\n * U_r = q_r − λ_C·(C_r/C_0) − λ_L·(L_r/L_0)\n *\n * Safety and permission are deliberately not terms in that utility. They are a\n * hard filter, because a cheap unsafe route must never win on weights.\n *\n * Latency is measured over the whole step, not the model call: when operator\n * approval dominates, a faster decision step barely moves the total. Amdahl's\n * bound is included so that limit is explicit rather than assumed away.\n */\n\nimport { ensure } from \"./validation.ts\";\n\nexport interface RouteCandidate {\n\treadonly id: string;\n\t/** Probability this route completes the step correctly. */\n\treadonly completionProbability: number;\n\treadonly costUsd: number;\n\treadonly latencyMs: number;\n\t/** Policy and permission verdict. A false value is a veto, not a penalty. */\n\treadonly approved: boolean;\n}\n\nexport interface RouteUnits {\n\treadonly costUnit: number;\n\treadonly latencyUnit: number;\n\treadonly costWeight: number;\n\treadonly latencyWeight: number;\n}\n\nfunction assertUnits(units: RouteUnits): void {\n\tensure(Number.isFinite(units.costUnit) && units.costUnit > 0, \"costUnit must be positive\");\n\tensure(Number.isFinite(units.latencyUnit) && units.latencyUnit > 0, \"latencyUnit must be positive\");\n\tensure(Number.isFinite(units.costWeight) && units.costWeight >= 0, \"costWeight must be nonnegative\");\n\tensure(Number.isFinite(units.latencyWeight) && units.latencyWeight >= 0, \"latencyWeight must be nonnegative\");\n}\n\n/** Dimensionless utility; cost and latency are normalized before weighting. */\nexport function routeUtility(route: RouteCandidate, units: RouteUnits): number {\n\tensure(\n\t\tNumber.isFinite(route.completionProbability) &&\n\t\t\troute.completionProbability >= 0 &&\n\t\t\troute.completionProbability <= 1,\n\t\t\"completionProbability must be in [0,1]\",\n\t);\n\tensure(Number.isFinite(route.costUsd) && route.costUsd >= 0, \"costUsd must be nonnegative\");\n\tensure(Number.isFinite(route.latencyMs) && route.latencyMs >= 0, \"latencyMs must be nonnegative\");\n\tassertUnits(units);\n\treturn (\n\t\troute.completionProbability -\n\t\tunits.costWeight * (route.costUsd / units.costUnit) -\n\t\tunits.latencyWeight * (route.latencyMs / units.latencyUnit)\n\t);\n}\n\n/**\n * Highest-utility approved route, or null when nothing is approved.\n *\n * Returning null rather than the best unapproved route keeps \"we may not do\n * this\" distinct from \"this is expensive\".\n */\nexport function selectRoute(routes: readonly RouteCandidate[], units: RouteUnits): RouteCandidate | null {\n\tensure(Array.isArray(routes) && routes.length > 0, \"routes must be a non-empty array\");\n\tlet best: RouteCandidate | undefined;\n\tlet bestUtility = Number.NEGATIVE_INFINITY;\n\tfor (const route of routes) {\n\t\tif (!route.approved) continue;\n\t\tconst utility = routeUtility(route, units);\n\t\tconst better = utility > bestUtility || (utility === bestUtility && best !== undefined && route.id < best.id);\n\t\tif (best === undefined || better) {\n\t\t\tbest = route;\n\t\t\tbestUtility = utility;\n\t\t}\n\t}\n\treturn best ?? null;\n}\n\nexport interface StepPhases {\n\treadonly queueMs: number;\n\treadonly observeMs: number;\n\treadonly packMs: number;\n\treadonly decideMs: number;\n\treadonly approvalMs: number;\n\treadonly executeMs: number;\n\treadonly verifyMs: number;\n\treadonly recoveryMs: number;\n}\n\n/** Whole-step duration. Model response time is one term among eight. */\nexport function stepDuration(phases: StepPhases): number {\n\tlet total = 0;\n\tfor (const [label, value] of Object.entries(phases)) {\n\t\tensure(Number.isFinite(value) && value >= 0, `${label} must be a nonnegative finite number`);\n\t\ttotal += value;\n\t}\n\treturn total;\n}\n\n/**\n * Amdahl bound: S = 1 / ((1−f) + f/s).\n *\n * `speedup` may be Infinity to ask what an instantaneous step would buy — the\n * answer is still capped by the fraction it occupies, which is the point.\n */\nexport function overallSpeedup(improvableFraction: number, speedup: number): number {\n\tensure(\n\t\tNumber.isFinite(improvableFraction) && improvableFraction >= 0 && improvableFraction <= 1,\n\t\t\"improvableFraction must be in [0,1]\",\n\t);\n\tensure(typeof speedup === \"number\" && !Number.isNaN(speedup) && speedup >= 1, \"speedup must be at least 1\");\n\tconst remaining = 1 - improvableFraction;\n\tconst improved = speedup === Number.POSITIVE_INFINITY ? 0 : improvableFraction / speedup;\n\treturn 1 / (remaining + improved);\n}\n\nexport interface FallbackCosts {\n\treadonly selectorCost: number;\n\treadonly verificationCost: number;\n\treadonly fallbackProbability: number;\n\treadonly fallbackCost: number;\n}\n\n/**\n * E[C] = c_J + c_V + p_F·c_L.\n *\n * A cost decomposition, not an independence claim. Compare it against the\n * incumbent path's cost under the same success and safety conditions; if it is\n * larger, the cheap path is not cheap.\n */\nexport function fallbackExpectedCost(costs: FallbackCosts): number {\n\tensure(Number.isFinite(costs.selectorCost) && costs.selectorCost >= 0, \"selectorCost must be nonnegative\");\n\tensure(\n\t\tNumber.isFinite(costs.verificationCost) && costs.verificationCost >= 0,\n\t\t\"verificationCost must be nonnegative\",\n\t);\n\tensure(Number.isFinite(costs.fallbackCost) && costs.fallbackCost >= 0, \"fallbackCost must be nonnegative\");\n\tensure(\n\t\tNumber.isFinite(costs.fallbackProbability) && costs.fallbackProbability >= 0 && costs.fallbackProbability <= 1,\n\t\t\"fallbackProbability must be in [0,1]\",\n\t);\n\treturn costs.selectorCost + costs.verificationCost + costs.fallbackProbability * costs.fallbackCost;\n}\n\nexport interface ReselectionInput {\n\t/** Attempts already spent on this observation fingerprint. */\n\treadonly attemptsForFingerprint: number;\n\treadonly maxAttempts: number;\n\t/** True when recovery changed the cause, not merely retried the same question. */\n\treadonly causeChanged: boolean;\n}\n\nexport type ReselectionDecision =\n\t| { readonly allowed: true }\n\t| { readonly allowed: false; readonly reason: \"attempt-budget-exhausted\" };\n\n/**\n * Damp selector/model ping-pong on one observation generation.\n *\n * Re-asking the same question about the same state only adds calls. A further\n * attempt is admitted when the budget remains, or when recovery genuinely\n * changed the cause. The budget is a configured value, not a claimed optimum.\n */\nexport function reselectionAllowed(input: ReselectionInput): ReselectionDecision {\n\tensure(\n\t\tNumber.isSafeInteger(input.attemptsForFingerprint) && input.attemptsForFingerprint >= 0,\n\t\t\"attemptsForFingerprint must be a nonnegative integer\",\n\t);\n\tensure(Number.isSafeInteger(input.maxAttempts) && input.maxAttempts > 0, \"maxAttempts must be a positive integer\");\n\tif (input.causeChanged) return { allowed: true };\n\tif (input.attemptsForFingerprint < input.maxAttempts) return { allowed: true };\n\treturn { allowed: false, reason: \"attempt-budget-exhausted\" };\n}\n"]}
|