agent-nuvira 2.7.2 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/agents/writer-tool-calling.d.ts +14 -0
- package/dist/agents/agents/writer-tool-calling.d.ts.map +1 -1
- package/dist/agents/agents/writer-tool-calling.js +20 -0
- package/dist/agents/agents/writer-tool-calling.js.map +1 -1
- package/dist/agents/agents/writer.d.ts.map +1 -1
- package/dist/agents/agents/writer.js +15 -4
- package/dist/agents/agents/writer.js.map +1 -1
- package/dist/agents/edit-module.d.ts +7 -0
- package/dist/agents/edit-module.d.ts.map +1 -1
- package/dist/agents/edit-module.js +21 -6
- package/dist/agents/edit-module.js.map +1 -1
- package/dist/agents/orchestrator.d.ts +40 -0
- package/dist/agents/orchestrator.d.ts.map +1 -1
- package/dist/agents/orchestrator.js +116 -27
- package/dist/agents/orchestrator.js.map +1 -1
- package/dist/agents/tool-calling-agent.d.ts +19 -0
- package/dist/agents/tool-calling-agent.d.ts.map +1 -1
- package/dist/agents/tool-calling-agent.js +42 -2
- package/dist/agents/tool-calling-agent.js.map +1 -1
- package/dist/auth-api.d.ts +2 -0
- package/dist/auth-api.d.ts.map +1 -0
- package/dist/auth-api.js +61 -0
- package/dist/auth-api.js.map +1 -0
- package/dist/auth.test.d.ts +1 -0
- package/dist/auth.test.d.ts.map +1 -0
- package/dist/auth.test.js +3 -0
- package/dist/auth.test.js.map +1 -0
- package/dist/cli/chat.d.ts +66 -1
- package/dist/cli/chat.d.ts.map +1 -1
- package/dist/cli/chat.js +323 -77
- package/dist/cli/chat.js.map +1 -1
- package/dist/cli/cli-program.d.ts +6 -0
- package/dist/cli/cli-program.d.ts.map +1 -0
- package/dist/cli/cli-program.js +222 -0
- package/dist/cli/cli-program.js.map +1 -0
- package/dist/cli/edit.d.ts.map +1 -1
- package/dist/cli/edit.js +18 -3
- package/dist/cli/edit.js.map +1 -1
- package/dist/cli/execute.d.ts.map +1 -1
- package/dist/cli/execute.js +29 -5
- package/dist/cli/execute.js.map +1 -1
- package/dist/cli/failover-runner.d.ts +13 -0
- package/dist/cli/failover-runner.d.ts.map +1 -1
- package/dist/cli/failover-runner.js +11 -0
- package/dist/cli/failover-runner.js.map +1 -1
- package/dist/cli/gateway.d.ts +16 -0
- package/dist/cli/gateway.d.ts.map +1 -1
- package/dist/cli/gateway.js +108 -2
- package/dist/cli/gateway.js.map +1 -1
- package/dist/cli/loop-executor.d.ts.map +1 -1
- package/dist/cli/loop-executor.js +296 -20
- package/dist/cli/loop-executor.js.map +1 -1
- package/dist/cli/plan.d.ts.map +1 -1
- package/dist/cli/plan.js +20 -6
- package/dist/cli/plan.js.map +1 -1
- package/dist/cli/process-control.d.ts +10 -0
- package/dist/cli/process-control.d.ts.map +1 -1
- package/dist/cli/process-control.js +73 -7
- package/dist/cli/process-control.js.map +1 -1
- package/dist/cli/router.d.ts +16 -5
- package/dist/cli/router.d.ts.map +1 -1
- package/dist/cli/router.js +31 -206
- package/dist/cli/router.js.map +1 -1
- package/dist/config/paths.d.ts +23 -0
- package/dist/config/paths.d.ts.map +1 -1
- package/dist/config/paths.js +30 -0
- package/dist/config/paths.js.map +1 -1
- package/dist/config/provider-env.d.ts +37 -0
- package/dist/config/provider-env.d.ts.map +1 -0
- package/dist/config/provider-env.js +86 -0
- package/dist/config/provider-env.js.map +1 -0
- package/dist/context/history.d.ts.map +1 -1
- package/dist/context/history.js +24 -8
- package/dist/context/history.js.map +1 -1
- package/dist/context/session-recall.d.ts +30 -0
- package/dist/context/session-recall.d.ts.map +1 -1
- package/dist/context/session-recall.js +61 -0
- package/dist/context/session-recall.js.map +1 -1
- package/dist/file.js +0 -1
- package/dist/file.js.map +1 -1
- package/dist/gateway/adapters.d.ts +10 -0
- package/dist/gateway/adapters.d.ts.map +1 -1
- package/dist/gateway/adapters.js +4 -1
- package/dist/gateway/adapters.js.map +1 -1
- package/dist/gateway/dedup.d.ts +105 -0
- package/dist/gateway/dedup.d.ts.map +1 -0
- package/dist/gateway/dedup.js +160 -0
- package/dist/gateway/dedup.js.map +1 -0
- package/dist/gateway/heartbeat.d.ts +99 -0
- package/dist/gateway/heartbeat.d.ts.map +1 -0
- package/dist/gateway/heartbeat.js +122 -0
- package/dist/gateway/heartbeat.js.map +1 -0
- package/dist/gateway/inbox.d.ts +14 -1
- package/dist/gateway/inbox.d.ts.map +1 -1
- package/dist/gateway/inbox.js.map +1 -1
- package/dist/gateway/platform-config.d.ts +5 -0
- package/dist/gateway/platform-config.d.ts.map +1 -1
- package/dist/gateway/platform-config.js +8 -13
- package/dist/gateway/platform-config.js.map +1 -1
- package/dist/gateway/registry.d.ts +65 -0
- package/dist/gateway/registry.d.ts.map +1 -1
- package/dist/gateway/registry.js +307 -32
- package/dist/gateway/registry.js.map +1 -1
- package/dist/gateway/whatsapp/baileys-bridge.d.ts +11 -1
- package/dist/gateway/whatsapp/baileys-bridge.d.ts.map +1 -1
- package/dist/gateway/whatsapp/baileys-bridge.js +64 -1
- package/dist/gateway/whatsapp/baileys-bridge.js.map +1 -1
- package/dist/gateway/whatsapp/bridge.d.ts +4 -2
- package/dist/gateway/whatsapp/bridge.d.ts.map +1 -1
- package/dist/gateway/whatsapp/bridge.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/inference/factory.d.ts +16 -0
- package/dist/inference/factory.d.ts.map +1 -1
- package/dist/inference/factory.js +42 -0
- package/dist/inference/factory.js.map +1 -1
- package/dist/inference/gemini-adapter.d.ts.map +1 -1
- package/dist/inference/gemini-adapter.js +3 -0
- package/dist/inference/gemini-adapter.js.map +1 -1
- package/dist/inference/interface.d.ts +12 -0
- package/dist/inference/interface.d.ts.map +1 -1
- package/dist/inference/local-adapter.d.ts +2 -0
- package/dist/inference/local-adapter.d.ts.map +1 -1
- package/dist/inference/local-adapter.js +36 -5
- package/dist/inference/local-adapter.js.map +1 -1
- package/dist/inference/model-catalog.d.ts +8 -0
- package/dist/inference/model-catalog.d.ts.map +1 -1
- package/dist/inference/model-catalog.js +40 -0
- package/dist/inference/model-catalog.js.map +1 -1
- package/dist/inference/model-probe.d.ts +7 -0
- package/dist/inference/model-probe.d.ts.map +1 -1
- package/dist/inference/model-probe.js +25 -7
- package/dist/inference/model-probe.js.map +1 -1
- package/dist/inference/native-tools.d.ts +8 -0
- package/dist/inference/native-tools.d.ts.map +1 -1
- package/dist/inference/native-tools.js +14 -3
- package/dist/inference/native-tools.js.map +1 -1
- package/dist/inference/tool-call-utils.d.ts +66 -7
- package/dist/inference/tool-call-utils.d.ts.map +1 -1
- package/dist/inference/tool-call-utils.js +134 -13
- package/dist/inference/tool-call-utils.js.map +1 -1
- package/dist/learning/auto-router.d.ts +21 -0
- package/dist/learning/auto-router.d.ts.map +1 -1
- package/dist/learning/auto-router.js +282 -21
- package/dist/learning/auto-router.js.map +1 -1
- package/dist/learning/context-budget.d.ts +133 -0
- package/dist/learning/context-budget.d.ts.map +1 -0
- package/dist/learning/context-budget.js +196 -0
- package/dist/learning/context-budget.js.map +1 -0
- package/dist/learning/cost-tracker.d.ts.map +1 -1
- package/dist/learning/cost-tracker.js +20 -8
- package/dist/learning/cost-tracker.js.map +1 -1
- package/dist/learning/eval-framework.d.ts.map +1 -1
- package/dist/learning/eval-framework.js +6 -2
- package/dist/learning/eval-framework.js.map +1 -1
- package/dist/learning/failure-bookkeeping.d.ts +41 -0
- package/dist/learning/failure-bookkeeping.d.ts.map +1 -1
- package/dist/learning/failure-bookkeeping.js +122 -4
- package/dist/learning/failure-bookkeeping.js.map +1 -1
- package/dist/learning/feedback.d.ts.map +1 -1
- package/dist/learning/feedback.js +19 -8
- package/dist/learning/feedback.js.map +1 -1
- package/dist/learning/model-first-router.d.ts.map +1 -1
- package/dist/learning/model-first-router.js +5 -11
- package/dist/learning/model-first-router.js.map +1 -1
- package/dist/learning/model-harness.d.ts +76 -0
- package/dist/learning/model-harness.d.ts.map +1 -0
- package/dist/learning/model-harness.js +119 -0
- package/dist/learning/model-harness.js.map +1 -0
- package/dist/learning/model-registry.d.ts +29 -0
- package/dist/learning/model-registry.d.ts.map +1 -1
- package/dist/learning/model-registry.js +129 -3
- package/dist/learning/model-registry.js.map +1 -1
- package/dist/learning/model-scoring.d.ts.map +1 -1
- package/dist/learning/model-scoring.js +6 -1
- package/dist/learning/model-scoring.js.map +1 -1
- package/dist/learning/model-selection.d.ts +15 -0
- package/dist/learning/model-selection.d.ts.map +1 -1
- package/dist/learning/model-selection.js +40 -1
- package/dist/learning/model-selection.js.map +1 -1
- package/dist/learning/provider-fallback.d.ts +12 -0
- package/dist/learning/provider-fallback.d.ts.map +1 -1
- package/dist/learning/provider-fallback.js +84 -0
- package/dist/learning/provider-fallback.js.map +1 -1
- package/dist/learning/provider-revival.d.ts +106 -0
- package/dist/learning/provider-revival.d.ts.map +1 -0
- package/dist/learning/provider-revival.js +154 -0
- package/dist/learning/provider-revival.js.map +1 -0
- package/dist/learning/quota-ledger.d.ts +64 -3
- package/dist/learning/quota-ledger.d.ts.map +1 -1
- package/dist/learning/quota-ledger.js +122 -9
- package/dist/learning/quota-ledger.js.map +1 -1
- package/dist/learning/resilient-call.d.ts +98 -0
- package/dist/learning/resilient-call.d.ts.map +1 -1
- package/dist/learning/resilient-call.js +252 -46
- package/dist/learning/resilient-call.js.map +1 -1
- package/dist/nlu/conversation-gate.d.ts +37 -0
- package/dist/nlu/conversation-gate.d.ts.map +1 -1
- package/dist/nlu/conversation-gate.js +49 -0
- package/dist/nlu/conversation-gate.js.map +1 -1
- package/dist/nlu/schema.d.ts +4 -4
- package/dist/observability/dag-bridge.d.ts +69 -0
- package/dist/observability/dag-bridge.d.ts.map +1 -0
- package/dist/observability/dag-bridge.js +56 -0
- package/dist/observability/dag-bridge.js.map +1 -0
- package/dist/observability/event-bus.d.ts +5 -10
- package/dist/observability/event-bus.d.ts.map +1 -1
- package/dist/observability/event-bus.js +10 -42
- package/dist/observability/event-bus.js.map +1 -1
- package/dist/routes/auth.d.ts +3 -0
- package/dist/routes/auth.d.ts.map +1 -0
- package/dist/routes/auth.js +41 -36
- package/dist/routes/auth.js.map +1 -0
- package/dist/skills/execution-audit.d.ts.map +1 -1
- package/dist/skills/execution-audit.js +17 -5
- package/dist/skills/execution-audit.js.map +1 -1
- package/dist/skills/sandbox-executor.d.ts +12 -1
- package/dist/skills/sandbox-executor.d.ts.map +1 -1
- package/dist/skills/sandbox-executor.js +28 -6
- package/dist/skills/sandbox-executor.js.map +1 -1
- package/dist/skills/secret-capture.d.ts +45 -1
- package/dist/skills/secret-capture.d.ts.map +1 -1
- package/dist/skills/secret-capture.js +82 -19
- package/dist/skills/secret-capture.js.map +1 -1
- package/dist/skills/skill-env-inventory.d.ts +79 -0
- package/dist/skills/skill-env-inventory.d.ts.map +1 -0
- package/dist/skills/skill-env-inventory.js +167 -0
- package/dist/skills/skill-env-inventory.js.map +1 -0
- package/dist/skills/skill-executor.d.ts +2 -0
- package/dist/skills/skill-executor.d.ts.map +1 -1
- package/dist/skills/skill-executor.js +19 -24
- package/dist/skills/skill-executor.js.map +1 -1
- package/dist/tools/ask-user.d.ts +14 -1
- package/dist/tools/ask-user.d.ts.map +1 -1
- package/dist/tools/ask-user.js +25 -1
- package/dist/tools/ask-user.js.map +1 -1
- package/dist/tools/followup-utils.d.ts +64 -0
- package/dist/tools/followup-utils.d.ts.map +1 -0
- package/dist/tools/followup-utils.js +158 -0
- package/dist/tools/followup-utils.js.map +1 -0
- package/dist/tools/memory-tools.d.ts +35 -0
- package/dist/tools/memory-tools.d.ts.map +1 -1
- package/dist/tools/memory-tools.js +76 -0
- package/dist/tools/memory-tools.js.map +1 -1
- package/dist/tools/pipeline-tool.d.ts.map +1 -1
- package/dist/tools/pipeline-tool.js +8 -3
- package/dist/tools/pipeline-tool.js.map +1 -1
- package/dist/tools/registry.d.ts +25 -12
- package/dist/tools/registry.d.ts.map +1 -1
- package/dist/tools/registry.js +31 -6
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/skill-tool.d.ts.map +1 -1
- package/dist/tools/skill-tool.js +52 -5
- package/dist/tools/skill-tool.js.map +1 -1
- package/dist/tools/tool-loop.d.ts +63 -1
- package/dist/tools/tool-loop.d.ts.map +1 -1
- package/dist/tools/tool-loop.js +305 -66
- package/dist/tools/tool-loop.js.map +1 -1
- package/dist/tools/toolsets.d.ts +19 -3
- package/dist/tools/toolsets.d.ts.map +1 -1
- package/dist/tools/toolsets.js +21 -5
- package/dist/tools/toolsets.js.map +1 -1
- package/dist/utils/env.d.ts.map +1 -1
- package/dist/utils/env.js +9 -13
- package/dist/utils/env.js.map +1 -1
- package/dist/web-dashboard/chat-console.d.ts +13 -1
- package/dist/web-dashboard/chat-console.d.ts.map +1 -1
- package/dist/web-dashboard/chat-console.js +16 -2
- package/dist/web-dashboard/chat-console.js.map +1 -1
- package/dist/web-dashboard/hub-data.d.ts +2 -0
- package/dist/web-dashboard/hub-data.d.ts.map +1 -1
- package/dist/web-dashboard/hub-data.js +4 -0
- package/dist/web-dashboard/hub-data.js.map +1 -1
- package/dist/web-dashboard/server.d.ts +6 -0
- package/dist/web-dashboard/server.d.ts.map +1 -1
- package/dist/web-dashboard/server.js +196 -3
- package/dist/web-dashboard/server.js.map +1 -1
- package/dist/web-dashboard/src/types.d.ts +31 -1
- package/dist/web-dashboard/src/types.d.ts.map +1 -1
- package/package.json +11 -1
- package/src/web-dashboard/public/assets/index-56yPnN_m.js +207 -0
- package/src/web-dashboard/public/assets/index-56yPnN_m.js.map +1 -0
- package/src/web-dashboard/public/assets/{index-C507EUWf.css → index-Cyd6tIew.css} +1 -1
- package/src/web-dashboard/public/index.html +2 -2
- package/dist/example.d.ts +0 -1
- package/dist/example.d.ts.map +0 -1
- package/dist/example.js +0 -3
- package/dist/example.js.map +0 -1
- package/dist/fresh.d.ts +0 -2
- package/dist/fresh.d.ts.map +0 -1
- package/dist/fresh.js +0 -2
- package/dist/fresh.js.map +0 -1
- package/dist/mcp/mcp-dashboard-oauth.d.ts +0 -94
- package/dist/mcp/mcp-dashboard-oauth.d.ts.map +0 -1
- package/dist/mcp/mcp-dashboard-oauth.js +0 -140
- package/dist/mcp/mcp-dashboard-oauth.js.map +0 -1
- package/dist/memory/background-sync.d.ts +0 -107
- package/dist/memory/background-sync.d.ts.map +0 -1
- package/dist/memory/background-sync.js +0 -242
- package/dist/memory/background-sync.js.map +0 -1
- package/dist/memory/cross-session.d.ts +0 -68
- package/dist/memory/cross-session.d.ts.map +0 -1
- package/dist/memory/cross-session.js +0 -153
- package/dist/memory/cross-session.js.map +0 -1
- package/dist/memory/drift-detector.d.ts +0 -76
- package/dist/memory/drift-detector.d.ts.map +0 -1
- package/dist/memory/drift-detector.js +0 -216
- package/dist/memory/drift-detector.js.map +0 -1
- package/dist/memory/enhanced-manager.d.ts +0 -105
- package/dist/memory/enhanced-manager.d.ts.map +0 -1
- package/dist/memory/enhanced-manager.js +0 -280
- package/dist/memory/enhanced-manager.js.map +0 -1
- package/dist/memory/session-extraction.d.ts +0 -93
- package/dist/memory/session-extraction.d.ts.map +0 -1
- package/dist/memory/session-extraction.js +0 -290
- package/dist/memory/session-extraction.js.map +0 -1
- package/dist/memory/sqlite-store.d.ts +0 -208
- package/dist/memory/sqlite-store.d.ts.map +0 -1
- package/dist/memory/sqlite-store.js +0 -556
- package/dist/memory/sqlite-store.js.map +0 -1
- package/dist/skills/daytona-executor.d.ts +0 -78
- package/dist/skills/daytona-executor.d.ts.map +0 -1
- package/dist/skills/daytona-executor.js +0 -256
- package/dist/skills/daytona-executor.js.map +0 -1
- package/dist/skills/modal-executor.d.ts +0 -81
- package/dist/skills/modal-executor.d.ts.map +0 -1
- package/dist/skills/modal-executor.js +0 -285
- package/dist/skills/modal-executor.js.map +0 -1
- package/dist/sync/inventory.d.ts +0 -1
- package/dist/sync/inventory.d.ts.map +0 -1
- package/dist/sync/inventory.js +0 -3
- package/dist/sync/inventory.js.map +0 -1
- package/dist/sync/validate.d.ts +0 -1
- package/dist/sync/validate.d.ts.map +0 -1
- package/dist/sync/validate.js +0 -3
- package/dist/sync/validate.js.map +0 -1
- package/dist/test.d.ts +0 -2
- package/dist/test.d.ts.map +0 -1
- package/dist/test.js +0 -3
- package/dist/test.js.map +0 -1
- package/dist/tools/browser-tool.d.ts +0 -206
- package/dist/tools/browser-tool.d.ts.map +0 -1
- package/dist/tools/browser-tool.js +0 -726
- package/dist/tools/browser-tool.js.map +0 -1
- package/dist/tools/delegate-tool.d.ts +0 -109
- package/dist/tools/delegate-tool.d.ts.map +0 -1
- package/dist/tools/delegate-tool.js +0 -185
- package/dist/tools/delegate-tool.js.map +0 -1
- package/dist/tools/delegation-state.d.ts +0 -87
- package/dist/tools/delegation-state.d.ts.map +0 -1
- package/dist/tools/delegation-state.js +0 -278
- package/dist/tools/delegation-state.js.map +0 -1
- package/dist/tools/desktop-ui.d.ts +0 -148
- package/dist/tools/desktop-ui.d.ts.map +0 -1
- package/dist/tools/desktop-ui.js +0 -486
- package/dist/tools/desktop-ui.js.map +0 -1
- package/dist/tools/image-video-tool.d.ts +0 -88
- package/dist/tools/image-video-tool.d.ts.map +0 -1
- package/dist/tools/image-video-tool.js +0 -276
- package/dist/tools/image-video-tool.js.map +0 -1
- package/dist/tools/kanban-cron-tools.d.ts +0 -92
- package/dist/tools/kanban-cron-tools.d.ts.map +0 -1
- package/dist/tools/kanban-cron-tools.js +0 -197
- package/dist/tools/kanban-cron-tools.js.map +0 -1
- package/dist/tools/messaging-tool.d.ts +0 -127
- package/dist/tools/messaging-tool.d.ts.map +0 -1
- package/dist/tools/messaging-tool.js +0 -314
- package/dist/tools/messaging-tool.js.map +0 -1
- package/dist/tools/modality/generic-caller.d.ts +0 -43
- package/dist/tools/modality/generic-caller.d.ts.map +0 -1
- package/dist/tools/modality/generic-caller.js +0 -254
- package/dist/tools/modality/generic-caller.js.map +0 -1
- package/dist/tools/modality/modality-catalog.d.ts +0 -134
- package/dist/tools/modality/modality-catalog.d.ts.map +0 -1
- package/dist/tools/modality/modality-catalog.js +0 -445
- package/dist/tools/modality/modality-catalog.js.map +0 -1
- package/dist/tools/modality/tool-router.d.ts +0 -81
- package/dist/tools/modality/tool-router.d.ts.map +0 -1
- package/dist/tools/modality/tool-router.js +0 -84
- package/dist/tools/modality/tool-router.js.map +0 -1
- package/dist/tools/security-tools.d.ts +0 -107
- package/dist/tools/security-tools.d.ts.map +0 -1
- package/dist/tools/security-tools.js +0 -264
- package/dist/tools/security-tools.js.map +0 -1
- package/dist/tools/ssh-tool.d.ts +0 -130
- package/dist/tools/ssh-tool.d.ts.map +0 -1
- package/dist/tools/ssh-tool.js +0 -328
- package/dist/tools/ssh-tool.js.map +0 -1
- package/dist/tools/tts-tool.d.ts +0 -91
- package/dist/tools/tts-tool.d.ts.map +0 -1
- package/dist/tools/tts-tool.js +0 -406
- package/dist/tools/tts-tool.js.map +0 -1
- package/dist/utils/shell-detection.d.ts +0 -124
- package/dist/utils/shell-detection.d.ts.map +0 -1
- package/dist/utils/shell-detection.js +0 -305
- package/dist/utils/shell-detection.js.map +0 -1
- package/dist/utils/windows-paths.d.ts +0 -185
- package/dist/utils/windows-paths.d.ts.map +0 -1
- package/dist/utils/windows-paths.js +0 -472
- package/dist/utils/windows-paths.js.map +0 -1
- package/src/web-dashboard/public/assets/index-C4frng1Q.js +0 -207
- package/src/web-dashboard/public/assets/index-C4frng1Q.js.map +0 -1
|
@@ -44,14 +44,28 @@ import { getRouterBandit, DEFAULT_MIN_SAMPLES } from './router-bandit.js';
|
|
|
44
44
|
import { getRouterPromotion, DEFAULT_MIN_PROMOTION_DECISIONS } from './router-promotion.js';
|
|
45
45
|
import { getMlRouter, DEFAULT_ML_K, DEFAULT_ML_MIN_SAMPLES, DEFAULT_ML_STRENGTH } from './ml-router.js';
|
|
46
46
|
import { buildModelCandidates } from './model-first-router.js';
|
|
47
|
+
import { pickBestModel, topModelCandidates } from './model-scoring.js';
|
|
47
48
|
import { getModelRegistry } from './model-registry.js';
|
|
49
|
+
// R4: the agentic capability floor needs the same "too small to hold a tool
|
|
50
|
+
// loop" judgement the harness uses. model-harness.ts imports nothing, so this
|
|
51
|
+
// adds no cycle risk to the router.
|
|
52
|
+
import { isTinyModel } from './model-harness.js';
|
|
48
53
|
import { estimateTokens } from './cost-tracker.js';
|
|
49
54
|
import { preferredModelsFor, PROVIDER_CONTEXT_WINDOWS } from './model-selection.js';
|
|
55
|
+
import { isNonChatModel } from '../inference/model-catalog.js';
|
|
50
56
|
import { CATALOG_PROVIDER_IDS, getCatalogProvider, getDefaultModel, isCatalogKeyless } from '../inference/provider-catalog.js';
|
|
57
|
+
import { ProviderFactory } from '../inference/factory.js';
|
|
51
58
|
import { logger } from '../utils/logger.js';
|
|
52
59
|
// ─── Constants ──────────────────────────────────────────────────────────────
|
|
53
60
|
/** The special model value that triggers automatic per-task routing. */
|
|
54
61
|
export const AUTO_MODEL = 'auto';
|
|
62
|
+
/**
|
|
63
|
+
* How many models ONE provider contributes to the failover chain (DEEP
|
|
64
|
+
* FAILOVER). More than one so a provider's 2nd/3rd-best model is actually
|
|
65
|
+
* reachable — per-model RPD/TPM limits on free tiers mean a 429 on one model
|
|
66
|
+
* says nothing about its siblings.
|
|
67
|
+
*/
|
|
68
|
+
export const FALLBACK_MODELS_PER_PROVIDER = 3;
|
|
55
69
|
/** The special provider value stored in active-model state for Auto mode. */
|
|
56
70
|
export const AUTO_PROVIDER = 'auto';
|
|
57
71
|
/** Human labels for each dimension (used in explanations). */
|
|
@@ -621,7 +635,7 @@ export class AutoModelRouter {
|
|
|
621
635
|
*/
|
|
622
636
|
getDefaultAllowedProviders(configManager) {
|
|
623
637
|
if (!configManager || typeof configManager.hasRequiredCredentials !== 'function') {
|
|
624
|
-
return { allowed: DEFAULT_AUTO_PROVIDERS, excluded: [] };
|
|
638
|
+
return { allowed: DEFAULT_AUTO_PROVIDERS, excluded: [], reserve: [] };
|
|
625
639
|
}
|
|
626
640
|
// ── Registry-aware filtering: prefer providers with VERIFIED, usable
|
|
627
641
|
// models over bare credential checks. A key existing ≠ the models on that
|
|
@@ -654,6 +668,16 @@ export class AutoModelRouter {
|
|
|
654
668
|
}
|
|
655
669
|
const registered = registry.getUsableProviders();
|
|
656
670
|
const base = [...new Set([...CATALOG_PROVIDER_IDS, ...configuredIds])].filter((p) => {
|
|
671
|
+
// A provider with no adapter can never be resolved: `resolveProvider`
|
|
672
|
+
// refuses to substitute another provider for it (see router.ts), so a
|
|
673
|
+
// candidate like this is guaranteed to fail — and leaving it in is how a
|
|
674
|
+
// credentialed-but-unconstructible id (`bedrock` is in the catalog but
|
|
675
|
+
// has no adapter) reached the failover walk, silently resolved to a
|
|
676
|
+
// DIFFERENT provider, and mislabeled that provider's models as its own.
|
|
677
|
+
if (!ProviderFactory.isConstructible(p)) {
|
|
678
|
+
excluded.push({ provider: p, reason: 'no adapter in this build' });
|
|
679
|
+
return false;
|
|
680
|
+
}
|
|
657
681
|
if (blocked.has(p) || degraded.has(p)) {
|
|
658
682
|
// Cite the registry's own counts so the explanation proves the data
|
|
659
683
|
// is working ("openrouter excluded — 0 verified, 6 unavailable"). The
|
|
@@ -688,14 +712,19 @@ export class AutoModelRouter {
|
|
|
688
712
|
if (registered.length > 0) {
|
|
689
713
|
const intersection = base.filter((p) => registered.includes(p));
|
|
690
714
|
if (intersection.length > 0) {
|
|
691
|
-
|
|
715
|
+
// Verified providers win the primary ranking, but the credentialed-yet-
|
|
716
|
+
// unverified rest is NOT thrown away — it becomes the reserve fallback
|
|
717
|
+
// pool, so a task still reaches those models when every verified
|
|
718
|
+
// candidate fails ("only reject when nothing is left").
|
|
719
|
+
const reserve = base.filter((p) => !registered.includes(p));
|
|
720
|
+
return { allowed: intersection, excluded, reserve };
|
|
692
721
|
}
|
|
693
722
|
}
|
|
694
723
|
// Never return an empty list: if EVERY configured provider is
|
|
695
724
|
// registry-blocked (pathological), fall back to the full built-in list so
|
|
696
725
|
// the caller still gets a decision and surfaces availability instead of
|
|
697
726
|
// crashing on an empty ranking.
|
|
698
|
-
return { allowed: base.length > 0 ? base : DEFAULT_AUTO_PROVIDERS, excluded };
|
|
727
|
+
return { allowed: base.length > 0 ? base : DEFAULT_AUTO_PROVIDERS, excluded, reserve: [] };
|
|
699
728
|
}
|
|
700
729
|
/**
|
|
701
730
|
* Resolve the optimal provider/model for a task.
|
|
@@ -796,6 +825,7 @@ export class AutoModelRouter {
|
|
|
796
825
|
// proves the gathered data is driving decisions. Explicit allowedProviders
|
|
797
826
|
// opt out of the registry filter entirely (caller knows best).
|
|
798
827
|
let registryExcluded = [];
|
|
828
|
+
let reserveProviders = [];
|
|
799
829
|
let allowed;
|
|
800
830
|
if (options.allowedProviders?.length) {
|
|
801
831
|
allowed = options.allowedProviders;
|
|
@@ -804,6 +834,7 @@ export class AutoModelRouter {
|
|
|
804
834
|
const defaultPool = this.getDefaultAllowedProviders(configManager);
|
|
805
835
|
allowed = defaultPool.allowed;
|
|
806
836
|
registryExcluded = defaultPool.excluded;
|
|
837
|
+
reserveProviders = defaultPool.reserve;
|
|
807
838
|
}
|
|
808
839
|
let escalationApplied = false;
|
|
809
840
|
let allowedProviders = allowed;
|
|
@@ -1169,6 +1200,52 @@ export class AutoModelRouter {
|
|
|
1169
1200
|
}
|
|
1170
1201
|
}
|
|
1171
1202
|
}
|
|
1203
|
+
// ── Agentic capability floor (R4) ──────────────────────────────────────
|
|
1204
|
+
// Effective capability is `model × (1 − harness tax)`: a multi-step agentic
|
|
1205
|
+
// task needs the served model to hold a tool loop across turns. A model too
|
|
1206
|
+
// small for that is not "a bit worse" here, it is a doomed run — it burns
|
|
1207
|
+
// steps, emits malformed tool calls, and then gets BOOKED as a model failure,
|
|
1208
|
+
// teaching the bandit a lesson about the model when the mismatch was ours
|
|
1209
|
+
// (auto handed an agentic task to a model that cannot do one). This is the
|
|
1210
|
+
// routing-side half of R1: the harness fits the model, and the router stops
|
|
1211
|
+
// feeding the harness a model it cannot fit.
|
|
1212
|
+
//
|
|
1213
|
+
// ORDERING (why this runs AFTER the hard constraints): the constraint slot
|
|
1214
|
+
// above owns explicit user/admin policy (maxCostUsd/minSpeed/minReasoning/
|
|
1215
|
+
// governance) and its benign "eliminated everyone" fallback restores the RAW
|
|
1216
|
+
// ranking. Running this floor first made that fallback restore the floor's
|
|
1217
|
+
// survivors instead, so an impossible minReasoning ask could still be served
|
|
1218
|
+
// a provider the user had just ruled out. Policy decides who is eligible;
|
|
1219
|
+
// this heuristic only narrows the eligible set afterwards.
|
|
1220
|
+
//
|
|
1221
|
+
// Deliberately conservative, exactly like the free/local gate above:
|
|
1222
|
+
// - only the SERVED model is judged (a provider hosting both a tiny and a
|
|
1223
|
+
// strong model keeps its strong entry);
|
|
1224
|
+
// - an UNKNOWN served model is kept (never eliminate on ignorance — the
|
|
1225
|
+
// JSON-contract transport still gives it a way to act);
|
|
1226
|
+
// - if the floor would eliminate everyone, the ranking is left alone rather
|
|
1227
|
+
// than returning no route at all. Auto must never dead-end.
|
|
1228
|
+
const agenticTask = complexity === 'complex' ||
|
|
1229
|
+
complexity === 'critical' ||
|
|
1230
|
+
taskProfile.requiresVerification === true;
|
|
1231
|
+
if (agenticTask) {
|
|
1232
|
+
const capable = scored.filter((s) => {
|
|
1233
|
+
let servedModel;
|
|
1234
|
+
try {
|
|
1235
|
+
servedModel = this.resolveModel(s.provider, agentType, configManager, taskDescription);
|
|
1236
|
+
}
|
|
1237
|
+
catch {
|
|
1238
|
+
servedModel = undefined;
|
|
1239
|
+
}
|
|
1240
|
+
return servedModel === undefined || !isTinyModel(servedModel);
|
|
1241
|
+
});
|
|
1242
|
+
if (capable.length > 0) {
|
|
1243
|
+
scored = capable;
|
|
1244
|
+
}
|
|
1245
|
+
else if (options.verbose) {
|
|
1246
|
+
logger.warn(' ⚠️ agentic capability floor would eliminate every provider — keeping the full ranking');
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1172
1249
|
// Rank: circuit-breaker-cooldown providers sink first, then quota-parked
|
|
1173
1250
|
// ones, then healthy ones; ties broken by score. A quota-parked provider
|
|
1174
1251
|
// is only selected when every candidate is parked (matching cooldown).
|
|
@@ -1372,17 +1449,121 @@ export class AutoModelRouter {
|
|
|
1372
1449
|
getRouterPromotion().noteParallelDecision(agentType, taskDescription, this.toParallelPick(heuristicWinner, agentType, configManager), this.toParallelPick(selected, agentType, configManager, model));
|
|
1373
1450
|
}
|
|
1374
1451
|
// Build fallback chain (skip in-cooldown providers when alternatives exist)
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1452
|
+
//
|
|
1453
|
+
// DEEP FAILOVER: every provider contributes MULTIPLE models, not one. Before
|
|
1454
|
+
// this the chain carried a single resolveModel() pick per provider, so a
|
|
1455
|
+
// provider's 2nd-best model was effectively unreachable — a 429 on the one
|
|
1456
|
+
// listed model skipped the provider entirely even though its other models
|
|
1457
|
+
// were healthy (free tiers meter per-model RPD/TPM, so siblings usually ARE
|
|
1458
|
+
// healthy). Ordering: the PRIMARY provider's alternate models first (stay on
|
|
1459
|
+
// the provider whose latency/health is already known, no provider switch
|
|
1460
|
+
// cost), then the other providers' primary picks, then their alternates, so
|
|
1461
|
+
// the chain both uses every model AND still leaves the provider before
|
|
1462
|
+
// burning through all of its fallbacks.
|
|
1463
|
+
const fallbackChain = [];
|
|
1464
|
+
const seenFallback = new Set();
|
|
1465
|
+
const pushFallback = (s, model, alternate) => {
|
|
1466
|
+
const key = `${s.provider}|${model}`;
|
|
1467
|
+
if (seenFallback.has(key))
|
|
1468
|
+
return;
|
|
1469
|
+
seenFallback.add(key);
|
|
1470
|
+
fallbackChain.push({
|
|
1471
|
+
provider: s.provider,
|
|
1472
|
+
model,
|
|
1473
|
+
estimatedCost: 0,
|
|
1474
|
+
qualityScore: s.score,
|
|
1475
|
+
contextWindowTokens: s.contextWindowTokens,
|
|
1476
|
+
reason: alternate
|
|
1477
|
+
? `Fallback (alternate model on ${s.provider})`
|
|
1478
|
+
: s.inCooldown
|
|
1479
|
+
? `Fallback (in cooldown): ${s.provider}`
|
|
1480
|
+
: `Fallback: ${s.provider}`,
|
|
1481
|
+
});
|
|
1482
|
+
};
|
|
1483
|
+
const modelsFor = (s) => this.fallbackModelsFor(s.provider, agentType, configManager, taskDescription, complexity);
|
|
1484
|
+
// Pass 1: the primary provider's OTHER models (deep failover within the
|
|
1485
|
+
// provider that just failed a call).
|
|
1486
|
+
for (const s of scored) {
|
|
1487
|
+
if (s.provider !== provider)
|
|
1488
|
+
continue;
|
|
1489
|
+
const models = modelsFor(s).slice(1); // [0] is the primary pick already in use
|
|
1490
|
+
for (const m of models)
|
|
1491
|
+
pushFallback(s, m, true);
|
|
1492
|
+
}
|
|
1493
|
+
// Pass 2: every other provider's best model (historical chain order).
|
|
1494
|
+
for (const s of scored) {
|
|
1495
|
+
if (s.provider === provider)
|
|
1496
|
+
continue;
|
|
1497
|
+
const models = modelsFor(s);
|
|
1498
|
+
if (models.length === 0)
|
|
1499
|
+
continue;
|
|
1500
|
+
pushFallback(s, models[0], false);
|
|
1501
|
+
}
|
|
1502
|
+
// Pass 3: those providers' remaining models.
|
|
1503
|
+
for (const s of scored) {
|
|
1504
|
+
if (s.provider === provider)
|
|
1505
|
+
continue;
|
|
1506
|
+
const models = modelsFor(s);
|
|
1507
|
+
for (const m of models.slice(1))
|
|
1508
|
+
pushFallback(s, m, true);
|
|
1509
|
+
}
|
|
1510
|
+
// Last-resort reserve: credentialed providers the registry has not verified
|
|
1511
|
+
// (no data yet). They never enter `ranked`/the primary pick — they are tried
|
|
1512
|
+
// only after every ranked fallback is exhausted, so "use every model we can
|
|
1513
|
+
// actually call, reject only when nothing is left" holds without routing
|
|
1514
|
+
// into unproven models by default.
|
|
1515
|
+
for (const p of reserveProviders) {
|
|
1516
|
+
if (p === provider)
|
|
1517
|
+
continue;
|
|
1518
|
+
if (fallbackChain.some((c) => c.provider === p))
|
|
1519
|
+
continue;
|
|
1520
|
+
fallbackChain.push({
|
|
1521
|
+
provider: p,
|
|
1522
|
+
model: this.resolveModel(p, agentType, configManager, taskDescription),
|
|
1523
|
+
estimatedCost: 0,
|
|
1524
|
+
qualityScore: 0,
|
|
1525
|
+
reason: `Fallback (unverified — last resort): ${p}`,
|
|
1526
|
+
});
|
|
1527
|
+
}
|
|
1528
|
+
// Pass 4 (reserve, deep): the reserve providers' alternate models too, so a
|
|
1529
|
+
// last-resort credential pool is not limited to one model per provider.
|
|
1530
|
+
for (const p of reserveProviders) {
|
|
1531
|
+
if (p === provider)
|
|
1532
|
+
continue;
|
|
1533
|
+
for (const m of this.fallbackModelsFor(p, agentType, configManager, taskDescription, complexity).slice(1)) {
|
|
1534
|
+
const key = `${p}|${m}`;
|
|
1535
|
+
if (seenFallback.has(key))
|
|
1536
|
+
continue;
|
|
1537
|
+
seenFallback.add(key);
|
|
1538
|
+
fallbackChain.push({
|
|
1539
|
+
provider: p,
|
|
1540
|
+
model: m,
|
|
1541
|
+
estimatedCost: 0,
|
|
1542
|
+
qualityScore: 0,
|
|
1543
|
+
reason: `Fallback (unverified, alternate model — last resort): ${p}`,
|
|
1544
|
+
});
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
// ── Present the FINAL decision consistently ──────────────────────────────
|
|
1548
|
+
// Model-first routing (and per-model learning) can select a provider/model
|
|
1549
|
+
// that differs from the deterministic `selected`. Before this, the rationale
|
|
1550
|
+
// line named the PRE-override provider, `decision.score` was that loser's
|
|
1551
|
+
// score, and the ✅ marker could sit on a row ranked below #1 — so
|
|
1552
|
+
// `models explain`'s rationale, Decision line and ranked table disagreed
|
|
1553
|
+
// (`Decision: gemini/gemini-3.1-flash-lite` beside a `groq/…` rationale).
|
|
1554
|
+
// Promote the FINAL provider's entry to the head of the ranked list and
|
|
1555
|
+
// present ITS score everywhere the decision is shown. `selected` itself is
|
|
1556
|
+
// left untouched — the promotion gate's A/B record must keep the true
|
|
1557
|
+
// deterministic/bandit pick.
|
|
1558
|
+
let winner = scored.find((s) => s.provider === provider);
|
|
1559
|
+
if (!winner) {
|
|
1560
|
+
// A model-first pick can name a provider with no scored entry only in
|
|
1561
|
+
// pathological cases; synthesize one so presentation never breaks.
|
|
1562
|
+
winner = { ...selected, provider, score: selected.score, reason: `${provider}: model-first pick` };
|
|
1563
|
+
}
|
|
1564
|
+
scored = [winner, ...scored.filter((s) => s.provider !== provider)];
|
|
1565
|
+
const decisionScore = winner.score;
|
|
1566
|
+
const explanation = this.buildExplanation(agentType, complexity, taskType, provider, decisionScore, mode, model, weights, taskProfile) + (routedBy === 'bandit' ? ' | bandit-learned' : '') +
|
|
1386
1567
|
(banditEscalation ? ' | escalated: winner unlearned' : '') +
|
|
1387
1568
|
// ISSUE-002 explanation transparency: cite the registry data that
|
|
1388
1569
|
// excluded providers from the candidate pool, so auto routing proves
|
|
@@ -1427,7 +1608,7 @@ export class AutoModelRouter {
|
|
|
1427
1608
|
taskType,
|
|
1428
1609
|
provider,
|
|
1429
1610
|
model,
|
|
1430
|
-
score:
|
|
1611
|
+
score: decisionScore,
|
|
1431
1612
|
weights,
|
|
1432
1613
|
ranked: scored,
|
|
1433
1614
|
fallbackChain,
|
|
@@ -1572,7 +1753,6 @@ export class AutoModelRouter {
|
|
|
1572
1753
|
// This ensures the bandit learns from the BEST models, not just verified ones.
|
|
1573
1754
|
if (taskDescription) {
|
|
1574
1755
|
try {
|
|
1575
|
-
const { topModelCandidates } = require('./model-scoring.js');
|
|
1576
1756
|
const scored = topModelCandidates(provider, taskDescription, 10, complexity);
|
|
1577
1757
|
for (const s of scored) {
|
|
1578
1758
|
if (!candidates.includes(s.model))
|
|
@@ -1710,6 +1890,66 @@ export class AutoModelRouter {
|
|
|
1710
1890
|
}
|
|
1711
1891
|
return undefined;
|
|
1712
1892
|
}
|
|
1893
|
+
/**
|
|
1894
|
+
* The ranked model list a provider can serve this task with, best first.
|
|
1895
|
+
*
|
|
1896
|
+
* Always starts with the model the router would actually pick, then the
|
|
1897
|
+
* provider's other task-scored candidates, then its remaining health-ranked
|
|
1898
|
+
* verified models. This is what makes the failover chain DEEP (several models
|
|
1899
|
+
* per provider) instead of one: a provider with five working models must be
|
|
1900
|
+
* able to serve from all five, not give up after its first rate limit.
|
|
1901
|
+
*
|
|
1902
|
+
* Never returns the `'default'` SENTINEL or a non-chat model (a probe can
|
|
1903
|
+
* verify a classifier/embedding/vision model, which can never answer a turn).
|
|
1904
|
+
* Best-effort — scoring failures degrade to the pick + verified list.
|
|
1905
|
+
*/
|
|
1906
|
+
fallbackModelsFor(provider, agentType, configManager, taskDescription, complexity) {
|
|
1907
|
+
const out = [];
|
|
1908
|
+
const push = (model) => {
|
|
1909
|
+
if (!model || model === 'default')
|
|
1910
|
+
return;
|
|
1911
|
+
if (out.includes(model))
|
|
1912
|
+
return;
|
|
1913
|
+
if (isNonChatModel(model))
|
|
1914
|
+
return;
|
|
1915
|
+
out.push(model);
|
|
1916
|
+
};
|
|
1917
|
+
push(this.resolveModel(provider, agentType, configManager, taskDescription));
|
|
1918
|
+
if (taskDescription) {
|
|
1919
|
+
try {
|
|
1920
|
+
for (const c of topModelCandidates(provider, taskDescription, FALLBACK_MODELS_PER_PROVIDER, complexity)) {
|
|
1921
|
+
push(c.model);
|
|
1922
|
+
}
|
|
1923
|
+
}
|
|
1924
|
+
catch {
|
|
1925
|
+
// Best-effort — model scoring must never break the chain.
|
|
1926
|
+
}
|
|
1927
|
+
}
|
|
1928
|
+
for (const m of preferredModelsFor(provider))
|
|
1929
|
+
push(m);
|
|
1930
|
+
// HEALTHY-FIRST, but never dropped: a model the registry currently deems
|
|
1931
|
+
// unusable (parked on its own quota / marked unavailable) must not outrank
|
|
1932
|
+
// a healthy sibling, yet it stays in the list as the LAST resort — parks
|
|
1933
|
+
// are short and the model may well have recovered by the time the walk
|
|
1934
|
+
// gets to it ("use every model available; reject only when nothing is
|
|
1935
|
+
// left"). Stable partition preserves the scoring order within each group.
|
|
1936
|
+
const usable = [];
|
|
1937
|
+
const unusable = [];
|
|
1938
|
+
try {
|
|
1939
|
+
const registry = getModelRegistry();
|
|
1940
|
+
for (const m of out) {
|
|
1941
|
+
if (registry.getEntry(provider, m) && !registry.isUsable(provider, m))
|
|
1942
|
+
unusable.push(m);
|
|
1943
|
+
else
|
|
1944
|
+
usable.push(m);
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
catch {
|
|
1948
|
+
// Best-effort — a registry failure must not empty the chain.
|
|
1949
|
+
return out.slice(0, FALLBACK_MODELS_PER_PROVIDER);
|
|
1950
|
+
}
|
|
1951
|
+
return [...usable, ...unusable].slice(0, FALLBACK_MODELS_PER_PROVIDER);
|
|
1952
|
+
}
|
|
1713
1953
|
/**
|
|
1714
1954
|
* Resolve the model name to use within a chosen provider.
|
|
1715
1955
|
* Prefers the provider's configured model; falls back to 'default'.
|
|
@@ -1760,10 +2000,26 @@ export class AutoModelRouter {
|
|
|
1760
2000
|
// hardcoded default.
|
|
1761
2001
|
if (taskDescription) {
|
|
1762
2002
|
try {
|
|
1763
|
-
const { pickBestModel } = require('./model-scoring.js');
|
|
1764
2003
|
const bestModel = pickBestModel(provider, taskDescription);
|
|
1765
|
-
if (bestModel)
|
|
2004
|
+
if (bestModel) {
|
|
2005
|
+
// USABILITY GATE: a task-scored model can still be one the registry
|
|
2006
|
+
// has parked (its own quota window) or marked unavailable. It must
|
|
2007
|
+
// never win the PRIMARY pick while a servable sibling exists —
|
|
2008
|
+
// scoring alone ranks the parked model low, not out. The registry
|
|
2009
|
+
// re-admits it automatically once its window lapses, so this is the
|
|
2010
|
+
// per-model quota contract end to end: skip the resting model, serve
|
|
2011
|
+
// from a sibling, and pick the resting one again when it recovers.
|
|
2012
|
+
const registry = getModelRegistry();
|
|
2013
|
+
const entry = registry.getEntry(provider, bestModel);
|
|
2014
|
+
if (!entry || registry.isUsable(provider, bestModel))
|
|
2015
|
+
return bestModel;
|
|
2016
|
+
const usable = preferredModelsFor(provider)[0];
|
|
2017
|
+
if (usable)
|
|
2018
|
+
return usable;
|
|
2019
|
+
// Nothing usable — fall through to the parked pick (the park may have
|
|
2020
|
+
// lapsed, and a rejected pick is better than no model at all).
|
|
1766
2021
|
return bestModel;
|
|
2022
|
+
}
|
|
1767
2023
|
}
|
|
1768
2024
|
catch {
|
|
1769
2025
|
// Fall through to preferred models
|
|
@@ -1872,7 +2128,12 @@ export class AutoModelRouter {
|
|
|
1872
2128
|
return parts.length ? `${provider}: ${parts.join(', ')}` : `${provider}: adequate for ${complexity} complexity`;
|
|
1873
2129
|
}
|
|
1874
2130
|
/** Build the human-readable decision explanation. */
|
|
1875
|
-
buildExplanation(agentType, complexity, taskType,
|
|
2131
|
+
buildExplanation(agentType, complexity, taskType,
|
|
2132
|
+
/** The FINAL provider id (post model-first override), so the rationale can
|
|
2133
|
+
* never name a different provider than the Decision line. */
|
|
2134
|
+
provider,
|
|
2135
|
+
/** The FINAL decision score (the promoted winner entry's score). */
|
|
2136
|
+
score, mode, model, weights, taskProfile) {
|
|
1876
2137
|
const complexityLabels = {
|
|
1877
2138
|
trivial: '🟢 trivial',
|
|
1878
2139
|
simple: '🔵 simple',
|
|
@@ -1884,8 +2145,8 @@ export class AutoModelRouter {
|
|
|
1884
2145
|
.reduce((a, b) => (weights[b] > weights[a] ? b : a), 'reasoning');
|
|
1885
2146
|
const modeStr = mode !== 'balanced' ? ` | ${mode}` : '';
|
|
1886
2147
|
const profileSuffix = taskProfile.requiresVerification ? ' | verification' : '';
|
|
1887
|
-
return `${agentType} (${complexityLabels[complexity]}, ${taskType}) → ${
|
|
1888
|
-
`score ${
|
|
2148
|
+
return `${agentType} (${complexityLabels[complexity]}, ${taskType}) → ${provider}/${model} ` +
|
|
2149
|
+
`score ${score.toFixed(2)} | dominant: ${DIMENSION_LABELS[dominant]}${modeStr}${profileSuffix}`;
|
|
1889
2150
|
}
|
|
1890
2151
|
}
|
|
1891
2152
|
// ─── Singleton ──────────────────────────────────────────────────────────────
|