@caupulican/pi-adaptative 0.80.85 → 0.80.88
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 +160 -1
- package/dist/core/agent-session.d.ts +394 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +1862 -46
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/autonomy/approval-gate.d.ts +4 -0
- package/dist/core/autonomy/approval-gate.d.ts.map +1 -0
- package/dist/core/autonomy/approval-gate.js +27 -0
- package/dist/core/autonomy/approval-gate.js.map +1 -0
- package/dist/core/autonomy/bounded-completion.d.ts +27 -0
- package/dist/core/autonomy/bounded-completion.d.ts.map +1 -0
- package/dist/core/autonomy/bounded-completion.js +44 -0
- package/dist/core/autonomy/bounded-completion.js.map +1 -0
- package/dist/core/autonomy/contracts.d.ts +129 -0
- package/dist/core/autonomy/contracts.d.ts.map +1 -0
- package/dist/core/autonomy/contracts.js +2 -0
- package/dist/core/autonomy/contracts.js.map +1 -0
- package/dist/core/autonomy/gates.d.ts +15 -0
- package/dist/core/autonomy/gates.d.ts.map +1 -0
- package/dist/core/autonomy/gates.js +205 -0
- package/dist/core/autonomy/gates.js.map +1 -0
- package/dist/core/autonomy/lane-tracker.d.ts +48 -0
- package/dist/core/autonomy/lane-tracker.d.ts.map +1 -0
- package/dist/core/autonomy/lane-tracker.js +125 -0
- package/dist/core/autonomy/lane-tracker.js.map +1 -0
- package/dist/core/autonomy/path-scope.d.ts +9 -0
- package/dist/core/autonomy/path-scope.d.ts.map +1 -0
- package/dist/core/autonomy/path-scope.js +122 -0
- package/dist/core/autonomy/path-scope.js.map +1 -0
- package/dist/core/autonomy/risk-assessment.d.ts +3 -0
- package/dist/core/autonomy/risk-assessment.d.ts.map +1 -0
- package/dist/core/autonomy/risk-assessment.js +122 -0
- package/dist/core/autonomy/risk-assessment.js.map +1 -0
- package/dist/core/autonomy/session-lane-record.d.ts +10 -0
- package/dist/core/autonomy/session-lane-record.d.ts.map +1 -0
- package/dist/core/autonomy/session-lane-record.js +36 -0
- package/dist/core/autonomy/session-lane-record.js.map +1 -0
- package/dist/core/autonomy/status.d.ts +40 -0
- package/dist/core/autonomy/status.d.ts.map +1 -0
- package/dist/core/autonomy/status.js +107 -0
- package/dist/core/autonomy/status.js.map +1 -0
- package/dist/core/autonomy/subagent-prompt.d.ts +21 -0
- package/dist/core/autonomy/subagent-prompt.d.ts.map +1 -0
- package/dist/core/autonomy/subagent-prompt.js +28 -0
- package/dist/core/autonomy/subagent-prompt.js.map +1 -0
- package/dist/core/autonomy/telemetry-events.d.ts +18 -0
- package/dist/core/autonomy/telemetry-events.d.ts.map +1 -0
- package/dist/core/autonomy/telemetry-events.js +60 -0
- package/dist/core/autonomy/telemetry-events.js.map +1 -0
- package/dist/core/context/artifact-retrieval.d.ts +49 -0
- package/dist/core/context/artifact-retrieval.d.ts.map +1 -0
- package/dist/core/context/artifact-retrieval.js +49 -0
- package/dist/core/context/artifact-retrieval.js.map +1 -0
- package/dist/core/context/context-artifacts.d.ts +94 -0
- package/dist/core/context/context-artifacts.d.ts.map +1 -0
- package/dist/core/context/context-artifacts.js +307 -0
- package/dist/core/context/context-artifacts.js.map +1 -0
- package/dist/core/context/context-audit.d.ts +66 -0
- package/dist/core/context/context-audit.d.ts.map +1 -0
- package/dist/core/context/context-audit.js +173 -0
- package/dist/core/context/context-audit.js.map +1 -0
- package/dist/core/context/context-item.d.ts +117 -0
- package/dist/core/context/context-item.d.ts.map +1 -0
- package/dist/core/context/context-item.js +36 -0
- package/dist/core/context/context-item.js.map +1 -0
- package/dist/core/context/context-prompt-enforcement.d.ts +73 -0
- package/dist/core/context/context-prompt-enforcement.d.ts.map +1 -0
- package/dist/core/context/context-prompt-enforcement.js +153 -0
- package/dist/core/context/context-prompt-enforcement.js.map +1 -0
- package/dist/core/context/context-prompt-policy.d.ts +90 -0
- package/dist/core/context/context-prompt-policy.d.ts.map +1 -0
- package/dist/core/context/context-prompt-policy.js +73 -0
- package/dist/core/context/context-prompt-policy.js.map +1 -0
- package/dist/core/context/context-retention.d.ts +36 -0
- package/dist/core/context/context-retention.d.ts.map +1 -0
- package/dist/core/context/context-retention.js +108 -0
- package/dist/core/context/context-retention.js.map +1 -0
- package/dist/core/context/context-store.d.ts +37 -0
- package/dist/core/context/context-store.d.ts.map +1 -0
- package/dist/core/context/context-store.js +45 -0
- package/dist/core/context/context-store.js.map +1 -0
- package/dist/core/context/memory-diagnostics.d.ts +50 -0
- package/dist/core/context/memory-diagnostics.d.ts.map +1 -0
- package/dist/core/context/memory-diagnostics.js +43 -0
- package/dist/core/context/memory-diagnostics.js.map +1 -0
- package/dist/core/context/memory-index-store.d.ts +28 -0
- package/dist/core/context/memory-index-store.d.ts.map +1 -0
- package/dist/core/context/memory-index-store.js +38 -0
- package/dist/core/context/memory-index-store.js.map +1 -0
- package/dist/core/context/memory-prompt-block.d.ts +34 -0
- package/dist/core/context/memory-prompt-block.d.ts.map +1 -0
- package/dist/core/context/memory-prompt-block.js +58 -0
- package/dist/core/context/memory-prompt-block.js.map +1 -0
- package/dist/core/context/memory-provider-contract.d.ts +114 -0
- package/dist/core/context/memory-provider-contract.d.ts.map +1 -0
- package/dist/core/context/memory-provider-contract.js +121 -0
- package/dist/core/context/memory-provider-contract.js.map +1 -0
- package/dist/core/context/memory-retrieval.d.ts +27 -0
- package/dist/core/context/memory-retrieval.d.ts.map +1 -0
- package/dist/core/context/memory-retrieval.js +91 -0
- package/dist/core/context/memory-retrieval.js.map +1 -0
- package/dist/core/context/okf-memory-provider.d.ts +26 -0
- package/dist/core/context/okf-memory-provider.d.ts.map +1 -0
- package/dist/core/context/okf-memory-provider.js +154 -0
- package/dist/core/context/okf-memory-provider.js.map +1 -0
- package/dist/core/context/okf-memory.d.ts +42 -0
- package/dist/core/context/okf-memory.d.ts.map +1 -0
- package/dist/core/context/okf-memory.js +175 -0
- package/dist/core/context/okf-memory.js.map +1 -0
- package/dist/core/context/policy-engine.d.ts +66 -0
- package/dist/core/context/policy-engine.d.ts.map +1 -0
- package/dist/core/context/policy-engine.js +171 -0
- package/dist/core/context/policy-engine.js.map +1 -0
- package/dist/core/context/policy-types.d.ts +102 -0
- package/dist/core/context/policy-types.d.ts.map +1 -0
- package/dist/core/context/policy-types.js +7 -0
- package/dist/core/context/policy-types.js.map +1 -0
- package/dist/core/context/sqlite-runtime-index.d.ts +19 -0
- package/dist/core/context/sqlite-runtime-index.d.ts.map +1 -0
- package/dist/core/context/sqlite-runtime-index.js +344 -0
- package/dist/core/context/sqlite-runtime-index.js.map +1 -0
- package/dist/core/context/storage-authority.d.ts +20 -0
- package/dist/core/context/storage-authority.d.ts.map +1 -0
- package/dist/core/context/storage-authority.js +51 -0
- package/dist/core/context/storage-authority.js.map +1 -0
- package/dist/core/context/tool-output-packer.d.ts +75 -0
- package/dist/core/context/tool-output-packer.d.ts.map +1 -0
- package/dist/core/context/tool-output-packer.js +77 -0
- package/dist/core/context/tool-output-packer.js.map +1 -0
- package/dist/core/cost/session-usage.d.ts +20 -0
- package/dist/core/cost/session-usage.d.ts.map +1 -0
- package/dist/core/cost/session-usage.js +164 -0
- package/dist/core/cost/session-usage.js.map +1 -0
- package/dist/core/delegation/session-worker-result.d.ts +10 -0
- package/dist/core/delegation/session-worker-result.d.ts.map +1 -0
- package/dist/core/delegation/session-worker-result.js +36 -0
- package/dist/core/delegation/session-worker-result.js.map +1 -0
- package/dist/core/delegation/worker-result.d.ts +9 -0
- package/dist/core/delegation/worker-result.d.ts.map +1 -0
- package/dist/core/delegation/worker-result.js +152 -0
- package/dist/core/delegation/worker-result.js.map +1 -0
- package/dist/core/delegation/worker-runner.d.ts +58 -0
- package/dist/core/delegation/worker-runner.d.ts.map +1 -0
- package/dist/core/delegation/worker-runner.js +188 -0
- package/dist/core/delegation/worker-runner.js.map +1 -0
- package/dist/core/extensions/builtin.d.ts +5 -1
- package/dist/core/extensions/builtin.d.ts.map +1 -1
- package/dist/core/extensions/builtin.js +23 -1
- package/dist/core/extensions/builtin.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +5 -1
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +13 -0
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/goals/goal-continuation-controller.d.ts +22 -0
- package/dist/core/goals/goal-continuation-controller.d.ts.map +1 -0
- package/dist/core/goals/goal-continuation-controller.js +88 -0
- package/dist/core/goals/goal-continuation-controller.js.map +1 -0
- package/dist/core/goals/goal-continuation-defaults.d.ts +10 -0
- package/dist/core/goals/goal-continuation-defaults.d.ts.map +1 -0
- package/dist/core/goals/goal-continuation-defaults.js +10 -0
- package/dist/core/goals/goal-continuation-defaults.js.map +1 -0
- package/dist/core/goals/goal-continuation-prompt.d.ts +18 -0
- package/dist/core/goals/goal-continuation-prompt.d.ts.map +1 -0
- package/dist/core/goals/goal-continuation-prompt.js +141 -0
- package/dist/core/goals/goal-continuation-prompt.js.map +1 -0
- package/dist/core/goals/goal-runtime-snapshot.d.ts +19 -0
- package/dist/core/goals/goal-runtime-snapshot.d.ts.map +1 -0
- package/dist/core/goals/goal-runtime-snapshot.js +23 -0
- package/dist/core/goals/goal-runtime-snapshot.js.map +1 -0
- package/dist/core/goals/goal-state.d.ts +87 -0
- package/dist/core/goals/goal-state.d.ts.map +1 -0
- package/dist/core/goals/goal-state.js +259 -0
- package/dist/core/goals/goal-state.js.map +1 -0
- package/dist/core/goals/goal-tool-core.d.ts +66 -0
- package/dist/core/goals/goal-tool-core.d.ts.map +1 -0
- package/dist/core/goals/goal-tool-core.js +146 -0
- package/dist/core/goals/goal-tool-core.js.map +1 -0
- package/dist/core/goals/session-goal-state.d.ts +10 -0
- package/dist/core/goals/session-goal-state.d.ts.map +1 -0
- package/dist/core/goals/session-goal-state.js +35 -0
- package/dist/core/goals/session-goal-state.js.map +1 -0
- package/dist/core/learning/learning-audit.d.ts +45 -0
- package/dist/core/learning/learning-audit.d.ts.map +1 -0
- package/dist/core/learning/learning-audit.js +139 -0
- package/dist/core/learning/learning-audit.js.map +1 -0
- package/dist/core/learning/learning-gate.d.ts +29 -0
- package/dist/core/learning/learning-gate.d.ts.map +1 -0
- package/dist/core/learning/learning-gate.js +150 -0
- package/dist/core/learning/learning-gate.js.map +1 -0
- package/dist/core/learning/session-learning-decision.d.ts +10 -0
- package/dist/core/learning/session-learning-decision.d.ts.map +1 -0
- package/dist/core/learning/session-learning-decision.js +36 -0
- package/dist/core/learning/session-learning-decision.js.map +1 -0
- package/dist/core/model-capability.d.ts +41 -0
- package/dist/core/model-capability.d.ts.map +1 -0
- package/dist/core/model-capability.js +101 -0
- package/dist/core/model-capability.js.map +1 -0
- package/dist/core/model-router/config-diagnostics.d.ts.map +1 -1
- package/dist/core/model-router/config-diagnostics.js +1 -0
- package/dist/core/model-router/config-diagnostics.js.map +1 -1
- package/dist/core/model-router/intent-classifier.d.ts +2 -0
- package/dist/core/model-router/intent-classifier.d.ts.map +1 -1
- package/dist/core/model-router/intent-classifier.js +154 -9
- package/dist/core/model-router/intent-classifier.js.map +1 -1
- package/dist/core/model-router/route-judge.d.ts +54 -0
- package/dist/core/model-router/route-judge.d.ts.map +1 -0
- package/dist/core/model-router/route-judge.js +128 -0
- package/dist/core/model-router/route-judge.js.map +1 -0
- package/dist/core/model-router/status.d.ts +4 -1
- package/dist/core/model-router/status.d.ts.map +1 -1
- package/dist/core/model-router/status.js +30 -6
- package/dist/core/model-router/status.js.map +1 -1
- package/dist/core/model-router/tool-escalation.d.ts +4 -6
- package/dist/core/model-router/tool-escalation.d.ts.map +1 -1
- package/dist/core/model-router/tool-escalation.js +1 -1
- package/dist/core/model-router/tool-escalation.js.map +1 -1
- package/dist/core/models/fitness-store.d.ts +40 -0
- package/dist/core/models/fitness-store.d.ts.map +1 -0
- package/dist/core/models/fitness-store.js +61 -0
- package/dist/core/models/fitness-store.js.map +1 -0
- package/dist/core/profile-registry.d.ts.map +1 -1
- package/dist/core/profile-registry.js +1 -1
- package/dist/core/profile-registry.js.map +1 -1
- package/dist/core/prompt-templates.d.ts +2 -0
- package/dist/core/prompt-templates.d.ts.map +1 -1
- package/dist/core/prompt-templates.js +12 -4
- package/dist/core/prompt-templates.js.map +1 -1
- package/dist/core/research/automata-provider.d.ts +5 -0
- package/dist/core/research/automata-provider.d.ts.map +1 -0
- package/dist/core/research/automata-provider.js +15 -0
- package/dist/core/research/automata-provider.js.map +1 -0
- package/dist/core/research/evidence-bundle.d.ts +10 -0
- package/dist/core/research/evidence-bundle.d.ts.map +1 -0
- package/dist/core/research/evidence-bundle.js +116 -0
- package/dist/core/research/evidence-bundle.js.map +1 -0
- package/dist/core/research/model-fitness.d.ts +79 -0
- package/dist/core/research/model-fitness.d.ts.map +1 -0
- package/dist/core/research/model-fitness.js +257 -0
- package/dist/core/research/model-fitness.js.map +1 -0
- package/dist/core/research/research-gate.d.ts +11 -0
- package/dist/core/research/research-gate.d.ts.map +1 -0
- package/dist/core/research/research-gate.js +82 -0
- package/dist/core/research/research-gate.js.map +1 -0
- package/dist/core/research/research-runner.d.ts +59 -0
- package/dist/core/research/research-runner.d.ts.map +1 -0
- package/dist/core/research/research-runner.js +155 -0
- package/dist/core/research/research-runner.js.map +1 -0
- package/dist/core/research/session-evidence-bundle.d.ts +11 -0
- package/dist/core/research/session-evidence-bundle.d.ts.map +1 -0
- package/dist/core/research/session-evidence-bundle.js +55 -0
- package/dist/core/research/session-evidence-bundle.js.map +1 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +7 -1
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/settings-manager.d.ts +147 -4
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +285 -9
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills.d.ts +4 -0
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +18 -6
- package/dist/core/skills.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +4 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/toolkit/script-registry.d.ts +34 -0
- package/dist/core/toolkit/script-registry.d.ts.map +1 -0
- package/dist/core/toolkit/script-registry.js +71 -0
- package/dist/core/toolkit/script-registry.js.map +1 -0
- package/dist/core/toolkit/script-runner.d.ts +28 -0
- package/dist/core/toolkit/script-runner.d.ts.map +1 -0
- package/dist/core/toolkit/script-runner.js +48 -0
- package/dist/core/toolkit/script-runner.js.map +1 -0
- package/dist/core/tools/artifact-retrieve.d.ts +23 -0
- package/dist/core/tools/artifact-retrieve.d.ts.map +1 -0
- package/dist/core/tools/artifact-retrieve.js +110 -0
- package/dist/core/tools/artifact-retrieve.js.map +1 -0
- package/dist/core/tools/delegate.d.ts +32 -0
- package/dist/core/tools/delegate.d.ts.map +1 -0
- package/dist/core/tools/delegate.js +60 -0
- package/dist/core/tools/delegate.js.map +1 -0
- package/dist/core/tools/fff-search-backend.d.ts +103 -0
- package/dist/core/tools/fff-search-backend.d.ts.map +1 -0
- package/dist/core/tools/fff-search-backend.js +151 -0
- package/dist/core/tools/fff-search-backend.js.map +1 -0
- package/dist/core/tools/find.d.ts +21 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +183 -10
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/goal.d.ts +35 -0
- package/dist/core/tools/goal.d.ts.map +1 -0
- package/dist/core/tools/goal.js +122 -0
- package/dist/core/tools/goal.js.map +1 -0
- package/dist/core/tools/grep.d.ts +21 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +272 -27
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/index.d.ts +4 -1
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +9 -0
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/model-fitness.d.ts +30 -0
- package/dist/core/tools/model-fitness.d.ts.map +1 -0
- package/dist/core/tools/model-fitness.js +38 -0
- package/dist/core/tools/model-fitness.js.map +1 -0
- package/dist/core/tools/run-toolkit-script.d.ts +24 -0
- package/dist/core/tools/run-toolkit-script.d.ts.map +1 -0
- package/dist/core/tools/run-toolkit-script.js +103 -0
- package/dist/core/tools/run-toolkit-script.js.map +1 -0
- package/dist/core/tools/search-router.d.ts +75 -0
- package/dist/core/tools/search-router.d.ts.map +1 -0
- package/dist/core/tools/search-router.js +85 -0
- package/dist/core/tools/search-router.js.map +1 -0
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +18 -16
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +13 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +471 -11
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +4 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +220 -39
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +3 -0
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/utils/tools-manager.d.ts +2 -0
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +154 -2
- package/dist/utils/tools-manager.js.map +1 -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/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +368 -12
- package/package.json +5 -4
|
@@ -1,12 +1,157 @@
|
|
|
1
|
-
const
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
|
|
1
|
+
const EXPLICIT_MODIFY_REQUEST_RE = /^(?:can you|could you|please|pls|go ahead and|let'?s|i need you to|we need to|you should)\s+.*\b(add|apply|build|change|commit|create|delete|edit|fix|generate|implement|install|modify|patch|refactor|remove|rename|replace|run|test|update|write|publish|release|push|deploy|tag|reset|clean|rewrite)\b/i;
|
|
2
|
+
const READ_ONLY_QUESTION_RE = /^(?:(?:can you|could you|please|pls|go ahead and|let'?s|i need you to|we need to|you should)\s+)?(?:how|what|why|when|where|which|who|explain|summarize|compare|describe|list|show|search|find|view|read|locate)\b/i;
|
|
3
|
+
const RELEASE_PUBLISH_RE = /\b(publish|release|push|deploy|tag)\b/i;
|
|
4
|
+
const SECURITY_AUTH_RE = /\b(auth|token|credential|credentials|secret|api[-_]key)\b/i;
|
|
5
|
+
const DESTRUCTIVE_RE = /\b(delete|reset|rm\s+-rf|clean)\b/i;
|
|
6
|
+
const SELF_MOD_MUTATE_RE = /\b(modify|change|write|update|edit|delete|add|remove)\s+.*\b(skills|prompts|settings|tools|behavior)\b|self[-_]modification/i;
|
|
7
|
+
const ARCHITECTURE_MUTATE_RE = /\b(rewrite|redesign|change|modify|rearchitect)\s+.*\b(architecture|architect)\b/i;
|
|
8
|
+
// Planning floor: plans steer all downstream work, so planning never routes cheap by default.
|
|
9
|
+
// Only the route judge may downgrade a planning prompt back to cheap (explicit trivial verdict).
|
|
10
|
+
// Core terms are always planning; design/architecture words count only with prospective phrasing,
|
|
11
|
+
// so lookups like "show me the architecture" stay cheap.
|
|
12
|
+
const PLANNING_CORE_RE = /\b(plan|planning|roadmap|strategy)\b/i;
|
|
13
|
+
const PLANNING_DESIGN_WORD_RE = /\b(design|architect\w*|structure|approach)\b/i;
|
|
14
|
+
const PLANNING_PROSPECTIVE_RE = /\b(how (?:should|would|do we|can we)|what(?:'s| is) the best|propose|draft|come up with|figure out|decide (?:on|how))\b/i;
|
|
15
|
+
function isPlanningPrompt(text) {
|
|
16
|
+
return PLANNING_CORE_RE.test(text) || (PLANNING_DESIGN_WORD_RE.test(text) && PLANNING_PROSPECTIVE_RE.test(text));
|
|
17
|
+
}
|
|
18
|
+
const REFACTOR_RE = /\b(refactor|refactoring)\b/i;
|
|
19
|
+
const TEST_VALIDATION_RE = /\b(test|testing|validation|lint|vitest|jest|run)\b/i;
|
|
20
|
+
const IMPLEMENT_RE = /\b(implement|fix|apply|change|update|create|write|generate|modify|edit|patch|add)\b/i;
|
|
21
|
+
export function classifyModelRouterRoute(prompt) {
|
|
5
22
|
const text = prompt.trim();
|
|
6
|
-
if (
|
|
7
|
-
return
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
23
|
+
if (text.length === 0) {
|
|
24
|
+
return {
|
|
25
|
+
tier: "cheap",
|
|
26
|
+
risk: "read-only",
|
|
27
|
+
confidence: 0.1,
|
|
28
|
+
reasonCode: "empty_prompt",
|
|
29
|
+
reasons: ["Empty or whitespace prompt"],
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
// 1. Explicit read-only questions/lookups dominate (unless prefixed by explicit mutation verb).
|
|
33
|
+
// Planning-shaped questions are the exception: a plan steers expensive downstream work, so the
|
|
34
|
+
// floor is medium even when phrased as a question.
|
|
35
|
+
if (READ_ONLY_QUESTION_RE.test(text) && !EXPLICIT_MODIFY_REQUEST_RE.test(text)) {
|
|
36
|
+
if (isPlanningPrompt(text)) {
|
|
37
|
+
return {
|
|
38
|
+
tier: "medium",
|
|
39
|
+
risk: "read-only",
|
|
40
|
+
confidence: 0.75,
|
|
41
|
+
reasonCode: "planning_min_medium",
|
|
42
|
+
reasons: ["Planning/design prompts never route cheap by default; a judge may deem them trivial"],
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
tier: "cheap",
|
|
47
|
+
risk: "read-only",
|
|
48
|
+
confidence: 0.9,
|
|
49
|
+
reasonCode: "read_only_question",
|
|
50
|
+
reasons: ["Prompt asks a question or requests an explanation, search, or lookup"],
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
// Helper function to match patterns and return appropriate decision
|
|
54
|
+
function matchKeywords(input) {
|
|
55
|
+
// A. High-risk / approval-required/expensive signals
|
|
56
|
+
if (RELEASE_PUBLISH_RE.test(input)) {
|
|
57
|
+
return {
|
|
58
|
+
tier: "expensive",
|
|
59
|
+
risk: "approval-required",
|
|
60
|
+
confidence: 0.9,
|
|
61
|
+
reasonCode: "release_or_publish",
|
|
62
|
+
reasons: ["Prompt mentions publishing, releasing, pushing, or deploying"],
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
if (SECURITY_AUTH_RE.test(input)) {
|
|
66
|
+
return {
|
|
67
|
+
tier: "expensive",
|
|
68
|
+
risk: "high-impact",
|
|
69
|
+
confidence: 0.95,
|
|
70
|
+
reasonCode: "security_or_auth",
|
|
71
|
+
reasons: ["Prompt mentions credentials, authentication, tokens, or secrets"],
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
if (DESTRUCTIVE_RE.test(input)) {
|
|
75
|
+
return {
|
|
76
|
+
tier: "expensive",
|
|
77
|
+
risk: "approval-required",
|
|
78
|
+
confidence: 0.85,
|
|
79
|
+
reasonCode: "destructive_or_git_history",
|
|
80
|
+
reasons: ["Prompt mentions deleting, resetting, cleaning, or destructive operations"],
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
if (SELF_MOD_MUTATE_RE.test(input)) {
|
|
84
|
+
return {
|
|
85
|
+
tier: "expensive",
|
|
86
|
+
risk: "approval-required",
|
|
87
|
+
confidence: 0.9,
|
|
88
|
+
reasonCode: "settings_or_self_modification",
|
|
89
|
+
reasons: ["Prompt mentions modifying skills, prompts, settings, tools, or self-modification"],
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
if (ARCHITECTURE_MUTATE_RE.test(input)) {
|
|
93
|
+
return {
|
|
94
|
+
tier: "expensive",
|
|
95
|
+
risk: "high-impact",
|
|
96
|
+
confidence: 0.9,
|
|
97
|
+
reasonCode: "architecture_or_ambiguous",
|
|
98
|
+
reasons: ["Prompt mentions core architecture or rewrite"],
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
// B. Explicit implementation/scoped-write signals route medium
|
|
102
|
+
if (isPlanningPrompt(input)) {
|
|
103
|
+
return {
|
|
104
|
+
tier: "medium",
|
|
105
|
+
risk: "read-only",
|
|
106
|
+
confidence: 0.75,
|
|
107
|
+
reasonCode: "planning_min_medium",
|
|
108
|
+
reasons: ["Planning/design prompts never route cheap by default; a judge may deem them trivial"],
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
if (REFACTOR_RE.test(input)) {
|
|
112
|
+
return {
|
|
113
|
+
tier: "medium",
|
|
114
|
+
risk: "scoped-write",
|
|
115
|
+
confidence: 0.8,
|
|
116
|
+
reasonCode: "mechanical_refactor",
|
|
117
|
+
reasons: ["Prompt mentions refactoring code structure"],
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
if (TEST_VALIDATION_RE.test(input)) {
|
|
121
|
+
return {
|
|
122
|
+
tier: "medium",
|
|
123
|
+
risk: "scoped-write",
|
|
124
|
+
confidence: 0.8,
|
|
125
|
+
reasonCode: "test_or_validation",
|
|
126
|
+
reasons: ["Prompt mentions testing, validation, or linting"],
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
if (IMPLEMENT_RE.test(input)) {
|
|
130
|
+
return {
|
|
131
|
+
tier: "medium",
|
|
132
|
+
risk: "scoped-write",
|
|
133
|
+
confidence: 0.85,
|
|
134
|
+
reasonCode: "normal_implementation",
|
|
135
|
+
reasons: ["Prompt mentions implementing, updating, creating, or modifying code"],
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
const match = matchKeywords(text);
|
|
141
|
+
if (match) {
|
|
142
|
+
return match;
|
|
143
|
+
}
|
|
144
|
+
// 4. Default fallbacks
|
|
145
|
+
return {
|
|
146
|
+
tier: "cheap",
|
|
147
|
+
risk: "read-only",
|
|
148
|
+
confidence: 0.5,
|
|
149
|
+
reasonCode: "default_read_only",
|
|
150
|
+
reasons: ["No explicit implementation, destructive, or release patterns detected"],
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
export function classifyModelRouterIntent(prompt) {
|
|
154
|
+
const decision = classifyModelRouterRoute(prompt);
|
|
155
|
+
return decision.tier === "cheap" ? "research" : "modify";
|
|
11
156
|
}
|
|
12
157
|
//# sourceMappingURL=intent-classifier.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intent-classifier.js","sourceRoot":"","sources":["../../../src/core/model-router/intent-classifier.ts"],"names":[],"mappings":"AAEA,MAAM,gBAAgB,GACrB,6NAA6N,CAAC;AAE/N,MAAM,0BAA0B,GAC/B,wPAAwP,CAAC;AAE1P,MAAM,qBAAqB,GAAG,wFAAwF,CAAC;AAEvH,MAAM,UAAU,yBAAyB,CAAC,MAAc,EAAqB;IAC5E,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;IAC3B,IAAI,0BAA0B,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC3D,IAAI,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,UAAU,CAAC;IACxD,OAAO,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC;AAAA,CAC3D","sourcesContent":["export type ModelRouterIntent = \"research\" | \"modify\";\n\nconst MODIFY_INTENT_RE =\n\t/\\b(add|apply|build|change|commit|create|delete|edit|fix|generate|implement|install|modify|patch|refactor|remove|rename|replace|run|test|update|write)\\b|\\b(npm|pnpm|yarn|bun|git|gh|pytest|vitest|tsc|biome)\\b|[;&|]\\s*\\w+/i;\n\nconst EXPLICIT_MODIFY_REQUEST_RE =\n\t/^(?:can you|could you|please|pls|go ahead and|let'?s|i need you to|we need to|you should)\\s+.*\\b(add|apply|build|change|commit|create|delete|edit|fix|generate|implement|install|modify|patch|refactor|remove|rename|replace|run|test|update|write)\\b/i;\n\nconst READ_ONLY_QUESTION_RE = /^(?:how|what|why|when|where|which|who|explain|summarize|compare|describe|list|show)\\b/i;\n\nexport function classifyModelRouterIntent(prompt: string): ModelRouterIntent {\n\tconst text = prompt.trim();\n\tif (EXPLICIT_MODIFY_REQUEST_RE.test(text)) return \"modify\";\n\tif (READ_ONLY_QUESTION_RE.test(text)) return \"research\";\n\treturn MODIFY_INTENT_RE.test(text) ? \"modify\" : \"research\";\n}\n"]}
|
|
1
|
+
{"version":3,"file":"intent-classifier.js","sourceRoot":"","sources":["../../../src/core/model-router/intent-classifier.ts"],"names":[],"mappings":"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","sourcesContent":["import type { RouteDecision } from \"../autonomy/contracts.ts\";\n\nexport type ModelRouterIntent = \"research\" | \"modify\";\n\nconst EXPLICIT_MODIFY_REQUEST_RE =\n\t/^(?:can you|could you|please|pls|go ahead and|let'?s|i need you to|we need to|you should)\\s+.*\\b(add|apply|build|change|commit|create|delete|edit|fix|generate|implement|install|modify|patch|refactor|remove|rename|replace|run|test|update|write|publish|release|push|deploy|tag|reset|clean|rewrite)\\b/i;\n\nconst READ_ONLY_QUESTION_RE =\n\t/^(?:(?:can you|could you|please|pls|go ahead and|let'?s|i need you to|we need to|you should)\\s+)?(?:how|what|why|when|where|which|who|explain|summarize|compare|describe|list|show|search|find|view|read|locate)\\b/i;\n\nconst RELEASE_PUBLISH_RE = /\\b(publish|release|push|deploy|tag)\\b/i;\nconst SECURITY_AUTH_RE = /\\b(auth|token|credential|credentials|secret|api[-_]key)\\b/i;\nconst DESTRUCTIVE_RE = /\\b(delete|reset|rm\\s+-rf|clean)\\b/i;\n\nconst SELF_MOD_MUTATE_RE =\n\t/\\b(modify|change|write|update|edit|delete|add|remove)\\s+.*\\b(skills|prompts|settings|tools|behavior)\\b|self[-_]modification/i;\nconst ARCHITECTURE_MUTATE_RE = /\\b(rewrite|redesign|change|modify|rearchitect)\\s+.*\\b(architecture|architect)\\b/i;\n\n// Planning floor: plans steer all downstream work, so planning never routes cheap by default.\n// Only the route judge may downgrade a planning prompt back to cheap (explicit trivial verdict).\n// Core terms are always planning; design/architecture words count only with prospective phrasing,\n// so lookups like \"show me the architecture\" stay cheap.\nconst PLANNING_CORE_RE = /\\b(plan|planning|roadmap|strategy)\\b/i;\nconst PLANNING_DESIGN_WORD_RE = /\\b(design|architect\\w*|structure|approach)\\b/i;\nconst PLANNING_PROSPECTIVE_RE =\n\t/\\b(how (?:should|would|do we|can we)|what(?:'s| is) the best|propose|draft|come up with|figure out|decide (?:on|how))\\b/i;\n\nfunction isPlanningPrompt(text: string): boolean {\n\treturn PLANNING_CORE_RE.test(text) || (PLANNING_DESIGN_WORD_RE.test(text) && PLANNING_PROSPECTIVE_RE.test(text));\n}\n\nconst REFACTOR_RE = /\\b(refactor|refactoring)\\b/i;\nconst TEST_VALIDATION_RE = /\\b(test|testing|validation|lint|vitest|jest|run)\\b/i;\nconst IMPLEMENT_RE = /\\b(implement|fix|apply|change|update|create|write|generate|modify|edit|patch|add)\\b/i;\n\nexport function classifyModelRouterRoute(prompt: string): RouteDecision {\n\tconst text = prompt.trim();\n\n\tif (text.length === 0) {\n\t\treturn {\n\t\t\ttier: \"cheap\",\n\t\t\trisk: \"read-only\",\n\t\t\tconfidence: 0.1,\n\t\t\treasonCode: \"empty_prompt\",\n\t\t\treasons: [\"Empty or whitespace prompt\"],\n\t\t};\n\t}\n\n\t// 1. Explicit read-only questions/lookups dominate (unless prefixed by explicit mutation verb).\n\t// Planning-shaped questions are the exception: a plan steers expensive downstream work, so the\n\t// floor is medium even when phrased as a question.\n\tif (READ_ONLY_QUESTION_RE.test(text) && !EXPLICIT_MODIFY_REQUEST_RE.test(text)) {\n\t\tif (isPlanningPrompt(text)) {\n\t\t\treturn {\n\t\t\t\ttier: \"medium\",\n\t\t\t\trisk: \"read-only\",\n\t\t\t\tconfidence: 0.75,\n\t\t\t\treasonCode: \"planning_min_medium\",\n\t\t\t\treasons: [\"Planning/design prompts never route cheap by default; a judge may deem them trivial\"],\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\ttier: \"cheap\",\n\t\t\trisk: \"read-only\",\n\t\t\tconfidence: 0.9,\n\t\t\treasonCode: \"read_only_question\",\n\t\t\treasons: [\"Prompt asks a question or requests an explanation, search, or lookup\"],\n\t\t};\n\t}\n\n\t// Helper function to match patterns and return appropriate decision\n\tfunction matchKeywords(input: string): RouteDecision | null {\n\t\t// A. High-risk / approval-required/expensive signals\n\t\tif (RELEASE_PUBLISH_RE.test(input)) {\n\t\t\treturn {\n\t\t\t\ttier: \"expensive\",\n\t\t\t\trisk: \"approval-required\",\n\t\t\t\tconfidence: 0.9,\n\t\t\t\treasonCode: \"release_or_publish\",\n\t\t\t\treasons: [\"Prompt mentions publishing, releasing, pushing, or deploying\"],\n\t\t\t};\n\t\t}\n\t\tif (SECURITY_AUTH_RE.test(input)) {\n\t\t\treturn {\n\t\t\t\ttier: \"expensive\",\n\t\t\t\trisk: \"high-impact\",\n\t\t\t\tconfidence: 0.95,\n\t\t\t\treasonCode: \"security_or_auth\",\n\t\t\t\treasons: [\"Prompt mentions credentials, authentication, tokens, or secrets\"],\n\t\t\t};\n\t\t}\n\t\tif (DESTRUCTIVE_RE.test(input)) {\n\t\t\treturn {\n\t\t\t\ttier: \"expensive\",\n\t\t\t\trisk: \"approval-required\",\n\t\t\t\tconfidence: 0.85,\n\t\t\t\treasonCode: \"destructive_or_git_history\",\n\t\t\t\treasons: [\"Prompt mentions deleting, resetting, cleaning, or destructive operations\"],\n\t\t\t};\n\t\t}\n\t\tif (SELF_MOD_MUTATE_RE.test(input)) {\n\t\t\treturn {\n\t\t\t\ttier: \"expensive\",\n\t\t\t\trisk: \"approval-required\",\n\t\t\t\tconfidence: 0.9,\n\t\t\t\treasonCode: \"settings_or_self_modification\",\n\t\t\t\treasons: [\"Prompt mentions modifying skills, prompts, settings, tools, or self-modification\"],\n\t\t\t};\n\t\t}\n\t\tif (ARCHITECTURE_MUTATE_RE.test(input)) {\n\t\t\treturn {\n\t\t\t\ttier: \"expensive\",\n\t\t\t\trisk: \"high-impact\",\n\t\t\t\tconfidence: 0.9,\n\t\t\t\treasonCode: \"architecture_or_ambiguous\",\n\t\t\t\treasons: [\"Prompt mentions core architecture or rewrite\"],\n\t\t\t};\n\t\t}\n\n\t\t// B. Explicit implementation/scoped-write signals route medium\n\t\tif (isPlanningPrompt(input)) {\n\t\t\treturn {\n\t\t\t\ttier: \"medium\",\n\t\t\t\trisk: \"read-only\",\n\t\t\t\tconfidence: 0.75,\n\t\t\t\treasonCode: \"planning_min_medium\",\n\t\t\t\treasons: [\"Planning/design prompts never route cheap by default; a judge may deem them trivial\"],\n\t\t\t};\n\t\t}\n\t\tif (REFACTOR_RE.test(input)) {\n\t\t\treturn {\n\t\t\t\ttier: \"medium\",\n\t\t\t\trisk: \"scoped-write\",\n\t\t\t\tconfidence: 0.8,\n\t\t\t\treasonCode: \"mechanical_refactor\",\n\t\t\t\treasons: [\"Prompt mentions refactoring code structure\"],\n\t\t\t};\n\t\t}\n\t\tif (TEST_VALIDATION_RE.test(input)) {\n\t\t\treturn {\n\t\t\t\ttier: \"medium\",\n\t\t\t\trisk: \"scoped-write\",\n\t\t\t\tconfidence: 0.8,\n\t\t\t\treasonCode: \"test_or_validation\",\n\t\t\t\treasons: [\"Prompt mentions testing, validation, or linting\"],\n\t\t\t};\n\t\t}\n\t\tif (IMPLEMENT_RE.test(input)) {\n\t\t\treturn {\n\t\t\t\ttier: \"medium\",\n\t\t\t\trisk: \"scoped-write\",\n\t\t\t\tconfidence: 0.85,\n\t\t\t\treasonCode: \"normal_implementation\",\n\t\t\t\treasons: [\"Prompt mentions implementing, updating, creating, or modifying code\"],\n\t\t\t};\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tconst match = matchKeywords(text);\n\tif (match) {\n\t\treturn match;\n\t}\n\n\t// 4. Default fallbacks\n\treturn {\n\t\ttier: \"cheap\",\n\t\trisk: \"read-only\",\n\t\tconfidence: 0.5,\n\t\treasonCode: \"default_read_only\",\n\t\treasons: [\"No explicit implementation, destructive, or release patterns detected\"],\n\t};\n}\n\nexport function classifyModelRouterIntent(prompt: string): ModelRouterIntent {\n\tconst decision = classifyModelRouterRoute(prompt);\n\treturn decision.tier === \"cheap\" ? \"research\" : \"modify\";\n}\n"]}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { RouteDecision } from "../autonomy/contracts.ts";
|
|
2
|
+
/**
|
|
3
|
+
* Routing-only judge: a bounded, tool-less completion (default: the medium model) that decides the
|
|
4
|
+
* final cheap/medium/expensive tier for a user prompt, refining the regex classifier's baseline.
|
|
5
|
+
* Core rule: planning is never cheap unless the judge explicitly deems the task trivial. The judge
|
|
6
|
+
* proposes; the existing pipeline (model resolution, auth, escalation, gates) still decides.
|
|
7
|
+
* Failure is honest: unparseable/timeout/unavailable falls back to the baseline with a visible
|
|
8
|
+
* reasonCode, never silently.
|
|
9
|
+
*/
|
|
10
|
+
/** Static across calls — callers pass cacheRetention "short" so only the variable tail is billed. */
|
|
11
|
+
export declare const ROUTE_JUDGE_SYSTEM_PROMPT: string;
|
|
12
|
+
export declare const ROUTE_JUDGE_MAX_OUTPUT_TOKENS = 128;
|
|
13
|
+
export declare const ROUTE_JUDGE_MAX_WALL_CLOCK_MS = 10000;
|
|
14
|
+
export interface RouteJudgeVerdict {
|
|
15
|
+
tier: "cheap" | "medium" | "expensive";
|
|
16
|
+
risk: RouteDecision["risk"];
|
|
17
|
+
trivial: boolean;
|
|
18
|
+
reason: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function buildRouteJudgeUserPrompt(args: {
|
|
21
|
+
prompt: string;
|
|
22
|
+
baseline: RouteDecision;
|
|
23
|
+
}): string;
|
|
24
|
+
export declare function parseRouteJudgeVerdict(text: string): RouteJudgeVerdict | undefined;
|
|
25
|
+
/** Merge a judge verdict into the baseline decision (pure; never returns learning). */
|
|
26
|
+
export declare function applyRouteJudgeVerdict(baseline: RouteDecision, verdict: RouteJudgeVerdict): RouteDecision;
|
|
27
|
+
export interface RouteJudgeRunResult {
|
|
28
|
+
decision: RouteDecision;
|
|
29
|
+
verdict?: RouteJudgeVerdict;
|
|
30
|
+
/** Set when the judge could not decide and the baseline was kept. */
|
|
31
|
+
fallbackReason?: string;
|
|
32
|
+
costUsd: number;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Run the judge over a baseline decision. The completion executor is injected (production:
|
|
36
|
+
* AgentSession.runIsolatedCompletion on the judge model). Never throws; every failure keeps the
|
|
37
|
+
* baseline with a visible fallbackReason.
|
|
38
|
+
*/
|
|
39
|
+
export declare function runRouteJudge(args: {
|
|
40
|
+
prompt: string;
|
|
41
|
+
baseline: RouteDecision;
|
|
42
|
+
complete: (input: {
|
|
43
|
+
systemPrompt: string;
|
|
44
|
+
userPrompt: string;
|
|
45
|
+
signal?: AbortSignal;
|
|
46
|
+
}) => Promise<{
|
|
47
|
+
text: string;
|
|
48
|
+
costUsd: number;
|
|
49
|
+
stopReason: string;
|
|
50
|
+
}>;
|
|
51
|
+
signal?: AbortSignal;
|
|
52
|
+
maxWallClockMs?: number;
|
|
53
|
+
}): Promise<RouteJudgeRunResult>;
|
|
54
|
+
//# sourceMappingURL=route-judge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-judge.d.ts","sourceRoot":"","sources":["../../../src/core/model-router/route-judge.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAE9D;;;;;;;GAOG;AAEH,uGAAqG;AACrG,eAAO,MAAM,yBAAyB,QAS1B,CAAC;AAEb,eAAO,MAAM,6BAA6B,MAAM,CAAC;AACjD,eAAO,MAAM,6BAA6B,QAAS,CAAC;AAEpD,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,WAAW,CAAC;IACvC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,aAAa,CAAA;CAAE,GAAG,MAAM,CAMnG;AAKD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAiClF;AAED,uFAAuF;AACvF,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,aAAa,EAAE,OAAO,EAAE,iBAAiB,GAAG,aAAa,CAczG;AAED,MAAM,WAAW,mBAAmB;IACnC,QAAQ,EAAE,aAAa,CAAC;IACxB,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,qEAAqE;IACrE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,aAAa,CAAC;IACxB,QAAQ,EAAE,CAAC,KAAK,EAAE;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,KAAK,OAAO,CAAC;QAChG,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;KACnB,CAAC,CAAC;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAyC/B","sourcesContent":["import { runBoundedCompletion } from \"../autonomy/bounded-completion.ts\";\nimport type { RouteDecision } from \"../autonomy/contracts.ts\";\n\n/**\n * Routing-only judge: a bounded, tool-less completion (default: the medium model) that decides the\n * final cheap/medium/expensive tier for a user prompt, refining the regex classifier's baseline.\n * Core rule: planning is never cheap unless the judge explicitly deems the task trivial. The judge\n * proposes; the existing pipeline (model resolution, auth, escalation, gates) still decides.\n * Failure is honest: unparseable/timeout/unavailable falls back to the baseline with a visible\n * reasonCode, never silently.\n */\n\n/** Static across calls — callers pass cacheRetention \"short\" so only the variable tail is billed. */\nexport const ROUTE_JUDGE_SYSTEM_PROMPT = [\n\t\"You are a routing judge for a coding agent. You only route; you never answer the task.\",\n\t\"Pick which model tier should handle the user prompt:\",\n\t'- \"cheap\": trivial, mechanical, read-only lookups only.',\n\t'- \"medium\": normal implementation, scoped edits, tests, and NON-trivial planning/design.',\n\t'- \"expensive\": architecture, ambiguity, security/auth, destructive or release operations, high-impact changes.',\n\t\"Planning, design, and strategy prompts are NEVER cheap unless the task is genuinely trivial.\",\n\t\"Respond with STRICT JSON only - no prose:\",\n\t'{\"tier\":\"cheap\"|\"medium\"|\"expensive\",\"risk\":\"read-only\"|\"scoped-write\"|\"high-impact\"|\"approval-required\",\"trivial\":true|false,\"reason\":\"<short reason>\"}',\n].join(\"\\n\");\n\nexport const ROUTE_JUDGE_MAX_OUTPUT_TOKENS = 128;\nexport const ROUTE_JUDGE_MAX_WALL_CLOCK_MS = 10_000;\n\nexport interface RouteJudgeVerdict {\n\ttier: \"cheap\" | \"medium\" | \"expensive\";\n\trisk: RouteDecision[\"risk\"];\n\ttrivial: boolean;\n\treason: string;\n}\n\nexport function buildRouteJudgeUserPrompt(args: { prompt: string; baseline: RouteDecision }): string {\n\treturn [\n\t\t`Baseline (regex) verdict: tier=${args.baseline.tier}, risk=${args.baseline.risk}, reason=${args.baseline.reasonCode}.`,\n\t\t\"User prompt:\",\n\t\targs.prompt.slice(0, 4000),\n\t].join(\"\\n\");\n}\n\nconst JUDGE_TIERS: readonly string[] = [\"cheap\", \"medium\", \"expensive\"];\nconst JUDGE_RISKS: readonly string[] = [\"read-only\", \"scoped-write\", \"high-impact\", \"approval-required\"];\n\nexport function parseRouteJudgeVerdict(text: string): RouteJudgeVerdict | undefined {\n\tconst trimmed = text.trim();\n\tconst candidates: string[] = [trimmed];\n\tconst fenced = /```(?:json)?\\s*([\\s\\S]*?)```/.exec(trimmed);\n\tif (fenced?.[1]) candidates.push(fenced[1].trim());\n\tconst start = trimmed.indexOf(\"{\");\n\tconst end = trimmed.lastIndexOf(\"}\");\n\tif (start >= 0 && end > start) candidates.push(trimmed.slice(start, end + 1));\n\n\tfor (const candidate of candidates) {\n\t\tlet parsed: unknown;\n\t\ttry {\n\t\t\tparsed = JSON.parse(candidate);\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t\tif (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) continue;\n\t\tconst record = parsed as Record<string, unknown>;\n\t\t// The judge may never select the learning tier or anything outside the three foreground tiers.\n\t\tif (typeof record.tier !== \"string\" || !JUDGE_TIERS.includes(record.tier)) continue;\n\t\tconst risk =\n\t\t\ttypeof record.risk === \"string\" && JUDGE_RISKS.includes(record.risk)\n\t\t\t\t? (record.risk as RouteDecision[\"risk\"])\n\t\t\t\t: undefined;\n\t\tif (!risk) continue;\n\t\treturn {\n\t\t\ttier: record.tier as RouteJudgeVerdict[\"tier\"],\n\t\t\trisk,\n\t\t\ttrivial: record.trivial === true,\n\t\t\treason: typeof record.reason === \"string\" ? record.reason.slice(0, 200) : \"\",\n\t\t};\n\t}\n\treturn undefined;\n}\n\n/** Merge a judge verdict into the baseline decision (pure; never returns learning). */\nexport function applyRouteJudgeVerdict(baseline: RouteDecision, verdict: RouteJudgeVerdict): RouteDecision {\n\t// Enforce the core rule in code, not just in the judge prompt: downgrading a non-cheap\n\t// baseline to cheap requires an EXPLICIT trivial verdict. An untrusted judge saying\n\t// {tier:\"cheap\", trivial:false} for an elevated prompt keeps the baseline tier.\n\tconst tier =\n\t\tverdict.tier === \"cheap\" && baseline.tier !== \"cheap\" && !verdict.trivial ? baseline.tier : verdict.tier;\n\treturn {\n\t\t...baseline,\n\t\ttier,\n\t\trisk: verdict.risk,\n\t\tconfidence: Math.max(baseline.confidence, 0.75),\n\t\treasonCode: `judge_${tier}${verdict.trivial ? \"_trivial\" : \"\"}`,\n\t\treasons: [...baseline.reasons, `Route judge: ${verdict.reason || \"no reason given\"}`],\n\t};\n}\n\nexport interface RouteJudgeRunResult {\n\tdecision: RouteDecision;\n\tverdict?: RouteJudgeVerdict;\n\t/** Set when the judge could not decide and the baseline was kept. */\n\tfallbackReason?: string;\n\tcostUsd: number;\n}\n\n/**\n * Run the judge over a baseline decision. The completion executor is injected (production:\n * AgentSession.runIsolatedCompletion on the judge model). Never throws; every failure keeps the\n * baseline with a visible fallbackReason.\n */\nexport async function runRouteJudge(args: {\n\tprompt: string;\n\tbaseline: RouteDecision;\n\tcomplete: (input: { systemPrompt: string; userPrompt: string; signal?: AbortSignal }) => Promise<{\n\t\ttext: string;\n\t\tcostUsd: number;\n\t\tstopReason: string;\n\t}>;\n\tsignal?: AbortSignal;\n\tmaxWallClockMs?: number;\n}): Promise<RouteJudgeRunResult> {\n\tconst bounded = await runBoundedCompletion({\n\t\tmaxWallClockMs: args.maxWallClockMs ?? ROUTE_JUDGE_MAX_WALL_CLOCK_MS,\n\t\tsignal: args.signal,\n\t\texecute: (signal) =>\n\t\t\targs.complete({\n\t\t\t\tsystemPrompt: ROUTE_JUDGE_SYSTEM_PROMPT,\n\t\t\t\tuserPrompt: buildRouteJudgeUserPrompt({ prompt: args.prompt, baseline: args.baseline }),\n\t\t\t\tsignal,\n\t\t\t}),\n\t});\n\tconst costUsd = bounded.completion?.costUsd ?? 0;\n\n\tif (bounded.failure || !bounded.completion) {\n\t\treturn {\n\t\t\tdecision: {\n\t\t\t\t...args.baseline,\n\t\t\t\treasons: [...args.baseline.reasons, \"Route judge unavailable; baseline kept\"],\n\t\t\t},\n\t\t\tfallbackReason: bounded.failure ? `judge_${bounded.failure.reasonCode}` : \"judge_unavailable_fallback\",\n\t\t\tcostUsd,\n\t\t};\n\t}\n\tif (bounded.completion.stopReason === \"error\" || bounded.completion.stopReason === \"aborted\") {\n\t\treturn {\n\t\t\tdecision: { ...args.baseline, reasons: [...args.baseline.reasons, \"Route judge errored; baseline kept\"] },\n\t\t\tfallbackReason: \"judge_model_error\",\n\t\t\tcostUsd,\n\t\t};\n\t}\n\n\tconst verdict = parseRouteJudgeVerdict(bounded.completion.text);\n\tif (!verdict) {\n\t\treturn {\n\t\t\tdecision: { ...args.baseline, reasons: [...args.baseline.reasons, \"Route judge unparseable; baseline kept\"] },\n\t\t\tfallbackReason: \"judge_unparseable_fallback\",\n\t\t\tcostUsd,\n\t\t};\n\t}\n\n\treturn { decision: applyRouteJudgeVerdict(args.baseline, verdict), verdict, costUsd };\n}\n"]}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { runBoundedCompletion } from "../autonomy/bounded-completion.js";
|
|
2
|
+
/**
|
|
3
|
+
* Routing-only judge: a bounded, tool-less completion (default: the medium model) that decides the
|
|
4
|
+
* final cheap/medium/expensive tier for a user prompt, refining the regex classifier's baseline.
|
|
5
|
+
* Core rule: planning is never cheap unless the judge explicitly deems the task trivial. The judge
|
|
6
|
+
* proposes; the existing pipeline (model resolution, auth, escalation, gates) still decides.
|
|
7
|
+
* Failure is honest: unparseable/timeout/unavailable falls back to the baseline with a visible
|
|
8
|
+
* reasonCode, never silently.
|
|
9
|
+
*/
|
|
10
|
+
/** Static across calls — callers pass cacheRetention "short" so only the variable tail is billed. */
|
|
11
|
+
export const ROUTE_JUDGE_SYSTEM_PROMPT = [
|
|
12
|
+
"You are a routing judge for a coding agent. You only route; you never answer the task.",
|
|
13
|
+
"Pick which model tier should handle the user prompt:",
|
|
14
|
+
'- "cheap": trivial, mechanical, read-only lookups only.',
|
|
15
|
+
'- "medium": normal implementation, scoped edits, tests, and NON-trivial planning/design.',
|
|
16
|
+
'- "expensive": architecture, ambiguity, security/auth, destructive or release operations, high-impact changes.',
|
|
17
|
+
"Planning, design, and strategy prompts are NEVER cheap unless the task is genuinely trivial.",
|
|
18
|
+
"Respond with STRICT JSON only - no prose:",
|
|
19
|
+
'{"tier":"cheap"|"medium"|"expensive","risk":"read-only"|"scoped-write"|"high-impact"|"approval-required","trivial":true|false,"reason":"<short reason>"}',
|
|
20
|
+
].join("\n");
|
|
21
|
+
export const ROUTE_JUDGE_MAX_OUTPUT_TOKENS = 128;
|
|
22
|
+
export const ROUTE_JUDGE_MAX_WALL_CLOCK_MS = 10_000;
|
|
23
|
+
export function buildRouteJudgeUserPrompt(args) {
|
|
24
|
+
return [
|
|
25
|
+
`Baseline (regex) verdict: tier=${args.baseline.tier}, risk=${args.baseline.risk}, reason=${args.baseline.reasonCode}.`,
|
|
26
|
+
"User prompt:",
|
|
27
|
+
args.prompt.slice(0, 4000),
|
|
28
|
+
].join("\n");
|
|
29
|
+
}
|
|
30
|
+
const JUDGE_TIERS = ["cheap", "medium", "expensive"];
|
|
31
|
+
const JUDGE_RISKS = ["read-only", "scoped-write", "high-impact", "approval-required"];
|
|
32
|
+
export function parseRouteJudgeVerdict(text) {
|
|
33
|
+
const trimmed = text.trim();
|
|
34
|
+
const candidates = [trimmed];
|
|
35
|
+
const fenced = /```(?:json)?\s*([\s\S]*?)```/.exec(trimmed);
|
|
36
|
+
if (fenced?.[1])
|
|
37
|
+
candidates.push(fenced[1].trim());
|
|
38
|
+
const start = trimmed.indexOf("{");
|
|
39
|
+
const end = trimmed.lastIndexOf("}");
|
|
40
|
+
if (start >= 0 && end > start)
|
|
41
|
+
candidates.push(trimmed.slice(start, end + 1));
|
|
42
|
+
for (const candidate of candidates) {
|
|
43
|
+
let parsed;
|
|
44
|
+
try {
|
|
45
|
+
parsed = JSON.parse(candidate);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
51
|
+
continue;
|
|
52
|
+
const record = parsed;
|
|
53
|
+
// The judge may never select the learning tier or anything outside the three foreground tiers.
|
|
54
|
+
if (typeof record.tier !== "string" || !JUDGE_TIERS.includes(record.tier))
|
|
55
|
+
continue;
|
|
56
|
+
const risk = typeof record.risk === "string" && JUDGE_RISKS.includes(record.risk)
|
|
57
|
+
? record.risk
|
|
58
|
+
: undefined;
|
|
59
|
+
if (!risk)
|
|
60
|
+
continue;
|
|
61
|
+
return {
|
|
62
|
+
tier: record.tier,
|
|
63
|
+
risk,
|
|
64
|
+
trivial: record.trivial === true,
|
|
65
|
+
reason: typeof record.reason === "string" ? record.reason.slice(0, 200) : "",
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
/** Merge a judge verdict into the baseline decision (pure; never returns learning). */
|
|
71
|
+
export function applyRouteJudgeVerdict(baseline, verdict) {
|
|
72
|
+
// Enforce the core rule in code, not just in the judge prompt: downgrading a non-cheap
|
|
73
|
+
// baseline to cheap requires an EXPLICIT trivial verdict. An untrusted judge saying
|
|
74
|
+
// {tier:"cheap", trivial:false} for an elevated prompt keeps the baseline tier.
|
|
75
|
+
const tier = verdict.tier === "cheap" && baseline.tier !== "cheap" && !verdict.trivial ? baseline.tier : verdict.tier;
|
|
76
|
+
return {
|
|
77
|
+
...baseline,
|
|
78
|
+
tier,
|
|
79
|
+
risk: verdict.risk,
|
|
80
|
+
confidence: Math.max(baseline.confidence, 0.75),
|
|
81
|
+
reasonCode: `judge_${tier}${verdict.trivial ? "_trivial" : ""}`,
|
|
82
|
+
reasons: [...baseline.reasons, `Route judge: ${verdict.reason || "no reason given"}`],
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Run the judge over a baseline decision. The completion executor is injected (production:
|
|
87
|
+
* AgentSession.runIsolatedCompletion on the judge model). Never throws; every failure keeps the
|
|
88
|
+
* baseline with a visible fallbackReason.
|
|
89
|
+
*/
|
|
90
|
+
export async function runRouteJudge(args) {
|
|
91
|
+
const bounded = await runBoundedCompletion({
|
|
92
|
+
maxWallClockMs: args.maxWallClockMs ?? ROUTE_JUDGE_MAX_WALL_CLOCK_MS,
|
|
93
|
+
signal: args.signal,
|
|
94
|
+
execute: (signal) => args.complete({
|
|
95
|
+
systemPrompt: ROUTE_JUDGE_SYSTEM_PROMPT,
|
|
96
|
+
userPrompt: buildRouteJudgeUserPrompt({ prompt: args.prompt, baseline: args.baseline }),
|
|
97
|
+
signal,
|
|
98
|
+
}),
|
|
99
|
+
});
|
|
100
|
+
const costUsd = bounded.completion?.costUsd ?? 0;
|
|
101
|
+
if (bounded.failure || !bounded.completion) {
|
|
102
|
+
return {
|
|
103
|
+
decision: {
|
|
104
|
+
...args.baseline,
|
|
105
|
+
reasons: [...args.baseline.reasons, "Route judge unavailable; baseline kept"],
|
|
106
|
+
},
|
|
107
|
+
fallbackReason: bounded.failure ? `judge_${bounded.failure.reasonCode}` : "judge_unavailable_fallback",
|
|
108
|
+
costUsd,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
if (bounded.completion.stopReason === "error" || bounded.completion.stopReason === "aborted") {
|
|
112
|
+
return {
|
|
113
|
+
decision: { ...args.baseline, reasons: [...args.baseline.reasons, "Route judge errored; baseline kept"] },
|
|
114
|
+
fallbackReason: "judge_model_error",
|
|
115
|
+
costUsd,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
const verdict = parseRouteJudgeVerdict(bounded.completion.text);
|
|
119
|
+
if (!verdict) {
|
|
120
|
+
return {
|
|
121
|
+
decision: { ...args.baseline, reasons: [...args.baseline.reasons, "Route judge unparseable; baseline kept"] },
|
|
122
|
+
fallbackReason: "judge_unparseable_fallback",
|
|
123
|
+
costUsd,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
return { decision: applyRouteJudgeVerdict(args.baseline, verdict), verdict, costUsd };
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=route-judge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-judge.js","sourceRoot":"","sources":["../../../src/core/model-router/route-judge.ts"],"names":[],"mappings":"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","sourcesContent":["import { runBoundedCompletion } from \"../autonomy/bounded-completion.ts\";\nimport type { RouteDecision } from \"../autonomy/contracts.ts\";\n\n/**\n * Routing-only judge: a bounded, tool-less completion (default: the medium model) that decides the\n * final cheap/medium/expensive tier for a user prompt, refining the regex classifier's baseline.\n * Core rule: planning is never cheap unless the judge explicitly deems the task trivial. The judge\n * proposes; the existing pipeline (model resolution, auth, escalation, gates) still decides.\n * Failure is honest: unparseable/timeout/unavailable falls back to the baseline with a visible\n * reasonCode, never silently.\n */\n\n/** Static across calls — callers pass cacheRetention \"short\" so only the variable tail is billed. */\nexport const ROUTE_JUDGE_SYSTEM_PROMPT = [\n\t\"You are a routing judge for a coding agent. You only route; you never answer the task.\",\n\t\"Pick which model tier should handle the user prompt:\",\n\t'- \"cheap\": trivial, mechanical, read-only lookups only.',\n\t'- \"medium\": normal implementation, scoped edits, tests, and NON-trivial planning/design.',\n\t'- \"expensive\": architecture, ambiguity, security/auth, destructive or release operations, high-impact changes.',\n\t\"Planning, design, and strategy prompts are NEVER cheap unless the task is genuinely trivial.\",\n\t\"Respond with STRICT JSON only - no prose:\",\n\t'{\"tier\":\"cheap\"|\"medium\"|\"expensive\",\"risk\":\"read-only\"|\"scoped-write\"|\"high-impact\"|\"approval-required\",\"trivial\":true|false,\"reason\":\"<short reason>\"}',\n].join(\"\\n\");\n\nexport const ROUTE_JUDGE_MAX_OUTPUT_TOKENS = 128;\nexport const ROUTE_JUDGE_MAX_WALL_CLOCK_MS = 10_000;\n\nexport interface RouteJudgeVerdict {\n\ttier: \"cheap\" | \"medium\" | \"expensive\";\n\trisk: RouteDecision[\"risk\"];\n\ttrivial: boolean;\n\treason: string;\n}\n\nexport function buildRouteJudgeUserPrompt(args: { prompt: string; baseline: RouteDecision }): string {\n\treturn [\n\t\t`Baseline (regex) verdict: tier=${args.baseline.tier}, risk=${args.baseline.risk}, reason=${args.baseline.reasonCode}.`,\n\t\t\"User prompt:\",\n\t\targs.prompt.slice(0, 4000),\n\t].join(\"\\n\");\n}\n\nconst JUDGE_TIERS: readonly string[] = [\"cheap\", \"medium\", \"expensive\"];\nconst JUDGE_RISKS: readonly string[] = [\"read-only\", \"scoped-write\", \"high-impact\", \"approval-required\"];\n\nexport function parseRouteJudgeVerdict(text: string): RouteJudgeVerdict | undefined {\n\tconst trimmed = text.trim();\n\tconst candidates: string[] = [trimmed];\n\tconst fenced = /```(?:json)?\\s*([\\s\\S]*?)```/.exec(trimmed);\n\tif (fenced?.[1]) candidates.push(fenced[1].trim());\n\tconst start = trimmed.indexOf(\"{\");\n\tconst end = trimmed.lastIndexOf(\"}\");\n\tif (start >= 0 && end > start) candidates.push(trimmed.slice(start, end + 1));\n\n\tfor (const candidate of candidates) {\n\t\tlet parsed: unknown;\n\t\ttry {\n\t\t\tparsed = JSON.parse(candidate);\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t\tif (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) continue;\n\t\tconst record = parsed as Record<string, unknown>;\n\t\t// The judge may never select the learning tier or anything outside the three foreground tiers.\n\t\tif (typeof record.tier !== \"string\" || !JUDGE_TIERS.includes(record.tier)) continue;\n\t\tconst risk =\n\t\t\ttypeof record.risk === \"string\" && JUDGE_RISKS.includes(record.risk)\n\t\t\t\t? (record.risk as RouteDecision[\"risk\"])\n\t\t\t\t: undefined;\n\t\tif (!risk) continue;\n\t\treturn {\n\t\t\ttier: record.tier as RouteJudgeVerdict[\"tier\"],\n\t\t\trisk,\n\t\t\ttrivial: record.trivial === true,\n\t\t\treason: typeof record.reason === \"string\" ? record.reason.slice(0, 200) : \"\",\n\t\t};\n\t}\n\treturn undefined;\n}\n\n/** Merge a judge verdict into the baseline decision (pure; never returns learning). */\nexport function applyRouteJudgeVerdict(baseline: RouteDecision, verdict: RouteJudgeVerdict): RouteDecision {\n\t// Enforce the core rule in code, not just in the judge prompt: downgrading a non-cheap\n\t// baseline to cheap requires an EXPLICIT trivial verdict. An untrusted judge saying\n\t// {tier:\"cheap\", trivial:false} for an elevated prompt keeps the baseline tier.\n\tconst tier =\n\t\tverdict.tier === \"cheap\" && baseline.tier !== \"cheap\" && !verdict.trivial ? baseline.tier : verdict.tier;\n\treturn {\n\t\t...baseline,\n\t\ttier,\n\t\trisk: verdict.risk,\n\t\tconfidence: Math.max(baseline.confidence, 0.75),\n\t\treasonCode: `judge_${tier}${verdict.trivial ? \"_trivial\" : \"\"}`,\n\t\treasons: [...baseline.reasons, `Route judge: ${verdict.reason || \"no reason given\"}`],\n\t};\n}\n\nexport interface RouteJudgeRunResult {\n\tdecision: RouteDecision;\n\tverdict?: RouteJudgeVerdict;\n\t/** Set when the judge could not decide and the baseline was kept. */\n\tfallbackReason?: string;\n\tcostUsd: number;\n}\n\n/**\n * Run the judge over a baseline decision. The completion executor is injected (production:\n * AgentSession.runIsolatedCompletion on the judge model). Never throws; every failure keeps the\n * baseline with a visible fallbackReason.\n */\nexport async function runRouteJudge(args: {\n\tprompt: string;\n\tbaseline: RouteDecision;\n\tcomplete: (input: { systemPrompt: string; userPrompt: string; signal?: AbortSignal }) => Promise<{\n\t\ttext: string;\n\t\tcostUsd: number;\n\t\tstopReason: string;\n\t}>;\n\tsignal?: AbortSignal;\n\tmaxWallClockMs?: number;\n}): Promise<RouteJudgeRunResult> {\n\tconst bounded = await runBoundedCompletion({\n\t\tmaxWallClockMs: args.maxWallClockMs ?? ROUTE_JUDGE_MAX_WALL_CLOCK_MS,\n\t\tsignal: args.signal,\n\t\texecute: (signal) =>\n\t\t\targs.complete({\n\t\t\t\tsystemPrompt: ROUTE_JUDGE_SYSTEM_PROMPT,\n\t\t\t\tuserPrompt: buildRouteJudgeUserPrompt({ prompt: args.prompt, baseline: args.baseline }),\n\t\t\t\tsignal,\n\t\t\t}),\n\t});\n\tconst costUsd = bounded.completion?.costUsd ?? 0;\n\n\tif (bounded.failure || !bounded.completion) {\n\t\treturn {\n\t\t\tdecision: {\n\t\t\t\t...args.baseline,\n\t\t\t\treasons: [...args.baseline.reasons, \"Route judge unavailable; baseline kept\"],\n\t\t\t},\n\t\t\tfallbackReason: bounded.failure ? `judge_${bounded.failure.reasonCode}` : \"judge_unavailable_fallback\",\n\t\t\tcostUsd,\n\t\t};\n\t}\n\tif (bounded.completion.stopReason === \"error\" || bounded.completion.stopReason === \"aborted\") {\n\t\treturn {\n\t\t\tdecision: { ...args.baseline, reasons: [...args.baseline.reasons, \"Route judge errored; baseline kept\"] },\n\t\t\tfallbackReason: \"judge_model_error\",\n\t\t\tcostUsd,\n\t\t};\n\t}\n\n\tconst verdict = parseRouteJudgeVerdict(bounded.completion.text);\n\tif (!verdict) {\n\t\treturn {\n\t\t\tdecision: { ...args.baseline, reasons: [...args.baseline.reasons, \"Route judge unparseable; baseline kept\"] },\n\t\t\tfallbackReason: \"judge_unparseable_fallback\",\n\t\t\tcostUsd,\n\t\t};\n\t}\n\n\treturn { decision: applyRouteJudgeVerdict(args.baseline, verdict), verdict, costUsd };\n}\n"]}
|
|
@@ -1,17 +1,20 @@
|
|
|
1
|
+
import type { RouteDecision } from "../autonomy/contracts.ts";
|
|
1
2
|
import type { SessionEntry } from "../session-manager.ts";
|
|
2
3
|
import type { ModelRouterIntent } from "./intent-classifier.ts";
|
|
3
4
|
export declare const MODEL_ROUTER_DECISION_CUSTOM_TYPE = "model_router_decision";
|
|
4
5
|
export type ModelRouterStatusSettings = {
|
|
5
6
|
enabled: boolean;
|
|
6
7
|
cheapModel?: string;
|
|
8
|
+
mediumModel?: string;
|
|
7
9
|
expensiveModel?: string;
|
|
8
10
|
learningModel?: string;
|
|
9
11
|
};
|
|
10
12
|
export type ModelRouterDecisionStatus = {
|
|
11
|
-
|
|
13
|
+
route: RouteDecision;
|
|
12
14
|
routedModel: string;
|
|
13
15
|
outcome: "routed" | "escalated" | "failed";
|
|
14
16
|
retryModel?: string;
|
|
17
|
+
intent?: ModelRouterIntent;
|
|
15
18
|
};
|
|
16
19
|
export declare function getRecentModelRouterDecisions(entries: SessionEntry[], limit?: number): ModelRouterDecisionStatus[];
|
|
17
20
|
export declare function formatModelRouterStatus(settings: ModelRouterStatusSettings, lastDecision?: ModelRouterDecisionStatus, formatLabel?: (label: string) => string, recentDecisions?: ModelRouterDecisionStatus[], lastSkipReason?: string, latestIntent?: ModelRouterIntent): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/core/model-router/status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAEhE,eAAO,MAAM,iCAAiC,0BAA0B,CAAC;AAEzE,MAAM,MAAM,yBAAyB,GAAG;IACvC,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACvC,
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/core/model-router/status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,aAAa,EAAa,MAAM,0BAA0B,CAAC;AACpF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAEhE,eAAO,MAAM,iCAAiC,0BAA0B,CAAC;AAEzE,MAAM,MAAM,yBAAyB,GAAG;IACvC,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACvC,KAAK,EAAE,aAAa,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,QAAQ,GAAG,WAAW,GAAG,QAAQ,CAAC;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC3B,CAAC;AAiDF,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,KAAK,SAAI,GAAG,yBAAyB,EAAE,CAQ7G;AAED,wBAAgB,uBAAuB,CACtC,QAAQ,EAAE,yBAAyB,EACnC,YAAY,CAAC,EAAE,yBAAyB,EACxC,WAAW,GAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAyB,EACzD,eAAe,GAAE,yBAAyB,EAAO,EACjD,cAAc,CAAC,EAAE,MAAM,EACvB,YAAY,CAAC,EAAE,iBAAiB,GAC9B,MAAM,CA+BR","sourcesContent":["import type { ModelTier, RouteDecision, RouteRisk } from \"../autonomy/contracts.ts\";\nimport type { SessionEntry } from \"../session-manager.ts\";\nimport type { ModelRouterIntent } from \"./intent-classifier.ts\";\n\nexport const MODEL_ROUTER_DECISION_CUSTOM_TYPE = \"model_router_decision\";\n\nexport type ModelRouterStatusSettings = {\n\tenabled: boolean;\n\tcheapModel?: string;\n\tmediumModel?: string;\n\texpensiveModel?: string;\n\tlearningModel?: string;\n};\n\nexport type ModelRouterDecisionStatus = {\n\troute: RouteDecision;\n\troutedModel: string;\n\toutcome: \"routed\" | \"escalated\" | \"failed\";\n\tretryModel?: string;\n\tintent?: ModelRouterIntent;\n};\n\nfunction isRouteDecision(value: unknown): value is RouteDecision {\n\tif (!value || typeof value !== \"object\") return false;\n\tconst route = value as Partial<RouteDecision>;\n\tconst validTiers = new Set<ModelTier>([\"cheap\", \"medium\", \"expensive\", \"learning\"]);\n\tconst validRisks = new Set<RouteRisk>([\"read-only\", \"scoped-write\", \"high-impact\", \"approval-required\"]);\n\n\treturn (\n\t\ttypeof route.confidence === \"number\" &&\n\t\ttypeof route.reasonCode === \"string\" &&\n\t\tArray.isArray(route.reasons) &&\n\t\troute.reasons.every((r) => typeof r === \"string\") &&\n\t\tvalidTiers.has(route.tier as ModelTier) &&\n\t\tvalidRisks.has(route.risk as RouteRisk) &&\n\t\t(route.model === undefined || typeof route.model === \"string\") &&\n\t\t(route.fallbackFrom === undefined ||\n\t\t\troute.fallbackFrom === \"cheap\" ||\n\t\t\troute.fallbackFrom === \"medium\" ||\n\t\t\troute.fallbackFrom === \"expensive\" ||\n\t\t\troute.fallbackFrom === \"learning\") &&\n\t\t(route.createdAt === undefined || typeof route.createdAt === \"string\")\n\t);\n}\n\nfunction isModelRouterDecisionStatus(data: unknown): data is ModelRouterDecisionStatus {\n\tif (!data || typeof data !== \"object\") return false;\n\tconst record = data as Partial<ModelRouterDecisionStatus>;\n\treturn (\n\t\tisRouteDecision(record.route) &&\n\t\trecord.route.tier !== \"learning\" && // Validate user prompt decisions never need learning tier in runtime\n\t\ttypeof record.routedModel === \"string\" &&\n\t\t(record.outcome === \"routed\" || record.outcome === \"escalated\" || record.outcome === \"failed\") &&\n\t\t(record.retryModel === undefined || typeof record.retryModel === \"string\") &&\n\t\t(record.intent === undefined || record.intent === \"research\" || record.intent === \"modify\")\n\t);\n}\n\nfunction formatDecision(decision: ModelRouterDecisionStatus): string {\n\tconst { tier, risk, reasonCode } = decision.route;\n\tlet outcomeText: string = decision.outcome;\n\tif (decision.outcome === \"escalated\" && decision.retryModel) {\n\t\toutcomeText = `escalated -> ${decision.retryModel}`;\n\t} else if (decision.outcome === \"failed\") {\n\t\toutcomeText = \"failed\";\n\t}\n\treturn `${tier}/${risk} -> ${decision.routedModel} (${reasonCode}, ${outcomeText})`;\n}\n\nexport function getRecentModelRouterDecisions(entries: SessionEntry[], limit = 3): ModelRouterDecisionStatus[] {\n\tconst decisions: ModelRouterDecisionStatus[] = [];\n\tfor (const entry of entries) {\n\t\tif (entry.type !== \"custom\" || entry.customType !== MODEL_ROUTER_DECISION_CUSTOM_TYPE) continue;\n\t\tif (!isModelRouterDecisionStatus(entry.data)) continue;\n\t\tdecisions.push(entry.data);\n\t}\n\treturn decisions.slice(-limit);\n}\n\nexport function formatModelRouterStatus(\n\tsettings: ModelRouterStatusSettings,\n\tlastDecision?: ModelRouterDecisionStatus,\n\tformatLabel: (label: string) => string = (label) => label,\n\trecentDecisions: ModelRouterDecisionStatus[] = [],\n\tlastSkipReason?: string,\n\tlatestIntent?: ModelRouterIntent,\n): string {\n\tconst effectiveLastDecision = lastSkipReason ? undefined : lastDecision;\n\tconst lines = [\n\t\t`${formatLabel(\"Status:\")} ${settings.enabled ? \"enabled\" : \"disabled\"}`,\n\t\t`${formatLabel(\"Cheap model:\")} ${settings.cheapModel ?? \"unset\"}`,\n\t\t`${formatLabel(\"Medium model:\")} ${settings.mediumModel ?? \"unset\"}`,\n\t\t`${formatLabel(\"Expensive model:\")} ${settings.expensiveModel ?? \"unset\"}`,\n\t\t`${formatLabel(\"Learning model:\")} ${settings.learningModel ?? \"active\"}`,\n\t];\n\tif (!settings.enabled) {\n\t\tlines.push(`${formatLabel(\"Routing:\")} inactive (disabled)`);\n\t} else if (lastSkipReason) {\n\t\tlines.push(`${formatLabel(\"Routing:\")} skipped (${lastSkipReason})`);\n\t} else if (effectiveLastDecision) {\n\t\tlines.push(`${formatLabel(\"Routing:\")} active`);\n\t} else {\n\t\tlines.push(`${formatLabel(\"Routing:\")} waiting for prompt`);\n\t}\n\tlines.push(`${formatLabel(\"Latest intent:\")} ${latestIntent ?? \"none\"}`);\n\tif (!effectiveLastDecision) {\n\t\tlines.push(`${formatLabel(\"Last decision:\")} none`);\n\t} else {\n\t\tlines.push(`${formatLabel(\"Last decision:\")} ${formatDecision(effectiveLastDecision)}`);\n\t}\n\tif (recentDecisions.length > 0) {\n\t\tlines.push(formatLabel(\"Recent decisions:\"));\n\t\tfor (const decision of recentDecisions) {\n\t\t\tlines.push(`- ${formatDecision(decision)}`);\n\t\t}\n\t}\n\treturn lines.join(\"\\n\");\n}\n"]}
|
|
@@ -1,22 +1,45 @@
|
|
|
1
1
|
export const MODEL_ROUTER_DECISION_CUSTOM_TYPE = "model_router_decision";
|
|
2
|
+
function isRouteDecision(value) {
|
|
3
|
+
if (!value || typeof value !== "object")
|
|
4
|
+
return false;
|
|
5
|
+
const route = value;
|
|
6
|
+
const validTiers = new Set(["cheap", "medium", "expensive", "learning"]);
|
|
7
|
+
const validRisks = new Set(["read-only", "scoped-write", "high-impact", "approval-required"]);
|
|
8
|
+
return (typeof route.confidence === "number" &&
|
|
9
|
+
typeof route.reasonCode === "string" &&
|
|
10
|
+
Array.isArray(route.reasons) &&
|
|
11
|
+
route.reasons.every((r) => typeof r === "string") &&
|
|
12
|
+
validTiers.has(route.tier) &&
|
|
13
|
+
validRisks.has(route.risk) &&
|
|
14
|
+
(route.model === undefined || typeof route.model === "string") &&
|
|
15
|
+
(route.fallbackFrom === undefined ||
|
|
16
|
+
route.fallbackFrom === "cheap" ||
|
|
17
|
+
route.fallbackFrom === "medium" ||
|
|
18
|
+
route.fallbackFrom === "expensive" ||
|
|
19
|
+
route.fallbackFrom === "learning") &&
|
|
20
|
+
(route.createdAt === undefined || typeof route.createdAt === "string"));
|
|
21
|
+
}
|
|
2
22
|
function isModelRouterDecisionStatus(data) {
|
|
3
23
|
if (!data || typeof data !== "object")
|
|
4
24
|
return false;
|
|
5
25
|
const record = data;
|
|
6
|
-
return ((record.
|
|
26
|
+
return (isRouteDecision(record.route) &&
|
|
27
|
+
record.route.tier !== "learning" && // Validate user prompt decisions never need learning tier in runtime
|
|
7
28
|
typeof record.routedModel === "string" &&
|
|
8
29
|
(record.outcome === "routed" || record.outcome === "escalated" || record.outcome === "failed") &&
|
|
9
|
-
(record.retryModel === undefined || typeof record.retryModel === "string")
|
|
30
|
+
(record.retryModel === undefined || typeof record.retryModel === "string") &&
|
|
31
|
+
(record.intent === undefined || record.intent === "research" || record.intent === "modify"));
|
|
10
32
|
}
|
|
11
33
|
function formatDecision(decision) {
|
|
12
|
-
|
|
34
|
+
const { tier, risk, reasonCode } = decision.route;
|
|
35
|
+
let outcomeText = decision.outcome;
|
|
13
36
|
if (decision.outcome === "escalated" && decision.retryModel) {
|
|
14
|
-
|
|
37
|
+
outcomeText = `escalated -> ${decision.retryModel}`;
|
|
15
38
|
}
|
|
16
39
|
else if (decision.outcome === "failed") {
|
|
17
|
-
|
|
40
|
+
outcomeText = "failed";
|
|
18
41
|
}
|
|
19
|
-
return
|
|
42
|
+
return `${tier}/${risk} -> ${decision.routedModel} (${reasonCode}, ${outcomeText})`;
|
|
20
43
|
}
|
|
21
44
|
export function getRecentModelRouterDecisions(entries, limit = 3) {
|
|
22
45
|
const decisions = [];
|
|
@@ -34,6 +57,7 @@ export function formatModelRouterStatus(settings, lastDecision, formatLabel = (l
|
|
|
34
57
|
const lines = [
|
|
35
58
|
`${formatLabel("Status:")} ${settings.enabled ? "enabled" : "disabled"}`,
|
|
36
59
|
`${formatLabel("Cheap model:")} ${settings.cheapModel ?? "unset"}`,
|
|
60
|
+
`${formatLabel("Medium model:")} ${settings.mediumModel ?? "unset"}`,
|
|
37
61
|
`${formatLabel("Expensive model:")} ${settings.expensiveModel ?? "unset"}`,
|
|
38
62
|
`${formatLabel("Learning model:")} ${settings.learningModel ?? "active"}`,
|
|
39
63
|
];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/core/model-router/status.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/core/model-router/status.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ModelTier, RouteDecision, RouteRisk } from \"../autonomy/contracts.ts\";\nimport type { SessionEntry } from \"../session-manager.ts\";\nimport type { ModelRouterIntent } from \"./intent-classifier.ts\";\n\nexport const MODEL_ROUTER_DECISION_CUSTOM_TYPE = \"model_router_decision\";\n\nexport type ModelRouterStatusSettings = {\n\tenabled: boolean;\n\tcheapModel?: string;\n\tmediumModel?: string;\n\texpensiveModel?: string;\n\tlearningModel?: string;\n};\n\nexport type ModelRouterDecisionStatus = {\n\troute: RouteDecision;\n\troutedModel: string;\n\toutcome: \"routed\" | \"escalated\" | \"failed\";\n\tretryModel?: string;\n\tintent?: ModelRouterIntent;\n};\n\nfunction isRouteDecision(value: unknown): value is RouteDecision {\n\tif (!value || typeof value !== \"object\") return false;\n\tconst route = value as Partial<RouteDecision>;\n\tconst validTiers = new Set<ModelTier>([\"cheap\", \"medium\", \"expensive\", \"learning\"]);\n\tconst validRisks = new Set<RouteRisk>([\"read-only\", \"scoped-write\", \"high-impact\", \"approval-required\"]);\n\n\treturn (\n\t\ttypeof route.confidence === \"number\" &&\n\t\ttypeof route.reasonCode === \"string\" &&\n\t\tArray.isArray(route.reasons) &&\n\t\troute.reasons.every((r) => typeof r === \"string\") &&\n\t\tvalidTiers.has(route.tier as ModelTier) &&\n\t\tvalidRisks.has(route.risk as RouteRisk) &&\n\t\t(route.model === undefined || typeof route.model === \"string\") &&\n\t\t(route.fallbackFrom === undefined ||\n\t\t\troute.fallbackFrom === \"cheap\" ||\n\t\t\troute.fallbackFrom === \"medium\" ||\n\t\t\troute.fallbackFrom === \"expensive\" ||\n\t\t\troute.fallbackFrom === \"learning\") &&\n\t\t(route.createdAt === undefined || typeof route.createdAt === \"string\")\n\t);\n}\n\nfunction isModelRouterDecisionStatus(data: unknown): data is ModelRouterDecisionStatus {\n\tif (!data || typeof data !== \"object\") return false;\n\tconst record = data as Partial<ModelRouterDecisionStatus>;\n\treturn (\n\t\tisRouteDecision(record.route) &&\n\t\trecord.route.tier !== \"learning\" && // Validate user prompt decisions never need learning tier in runtime\n\t\ttypeof record.routedModel === \"string\" &&\n\t\t(record.outcome === \"routed\" || record.outcome === \"escalated\" || record.outcome === \"failed\") &&\n\t\t(record.retryModel === undefined || typeof record.retryModel === \"string\") &&\n\t\t(record.intent === undefined || record.intent === \"research\" || record.intent === \"modify\")\n\t);\n}\n\nfunction formatDecision(decision: ModelRouterDecisionStatus): string {\n\tconst { tier, risk, reasonCode } = decision.route;\n\tlet outcomeText: string = decision.outcome;\n\tif (decision.outcome === \"escalated\" && decision.retryModel) {\n\t\toutcomeText = `escalated -> ${decision.retryModel}`;\n\t} else if (decision.outcome === \"failed\") {\n\t\toutcomeText = \"failed\";\n\t}\n\treturn `${tier}/${risk} -> ${decision.routedModel} (${reasonCode}, ${outcomeText})`;\n}\n\nexport function getRecentModelRouterDecisions(entries: SessionEntry[], limit = 3): ModelRouterDecisionStatus[] {\n\tconst decisions: ModelRouterDecisionStatus[] = [];\n\tfor (const entry of entries) {\n\t\tif (entry.type !== \"custom\" || entry.customType !== MODEL_ROUTER_DECISION_CUSTOM_TYPE) continue;\n\t\tif (!isModelRouterDecisionStatus(entry.data)) continue;\n\t\tdecisions.push(entry.data);\n\t}\n\treturn decisions.slice(-limit);\n}\n\nexport function formatModelRouterStatus(\n\tsettings: ModelRouterStatusSettings,\n\tlastDecision?: ModelRouterDecisionStatus,\n\tformatLabel: (label: string) => string = (label) => label,\n\trecentDecisions: ModelRouterDecisionStatus[] = [],\n\tlastSkipReason?: string,\n\tlatestIntent?: ModelRouterIntent,\n): string {\n\tconst effectiveLastDecision = lastSkipReason ? undefined : lastDecision;\n\tconst lines = [\n\t\t`${formatLabel(\"Status:\")} ${settings.enabled ? \"enabled\" : \"disabled\"}`,\n\t\t`${formatLabel(\"Cheap model:\")} ${settings.cheapModel ?? \"unset\"}`,\n\t\t`${formatLabel(\"Medium model:\")} ${settings.mediumModel ?? \"unset\"}`,\n\t\t`${formatLabel(\"Expensive model:\")} ${settings.expensiveModel ?? \"unset\"}`,\n\t\t`${formatLabel(\"Learning model:\")} ${settings.learningModel ?? \"active\"}`,\n\t];\n\tif (!settings.enabled) {\n\t\tlines.push(`${formatLabel(\"Routing:\")} inactive (disabled)`);\n\t} else if (lastSkipReason) {\n\t\tlines.push(`${formatLabel(\"Routing:\")} skipped (${lastSkipReason})`);\n\t} else if (effectiveLastDecision) {\n\t\tlines.push(`${formatLabel(\"Routing:\")} active`);\n\t} else {\n\t\tlines.push(`${formatLabel(\"Routing:\")} waiting for prompt`);\n\t}\n\tlines.push(`${formatLabel(\"Latest intent:\")} ${latestIntent ?? \"none\"}`);\n\tif (!effectiveLastDecision) {\n\t\tlines.push(`${formatLabel(\"Last decision:\")} none`);\n\t} else {\n\t\tlines.push(`${formatLabel(\"Last decision:\")} ${formatDecision(effectiveLastDecision)}`);\n\t}\n\tif (recentDecisions.length > 0) {\n\t\tlines.push(formatLabel(\"Recent decisions:\"));\n\t\tfor (const decision of recentDecisions) {\n\t\t\tlines.push(`- ${formatDecision(decision)}`);\n\t\t}\n\t}\n\treturn lines.join(\"\\n\");\n}\n"]}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import type { ModelTier } from "../autonomy/contracts.ts";
|
|
2
|
+
export declare function shouldEscalateModelRouterTool(options: {
|
|
3
|
+
tier: ModelTier;
|
|
4
4
|
toolName: string;
|
|
5
5
|
args?: unknown;
|
|
6
|
-
};
|
|
7
|
-
export declare function shouldEscalateModelRouterTool(options: ToolEscalationOptions): boolean;
|
|
8
|
-
export {};
|
|
6
|
+
}): boolean;
|
|
9
7
|
//# sourceMappingURL=tool-escalation.d.ts.map
|