muonroi-cli 1.8.4 → 1.9.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/LICENSE +17 -5
- package/dist/packages/agent-harness-core/src/driver.d.ts +27 -1
- package/dist/packages/agent-harness-core/src/driver.js +46 -0
- package/dist/packages/agent-harness-core/src/event-filter.js +11 -0
- package/dist/packages/agent-harness-core/src/event-redact.js +7 -0
- package/dist/packages/agent-harness-core/src/event-tee.d.ts +64 -0
- package/dist/packages/agent-harness-core/src/event-tee.js +104 -0
- package/dist/packages/agent-harness-core/src/mcp-server.d.ts +25 -0
- package/dist/packages/agent-harness-core/src/mcp-server.js +169 -21
- package/dist/packages/agent-harness-core/src/predicate.d.ts +1 -1
- package/dist/packages/agent-harness-core/src/protocol.d.ts +90 -4
- package/dist/packages/agent-harness-core/src/protocol.js +15 -0
- package/dist/packages/agent-harness-core/src/visual-quality.d.ts +58 -0
- package/dist/packages/agent-harness-core/src/visual-quality.js +141 -0
- package/dist/packages/agent-harness-opentui/src/agent-mode.d.ts +6 -0
- package/dist/packages/agent-harness-opentui/src/agent-mode.js +14 -1
- package/dist/packages/agent-harness-opentui/src/input-bridge.d.ts +2 -10
- package/dist/packages/agent-harness-opentui/src/input-bridge.js +103 -16
- package/dist/packages/agent-harness-opentui/src/install.d.ts +8 -0
- package/dist/packages/agent-harness-opentui/src/install.js +10 -0
- package/dist/packages/agent-harness-opentui/src/semantic.js +12 -10
- package/dist/packages/agent-harness-opentui/src/visual-capture.d.ts +56 -0
- package/dist/packages/agent-harness-opentui/src/visual-capture.js +103 -0
- package/dist/src/agent-harness/mock-model.d.ts +38 -0
- package/dist/src/agent-harness/mock-model.js +69 -3
- package/dist/src/agent-harness/test-spawn.js +31 -0
- package/dist/src/chat/chat-keychain.d.ts +7 -12
- package/dist/src/chat/chat-keychain.js +19 -86
- package/dist/src/cli/config/screen-providers.js +1 -1
- package/dist/src/cli/cost-forensics.d.ts +10 -0
- package/dist/src/cli/cost-forensics.js +18 -3
- package/dist/src/cli/keys-bundle.d.ts +1 -1
- package/dist/src/cli/keys-bundle.js +1 -1
- package/dist/src/cli/keys.d.ts +10 -47
- package/dist/src/cli/keys.js +31 -399
- package/dist/src/council/clarifier.d.ts +31 -3
- package/dist/src/council/clarifier.js +220 -32
- package/dist/src/council/context.js +49 -15
- package/dist/src/council/debate-checkpoint.d.ts +129 -0
- package/dist/src/council/debate-checkpoint.js +176 -0
- package/dist/src/council/debate-planner.js +54 -5
- package/dist/src/council/debate-summary.d.ts +25 -0
- package/dist/src/council/debate-summary.js +85 -0
- package/dist/src/council/debate.d.ts +169 -2
- package/dist/src/council/debate.js +1265 -135
- package/dist/src/council/index.d.ts +108 -1
- package/dist/src/council/index.js +670 -197
- package/dist/src/council/leader.d.ts +26 -0
- package/dist/src/council/leader.js +150 -9
- package/dist/src/council/llm.d.ts +94 -0
- package/dist/src/council/llm.js +348 -55
- package/dist/src/council/panel-select.d.ts +30 -0
- package/dist/src/council/panel-select.js +82 -0
- package/dist/src/council/planner.js +40 -0
- package/dist/src/council/preflight.d.ts +17 -0
- package/dist/src/council/preflight.js +50 -2
- package/dist/src/council/prompts.d.ts +39 -4
- package/dist/src/council/prompts.js +256 -69
- package/dist/src/council/stance-recall.d.ts +42 -0
- package/dist/src/council/stance-recall.js +57 -0
- package/dist/src/council/strip-think.d.ts +17 -0
- package/dist/src/council/strip-think.js +33 -0
- package/dist/src/council/types.d.ts +138 -0
- package/dist/src/ee/artifact-cache.d.ts +16 -0
- package/dist/src/ee/artifact-cache.js +32 -0
- package/dist/src/ee/auth.d.ts +20 -0
- package/dist/src/ee/auth.js +54 -2
- package/dist/src/ee/bridge.d.ts +10 -0
- package/dist/src/ee/bridge.js +58 -0
- package/dist/src/ee/client.js +109 -21
- package/dist/src/ee/ee-onboarding.js +6 -26
- package/dist/src/ee/export-transcripts.d.ts +1 -0
- package/dist/src/ee/export-transcripts.js +8 -10
- package/dist/src/ee/extract-session.js +29 -0
- package/dist/src/ee/extract-style.d.ts +58 -0
- package/dist/src/ee/extract-style.js +270 -0
- package/dist/src/ee/recall-ledger.d.ts +9 -0
- package/dist/src/ee/recall-ledger.js +3 -0
- package/dist/src/ee/scope.d.ts +1 -0
- package/dist/src/ee/scope.js +26 -1
- package/dist/src/ee/search.d.ts +7 -0
- package/dist/src/ee/search.js +24 -0
- package/dist/src/ee/transcript-emit.js +2 -0
- package/dist/src/ee/types.d.ts +22 -0
- package/dist/src/ee/who-am-i-brain.d.ts +35 -0
- package/dist/src/ee/who-am-i-brain.js +220 -0
- package/dist/src/ee/who-am-i.d.ts +10 -3
- package/dist/src/ee/who-am-i.js +12 -0
- package/dist/src/ee/workflow-event.d.ts +48 -0
- package/dist/src/ee/workflow-event.js +81 -0
- package/dist/src/flow/compaction/compress.d.ts +3 -3
- package/dist/src/flow/compaction/compress.js +58 -8
- package/dist/src/flow/compaction/extract.d.ts +4 -7
- package/dist/src/flow/compaction/extract.js +50 -10
- package/dist/src/flow/compaction/index.d.ts +14 -1
- package/dist/src/flow/compaction/index.js +96 -3
- package/dist/src/flow/compaction/input-guard.d.ts +24 -0
- package/dist/src/flow/compaction/input-guard.js +43 -0
- package/dist/src/flow/compaction/progress.d.ts +35 -0
- package/dist/src/flow/compaction/progress.js +35 -0
- package/dist/src/flow/fold-planning.d.ts +36 -0
- package/dist/src/flow/fold-planning.js +83 -0
- package/dist/src/flow/hierarchy.d.ts +146 -0
- package/dist/src/flow/hierarchy.js +427 -0
- package/dist/src/flow/index.d.ts +1 -0
- package/dist/src/flow/index.js +2 -0
- package/dist/src/flow/run-artifacts.d.ts +102 -0
- package/dist/src/flow/run-artifacts.js +208 -0
- package/dist/src/generated/version.d.ts +1 -1
- package/dist/src/generated/version.js +1 -1
- package/dist/src/gsd/assessment-schema.d.ts +44 -0
- package/dist/src/gsd/assessment-schema.js +134 -0
- package/dist/src/gsd/capability-registry.d.ts +45 -0
- package/dist/src/gsd/capability-registry.js +337 -0
- package/dist/src/gsd/complexity-assessor.d.ts +39 -0
- package/dist/src/gsd/complexity-assessor.js +152 -0
- package/dist/src/gsd/config-bridge.d.ts +7 -0
- package/dist/src/gsd/config-bridge.js +114 -0
- package/dist/src/gsd/config-loader.d.ts +27 -0
- package/dist/src/gsd/config-loader.js +50 -0
- package/dist/src/gsd/council-context.d.ts +44 -0
- package/dist/src/gsd/council-context.js +114 -0
- package/dist/src/gsd/ee-closure.d.ts +28 -0
- package/dist/src/gsd/ee-closure.js +49 -0
- package/dist/src/gsd/flags.d.ts +66 -0
- package/dist/src/gsd/flags.js +102 -0
- package/dist/src/gsd/gsd-dispatch.d.ts +58 -0
- package/dist/src/gsd/gsd-dispatch.js +131 -0
- package/dist/src/gsd/gsd-runtime.d.ts +22 -0
- package/dist/src/gsd/gsd-runtime.js +37 -0
- package/dist/src/gsd/host-adapter.d.ts +11 -0
- package/dist/src/gsd/host-adapter.js +29 -0
- package/dist/src/gsd/index.d.ts +24 -1
- package/dist/src/gsd/index.js +27 -0
- package/dist/src/gsd/loop-host-contract.d.ts +21 -0
- package/dist/src/gsd/loop-host-contract.js +39 -0
- package/dist/src/gsd/loop-host.d.ts +69 -0
- package/dist/src/gsd/loop-host.js +245 -0
- package/dist/src/gsd/loop-resolver.d.ts +36 -0
- package/dist/src/gsd/loop-resolver.js +79 -0
- package/dist/src/gsd/model-tier.d.ts +13 -0
- package/dist/src/gsd/model-tier.js +45 -0
- package/dist/src/gsd/mutation-gate.d.ts +16 -0
- package/dist/src/gsd/mutation-gate.js +41 -0
- package/dist/src/gsd/native-roadmap.d.ts +89 -0
- package/dist/src/gsd/native-roadmap.js +343 -0
- package/dist/src/gsd/native-state.d.ts +47 -0
- package/dist/src/gsd/native-state.js +220 -0
- package/dist/src/gsd/paths.d.ts +23 -0
- package/dist/src/gsd/paths.js +66 -0
- package/dist/src/gsd/phase-dag.d.ts +12 -0
- package/dist/src/gsd/phase-dag.js +94 -0
- package/dist/src/gsd/phase-sync.d.ts +42 -0
- package/dist/src/gsd/phase-sync.js +321 -0
- package/dist/src/gsd/pil-gate-context.d.ts +13 -0
- package/dist/src/gsd/pil-gate-context.js +64 -0
- package/dist/src/gsd/pil-gate-critic.d.ts +19 -0
- package/dist/src/gsd/pil-gate-critic.js +74 -0
- package/dist/src/gsd/plan-council-prompts.d.ts +25 -0
- package/dist/src/gsd/plan-council-prompts.js +79 -0
- package/dist/src/gsd/plan-council.d.ts +44 -0
- package/dist/src/gsd/plan-council.js +283 -0
- package/dist/src/gsd/plan-gate-vocabulary.d.ts +40 -0
- package/dist/src/gsd/plan-gate-vocabulary.js +64 -0
- package/dist/src/gsd/product-workspace.d.ts +13 -0
- package/dist/src/gsd/product-workspace.js +124 -0
- package/dist/src/gsd/ship-bridge.d.ts +25 -0
- package/dist/src/gsd/ship-bridge.js +65 -0
- package/dist/src/gsd/state-document.d.ts +40 -0
- package/dist/src/gsd/state-document.js +163 -0
- package/dist/src/gsd/verdict-schema.d.ts +39 -0
- package/dist/src/gsd/verdict-schema.js +144 -0
- package/dist/src/gsd/verify-context.d.ts +22 -0
- package/dist/src/gsd/verify-context.js +27 -0
- package/dist/src/gsd/verify-council-prompts.d.ts +19 -0
- package/dist/src/gsd/verify-council-prompts.js +85 -0
- package/dist/src/gsd/verify-council.d.ts +25 -0
- package/dist/src/gsd/verify-council.js +119 -0
- package/dist/src/gsd/verify-gate-vocabulary.d.ts +25 -0
- package/dist/src/gsd/verify-gate-vocabulary.js +46 -0
- package/dist/src/gsd/workflow-engine.d.ts +60 -0
- package/dist/src/gsd/workflow-engine.js +207 -0
- package/dist/src/gsd/workflow-tools.d.ts +13 -0
- package/dist/src/gsd/workflow-tools.js +277 -0
- package/dist/src/headless/council-answers.js +4 -0
- package/dist/src/hooks/index.js +1 -1
- package/dist/src/index.js +172 -270
- package/dist/src/lsp/builtins.js +3 -1
- package/dist/src/lsp/manager.d.ts +5 -1
- package/dist/src/lsp/manager.js +249 -3
- package/dist/src/lsp/npm-cache.d.ts +11 -1
- package/dist/src/lsp/npm-cache.js +17 -1
- package/dist/src/lsp/runtime.d.ts +6 -1
- package/dist/src/lsp/runtime.js +17 -1
- package/dist/src/lsp/types.d.ts +83 -1
- package/dist/src/lsp/types.js +10 -0
- package/dist/src/maintain/pr-builder.js +23 -13
- package/dist/src/mcp/auto-setup.js +57 -32
- package/dist/src/mcp/client-pool.js +44 -16
- package/dist/src/mcp/lsp-tools.d.ts +5 -1
- package/dist/src/mcp/lsp-tools.js +93 -2
- package/dist/src/mcp/mcp-keychain.d.ts +3 -5
- package/dist/src/mcp/mcp-keychain.js +9 -49
- package/dist/src/mcp/research-onboarding.js +8 -7
- package/dist/src/mcp/runtime.js +34 -2
- package/dist/src/mcp/setup-guide-text.d.ts +1 -1
- package/dist/src/mcp/setup-guide-text.js +22 -2
- package/dist/src/mcp/tools-server.d.ts +10 -0
- package/dist/src/mcp/tools-server.js +10 -2
- package/dist/src/models/catalog-client.d.ts +87 -0
- package/dist/src/models/catalog-client.js +105 -38
- package/dist/src/models/catalog.json +528 -265
- package/dist/src/models/registry.d.ts +22 -7
- package/dist/src/models/registry.js +73 -10
- package/dist/src/ops/doctor.js +1 -1
- package/dist/src/orchestrator/ask-user.d.ts +61 -0
- package/dist/src/orchestrator/ask-user.js +65 -0
- package/dist/src/orchestrator/auto-commit.js +1 -1
- package/dist/src/orchestrator/batch-turn-runner.js +2 -2
- package/dist/src/orchestrator/cache-prefix.d.ts +67 -0
- package/dist/src/orchestrator/cache-prefix.js +83 -0
- package/dist/src/orchestrator/compact-request.d.ts +32 -0
- package/dist/src/orchestrator/compact-request.js +41 -0
- package/dist/src/orchestrator/compaction.d.ts +12 -3
- package/dist/src/orchestrator/compaction.js +35 -15
- package/dist/src/orchestrator/council-manager.d.ts +12 -3
- package/dist/src/orchestrator/council-manager.js +74 -32
- package/dist/src/orchestrator/council-request.d.ts +49 -0
- package/dist/src/orchestrator/council-request.js +62 -0
- package/dist/src/orchestrator/cross-turn-dedup.d.ts +6 -0
- package/dist/src/orchestrator/cross-turn-dedup.js +22 -1
- package/dist/src/orchestrator/error-utils.d.ts +29 -0
- package/dist/src/orchestrator/error-utils.js +132 -24
- package/dist/src/orchestrator/grounding-check.js +39 -1
- package/dist/src/orchestrator/interactive-pause.d.ts +26 -0
- package/dist/src/orchestrator/interactive-pause.js +36 -0
- package/dist/src/orchestrator/message-processor.d.ts +4 -0
- package/dist/src/orchestrator/message-processor.js +268 -41
- package/dist/src/orchestrator/orchestrator.d.ts +64 -3
- package/dist/src/orchestrator/orchestrator.js +823 -120
- package/dist/src/orchestrator/preprocessor.js +3 -3
- package/dist/src/orchestrator/proactive-compact-detector.d.ts +26 -0
- package/dist/src/orchestrator/proactive-compact-detector.js +36 -0
- package/dist/src/orchestrator/prompts.js +17 -17
- package/dist/src/orchestrator/reactive-delegation.d.ts +39 -0
- package/dist/src/orchestrator/reactive-delegation.js +59 -0
- package/dist/src/orchestrator/retry-classifier.d.ts +2 -1
- package/dist/src/orchestrator/retry-classifier.js +46 -2
- package/dist/src/orchestrator/safety-askcard.d.ts +1 -1
- package/dist/src/orchestrator/safety-askcard.js +5 -2
- package/dist/src/orchestrator/safety-intercept.d.ts +50 -0
- package/dist/src/orchestrator/safety-intercept.js +62 -0
- package/dist/src/orchestrator/scope-reminder.js +1 -1
- package/dist/src/orchestrator/session-experience.d.ts +2 -1
- package/dist/src/orchestrator/session-experience.js +2 -1
- package/dist/src/orchestrator/should-run-gate.d.ts +5 -0
- package/dist/src/orchestrator/should-run-gate.js +18 -0
- package/dist/src/orchestrator/stall-watchdog.d.ts +31 -3
- package/dist/src/orchestrator/stall-watchdog.js +65 -10
- package/dist/src/orchestrator/stream-runner.d.ts +13 -3
- package/dist/src/orchestrator/stream-runner.js +115 -49
- package/dist/src/orchestrator/sub-agent-cap.d.ts +13 -1
- package/dist/src/orchestrator/sub-agent-cap.js +16 -1
- package/dist/src/orchestrator/sub-agent-model-tier.d.ts +13 -1
- package/dist/src/orchestrator/sub-agent-model-tier.js +16 -2
- package/dist/src/orchestrator/subagent-compactor.d.ts +53 -1
- package/dist/src/orchestrator/subagent-compactor.js +126 -15
- package/dist/src/orchestrator/tool-engine.d.ts +41 -0
- package/dist/src/orchestrator/tool-engine.js +846 -66
- package/dist/src/orchestrator/tool-limit-auto-recover.d.ts +22 -0
- package/dist/src/orchestrator/tool-limit-auto-recover.js +30 -0
- package/dist/src/orchestrator/turn-runner-deps.d.ts +19 -0
- package/dist/src/orchestrator/turn-watchdog.d.ts +44 -0
- package/dist/src/orchestrator/turn-watchdog.js +84 -0
- package/dist/src/pil/agent-operating-contract.d.ts +1 -1
- package/dist/src/pil/agent-operating-contract.js +6 -4
- package/dist/src/pil/cheap-model-playbook.d.ts +1 -1
- package/dist/src/pil/cheap-model-playbook.js +5 -1
- package/dist/src/pil/cheap-model-workbooks.d.ts +1 -1
- package/dist/src/pil/cheap-model-workbooks.js +1 -1
- package/dist/src/pil/discovery-types.d.ts +1 -0
- package/dist/src/pil/discovery.d.ts +1 -1
- package/dist/src/pil/discovery.js +18 -13
- package/dist/src/pil/layer1-intent.d.ts +18 -6
- package/dist/src/pil/layer1-intent.js +66 -757
- package/dist/src/pil/layer15-context-scan.js +15 -1
- package/dist/src/pil/layer1_5-complexity-size.d.ts +7 -0
- package/dist/src/pil/layer1_5-complexity-size.js +31 -5
- package/dist/src/pil/layer3-ee-injection.js +23 -8
- package/dist/src/pil/layer4-gsd.js +69 -16
- package/dist/src/pil/layer5-context.js +7 -3
- package/dist/src/pil/layer6-output.d.ts +23 -0
- package/dist/src/pil/layer6-output.js +5 -1
- package/dist/src/pil/llm-classify.d.ts +111 -5
- package/dist/src/pil/llm-classify.js +421 -189
- package/dist/src/pil/native-capabilities-workbook.d.ts +1 -1
- package/dist/src/pil/native-capabilities-workbook.js +8 -0
- package/dist/src/pil/pipeline.js +36 -2
- package/dist/src/pil/repo-grounding-probe.d.ts +15 -0
- package/dist/src/pil/repo-grounding-probe.js +136 -0
- package/dist/src/pil/repo-structure-hints.d.ts +7 -0
- package/dist/src/pil/repo-structure-hints.js +45 -0
- package/dist/src/pil/response-tools.js +5 -3
- package/dist/src/pil/schema.d.ts +1 -0
- package/dist/src/pil/schema.js +2 -0
- package/dist/src/pil/types.d.ts +18 -0
- package/dist/src/playbook/directives.d.ts +4 -0
- package/dist/src/playbook/directives.js +17 -5
- package/dist/src/product-loop/artifact-io.js +4 -0
- package/dist/src/product-loop/backlog-builder.d.ts +14 -1
- package/dist/src/product-loop/backlog-builder.js +30 -6
- package/dist/src/product-loop/criteria-seed.d.ts +51 -0
- package/dist/src/product-loop/criteria-seed.js +200 -0
- package/dist/src/product-loop/discovery-context-format.js +3 -1
- package/dist/src/product-loop/discovery-ecosystem.js +4 -1
- package/dist/src/product-loop/discovery-interview.d.ts +9 -0
- package/dist/src/product-loop/discovery-interview.js +60 -12
- package/dist/src/product-loop/discovery-recommender.js +2 -1
- package/dist/src/product-loop/discovery-schema.js +19 -2
- package/dist/src/product-loop/discovery-triage.d.ts +23 -0
- package/dist/src/product-loop/discovery-triage.js +109 -0
- package/dist/src/product-loop/gather.js +150 -2
- package/dist/src/product-loop/ideal-trace.d.ts +7 -0
- package/dist/src/product-loop/ideal-trace.js +64 -0
- package/dist/src/product-loop/index.d.ts +13 -1
- package/dist/src/product-loop/index.js +340 -52
- package/dist/src/product-loop/loop-driver.d.ts +7 -0
- package/dist/src/product-loop/loop-driver.js +330 -106
- package/dist/src/product-loop/phase-plan.d.ts +21 -0
- package/dist/src/product-loop/phase-plan.js +81 -6
- package/dist/src/product-loop/phase-rituals.d.ts +3 -0
- package/dist/src/product-loop/phase-rituals.js +8 -3
- package/dist/src/product-loop/phase-runner.js +39 -12
- package/dist/src/product-loop/plan-adherence-review.d.ts +26 -0
- package/dist/src/product-loop/plan-adherence-review.js +144 -0
- package/dist/src/product-loop/sprint-runner.d.ts +173 -0
- package/dist/src/product-loop/sprint-runner.js +863 -19
- package/dist/src/product-loop/types.d.ts +61 -5
- package/dist/src/providers/adapter.d.ts +1 -1
- package/dist/src/providers/adapter.js +3 -4
- package/dist/src/providers/anthropic.d.ts +9 -8
- package/dist/src/providers/anthropic.js +13 -47
- package/dist/src/providers/auth/browser-flow.d.ts +1 -1
- package/dist/src/providers/auth/browser-flow.js +1 -1
- package/dist/src/providers/auth/grok-oauth.d.ts +1 -0
- package/dist/src/providers/auth/grok-oauth.js +30 -5
- package/dist/src/providers/auth/openai-oauth.d.ts +1 -0
- package/dist/src/providers/auth/openai-oauth.js +15 -1
- package/dist/src/providers/auth/registry.js +0 -34
- package/dist/src/providers/auth/token-store.d.ts +9 -9
- package/dist/src/providers/auth/token-store.js +8 -67
- package/dist/src/providers/auth/types.d.ts +9 -1
- package/dist/src/providers/auth/types.js +1 -1
- package/dist/src/providers/capabilities.d.ts +24 -5
- package/dist/src/providers/capabilities.js +42 -24
- package/dist/src/providers/endpoints.d.ts +2 -2
- package/dist/src/providers/endpoints.js +11 -10
- package/dist/src/providers/env-store.d.ts +17 -0
- package/dist/src/providers/env-store.js +228 -0
- package/dist/src/providers/keychain.d.ts +22 -18
- package/dist/src/providers/keychain.js +127 -140
- package/dist/src/providers/mcp-vision-bridge.js +56 -146
- package/dist/src/providers/openai-compatible.js +8 -1
- package/dist/src/providers/pricing.d.ts +2 -2
- package/dist/src/providers/pricing.js +3 -13
- package/dist/src/providers/runtime.d.ts +43 -3
- package/dist/src/providers/runtime.js +88 -14
- package/dist/src/providers/strategies/base.strategy.d.ts +16 -0
- package/dist/src/providers/strategies/base.strategy.js +24 -1
- package/dist/src/providers/strategies/{siliconflow.strategy.d.ts → opencode-go.strategy.d.ts} +3 -3
- package/dist/src/providers/strategies/opencode-go.strategy.js +83 -0
- package/dist/src/providers/strategies/registry.js +4 -4
- package/dist/src/providers/strategies/thinking-mode.d.ts +109 -0
- package/dist/src/providers/strategies/thinking-mode.js +288 -1
- package/dist/src/providers/strategies/xai.strategy.js +27 -0
- package/dist/src/providers/strategies/zai.strategy.d.ts +14 -0
- package/dist/src/providers/strategies/zai.strategy.js +44 -0
- package/dist/src/providers/types.d.ts +5 -6
- package/dist/src/providers/types.js +2 -2
- package/dist/src/providers/vision-backend.d.ts +47 -0
- package/dist/src/providers/vision-backend.js +258 -0
- package/dist/src/providers/vision-proxy.d.ts +22 -9
- package/dist/src/providers/vision-proxy.js +63 -132
- package/dist/src/providers/warm.d.ts +65 -0
- package/dist/src/providers/warm.js +145 -0
- package/dist/src/providers/wire-debug.js +95 -0
- package/dist/src/router/decide.d.ts +13 -0
- package/dist/src/router/decide.js +138 -36
- package/dist/src/router/peak-hour.d.ts +38 -0
- package/dist/src/router/peak-hour.js +107 -0
- package/dist/src/router/step-router.js +3 -2
- package/dist/src/router/warm.js +4 -5
- package/dist/src/scaffold/continuation-prompt.d.ts +11 -0
- package/dist/src/scaffold/continuation-prompt.js +26 -0
- package/dist/src/scaffold/point-to-existing.d.ts +21 -0
- package/dist/src/scaffold/point-to-existing.js +25 -0
- package/dist/src/self-qa/agentic-loop.js +6 -5
- package/dist/src/{ui/state → state}/active-run.d.ts +19 -0
- package/dist/src/{ui/state → state}/active-run.js +21 -0
- package/dist/src/{ui/status-bar/store.d.ts → state/status-bar-store.d.ts} +4 -1
- package/dist/src/{ui/status-bar/store.js → state/status-bar-store.js} +12 -9
- package/dist/src/state/turn-trace.d.ts +43 -0
- package/dist/src/state/turn-trace.js +32 -0
- package/dist/src/storage/db.js +2 -1
- package/dist/src/storage/index.d.ts +1 -1
- package/dist/src/storage/index.js +1 -1
- package/dist/src/storage/interaction-log.d.ts +1 -1
- package/dist/src/storage/migrations.js +71 -1
- package/dist/src/storage/sessions.d.ts +28 -10
- package/dist/src/storage/sessions.js +78 -21
- package/dist/src/storage/transcript-view.js +1 -1
- package/dist/src/storage/transcript.d.ts +51 -0
- package/dist/src/storage/transcript.js +340 -15
- package/dist/src/tools/file.d.ts +15 -0
- package/dist/src/tools/file.js +32 -0
- package/dist/src/tools/git-safety.d.ts +19 -0
- package/dist/src/tools/git-safety.js +168 -0
- package/dist/src/tools/native-tools.d.ts +1 -1
- package/dist/src/tools/native-tools.js +81 -1
- package/dist/src/tools/registry.d.ts +20 -0
- package/dist/src/tools/registry.js +576 -23
- package/dist/src/tools/research.d.ts +29 -0
- package/dist/src/tools/research.js +233 -0
- package/dist/src/types/index.d.ts +147 -4
- package/dist/src/ui/app.js +0 -0
- package/dist/src/ui/cards/product-status-card.js +1 -1
- package/dist/src/ui/components/agent-rail-activities.d.ts +26 -0
- package/dist/src/ui/components/agent-rail-activities.js +47 -0
- package/dist/src/ui/components/bubble-body-guard.d.ts +27 -0
- package/dist/src/ui/components/bubble-body-guard.js +50 -0
- package/dist/src/ui/components/compact-progress-card.d.ts +24 -0
- package/dist/src/ui/components/compact-progress-card.js +42 -0
- package/dist/src/ui/components/context-rail.d.ts +26 -0
- package/dist/src/ui/components/context-rail.js +33 -0
- package/dist/src/ui/components/council-conclusion-card.d.ts +73 -0
- package/dist/src/ui/components/council-conclusion-card.js +420 -0
- package/dist/src/ui/components/council-debate-pill.d.ts +36 -0
- package/dist/src/ui/components/council-debate-pill.js +34 -0
- package/dist/src/ui/components/council-info-card.js +2 -2
- package/dist/src/ui/components/council-leader-bubble.d.ts +10 -3
- package/dist/src/ui/components/council-leader-bubble.js +21 -11
- package/dist/src/ui/components/council-message-bubble.d.ts +15 -2
- package/dist/src/ui/components/council-message-bubble.js +16 -15
- package/dist/src/ui/components/council-phase-timeline.d.ts +9 -1
- package/dist/src/ui/components/council-phase-timeline.js +66 -17
- package/dist/src/ui/components/council-placeholder-bubble.d.ts +16 -9
- package/dist/src/ui/components/council-placeholder-bubble.js +32 -29
- package/dist/src/ui/components/council-question-card.js +13 -12
- package/dist/src/ui/components/council-rail-rounds.d.ts +26 -0
- package/dist/src/ui/components/council-rail-rounds.js +57 -0
- package/dist/src/ui/components/council-round-group.d.ts +38 -0
- package/dist/src/ui/components/council-round-group.js +88 -0
- package/dist/src/ui/components/council-status-list.d.ts +3 -1
- package/dist/src/ui/components/council-status-list.js +36 -24
- package/dist/src/ui/components/council-synthesis-banner.d.ts +7 -2
- package/dist/src/ui/components/council-synthesis-banner.js +20 -5
- package/dist/src/ui/components/halt-recovery-card.js +9 -5
- package/dist/src/ui/components/jump-to-latest-pill.d.ts +11 -0
- package/dist/src/ui/components/jump-to-latest-pill.js +14 -0
- package/dist/src/ui/components/message-view.d.ts +15 -0
- package/dist/src/ui/components/message-view.js +50 -1
- package/dist/src/ui/components/prompt-box.js +18 -16
- package/dist/src/ui/components/session-tree-card.d.ts +14 -0
- package/dist/src/ui/components/session-tree-card.js +46 -0
- package/dist/src/ui/components/slash-inline-menu.d.ts +12 -0
- package/dist/src/ui/components/slash-inline-menu.js +26 -5
- package/dist/src/ui/components/task-list-panel.d.ts +14 -1
- package/dist/src/ui/components/task-list-panel.js +22 -2
- package/dist/src/ui/components/tool-group.d.ts +15 -3
- package/dist/src/ui/components/tool-group.js +69 -11
- package/dist/src/ui/containers/modals-layer.d.ts +4 -2
- package/dist/src/ui/containers/modals-layer.js +2 -2
- package/dist/src/ui/council-harness-event.d.ts +57 -0
- package/dist/src/ui/council-harness-event.js +46 -0
- package/dist/src/ui/heartbeat-debug.d.ts +29 -0
- package/dist/src/ui/heartbeat-debug.js +45 -0
- package/dist/src/ui/hooks/use-session-picker.d.ts +3 -3
- package/dist/src/ui/mcp-modal.js +2 -4
- package/dist/src/ui/modals/api-key-modal.js +1 -1
- package/dist/src/ui/modals/connect-modal.js +4 -3
- package/dist/src/ui/modals/model-picker-modal.d.ts +8 -18
- package/dist/src/ui/modals/model-picker-modal.js +8 -10
- package/dist/src/ui/modals/session-picker-modal.d.ts +2 -2
- package/dist/src/ui/modals/session-picker-modal.js +3 -5
- package/dist/src/ui/picker-providers.d.ts +1 -1
- package/dist/src/ui/picker-providers.js +1 -1
- package/dist/src/ui/primitives/index.d.ts +1 -0
- package/dist/src/ui/primitives/index.js +2 -0
- package/dist/src/ui/primitives/semantic-primitives.d.ts +76 -0
- package/dist/src/ui/primitives/semantic-primitives.js +81 -0
- package/dist/src/ui/slash/compact.js +5 -7
- package/dist/src/ui/slash/cost.js +1 -1
- package/dist/src/ui/slash/council.js +19 -1
- package/dist/src/ui/slash/debug.d.ts +3 -31
- package/dist/src/ui/slash/debug.js +9 -20
- package/dist/src/ui/slash/ee.js +81 -0
- package/dist/src/ui/slash/ideal.d.ts +6 -2
- package/dist/src/ui/slash/ideal.js +97 -7
- package/dist/src/ui/slash/menu-items.d.ts +7 -0
- package/dist/src/ui/slash/menu-items.js +23 -20
- package/dist/src/ui/slash/registry.d.ts +2 -0
- package/dist/src/ui/slash/registry.js +4 -0
- package/dist/src/ui/status-bar/cache-hit.d.ts +6 -0
- package/dist/src/ui/status-bar/cache-hit.js +9 -0
- package/dist/src/ui/status-bar/index.d.ts +1 -1
- package/dist/src/ui/status-bar/index.js +7 -3
- package/dist/src/ui/status-bar/usd-meter.d.ts +5 -4
- package/dist/src/ui/status-bar/usd-meter.js +6 -4
- package/dist/src/ui/theme.d.ts +1 -0
- package/dist/src/ui/theme.js +2 -0
- package/dist/src/ui/types.d.ts +7 -0
- package/dist/src/ui/use-app-logic.js +0 -0
- package/dist/src/ui/utils/agent-activities.d.ts +39 -0
- package/dist/src/ui/utils/agent-activities.js +96 -0
- package/dist/src/ui/utils/format.d.ts +14 -0
- package/dist/src/ui/utils/format.js +23 -3
- package/dist/src/ui/utils/group-tool-entries.d.ts +26 -0
- package/dist/src/ui/utils/group-tool-entries.js +111 -0
- package/dist/src/ui/utils/tool-summary.d.ts +21 -0
- package/dist/src/ui/utils/tool-summary.js +91 -0
- package/dist/src/usage/downgrade.js +2 -2
- package/dist/src/usage/product-ledger.js +2 -2
- package/dist/src/utils/event-loop-monitor.d.ts +85 -0
- package/dist/src/utils/event-loop-monitor.js +107 -0
- package/dist/src/utils/install-manager.js +2 -1
- package/dist/src/utils/llm-deadline.d.ts +14 -0
- package/dist/src/utils/llm-deadline.js +19 -0
- package/dist/src/utils/logger.js +2 -2
- package/dist/src/utils/loop-profiler.d.ts +102 -0
- package/dist/src/utils/loop-profiler.js +202 -0
- package/dist/src/utils/permission-mode.js +5 -3
- package/dist/src/utils/redactor.js +1 -1
- package/dist/src/utils/settings.d.ts +180 -5
- package/dist/src/utils/settings.js +271 -31
- package/dist/src/utils/side-question.d.ts +1 -2
- package/dist/src/utils/side-question.js +2 -2
- package/dist/src/utils/visible-retry.d.ts +11 -0
- package/dist/src/utils/visible-retry.js +10 -1
- package/dist/src/verify/entrypoint.d.ts +1 -1
- package/dist/src/verify/entrypoint.js +52 -17
- package/dist/src/verify/orchestrator.d.ts +1 -1
- package/dist/src/verify/orchestrator.js +20 -3
- package/dist/src/verify/recipes.d.ts +13 -0
- package/dist/src/verify/recipes.js +15 -0
- package/package.json +134 -132
- package/dist/src/cli/bw-vault.d.ts +0 -55
- package/dist/src/cli/bw-vault.js +0 -133
- package/dist/src/mcp/ee-tools.d.ts +0 -46
- package/dist/src/mcp/ee-tools.js +0 -193
- package/dist/src/providers/auth/gcloud.d.ts +0 -28
- package/dist/src/providers/auth/gcloud.js +0 -102
- package/dist/src/providers/auth/gemini-oauth.d.ts +0 -82
- package/dist/src/providers/auth/gemini-oauth.js +0 -472
- package/dist/src/providers/gemini.d.ts +0 -11
- package/dist/src/providers/gemini.js +0 -45
- package/dist/src/providers/siliconflow-sse-repair.d.ts +0 -58
- package/dist/src/providers/siliconflow-sse-repair.js +0 -177
- package/dist/src/providers/strategies/google.strategy.d.ts +0 -22
- package/dist/src/providers/strategies/google.strategy.js +0 -174
- package/dist/src/providers/strategies/siliconflow.strategy.js +0 -29
- package/dist/src/ui/containers/chat-feed.d.ts +0 -40
- package/dist/src/ui/containers/chat-feed.js +0 -66
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/providers/warm.ts
|
|
3
|
+
*
|
|
4
|
+
* Boot-time warm-up of the provider factory registry.
|
|
5
|
+
*
|
|
6
|
+
* Root cause it addresses (measured live, 2026-07-16, session 0c6728ba1a25):
|
|
7
|
+
* an xai session POSTed model `gpt-5.4` to api.x.ai and got 404 "The model
|
|
8
|
+
* gpt-5.4 does not exist" — an openai model sent to the xai endpoint. The
|
|
9
|
+
* factory/model guard in `runtime.ts` DID spot the mismatch and tried to
|
|
10
|
+
* redirect the request to openai's own factory, but the registry had no openai
|
|
11
|
+
* entry: a session only ever built the factory for ITS OWN provider, so any
|
|
12
|
+
* sub-task that resolved a model from another provider had nothing to redirect
|
|
13
|
+
* to and fell through to the wrong endpoint.
|
|
14
|
+
*
|
|
15
|
+
* That is the actual hole. Model ids and provider factories travel as two
|
|
16
|
+
* independent values, so "borrow the session's factory" is the silent default
|
|
17
|
+
* for every sub-task (compaction, classify, sub-agents, mode switches) and only
|
|
18
|
+
* some paths remember to re-derive the provider. Warming the registry for every
|
|
19
|
+
* credentialed provider closes it at the source: the factory for a model's own
|
|
20
|
+
* provider is then always present, so `resolveModelRuntime` can derive it from
|
|
21
|
+
* the model itself instead of trusting whatever factory a caller passed.
|
|
22
|
+
*
|
|
23
|
+
* Best-effort by construction: a provider that fails to warm is simply absent
|
|
24
|
+
* (the same state as today), never a boot failure.
|
|
25
|
+
*/
|
|
26
|
+
import { logger } from "../utils/logger.js";
|
|
27
|
+
import { createProviderFactoryAsync, hasProviderFactory } from "./runtime.js";
|
|
28
|
+
import { ALL_PROVIDER_IDS } from "./types.js";
|
|
29
|
+
/**
|
|
30
|
+
* Build and register a factory for every provider the user has credentials for.
|
|
31
|
+
*
|
|
32
|
+
* Runs providers concurrently — each is an independent credential read, and a
|
|
33
|
+
* serial loop would add every provider's latency to boot.
|
|
34
|
+
*
|
|
35
|
+
* Skips providers that already have a factory: the session builds its own with
|
|
36
|
+
* session-specific options (custom baseURL, OAuth headers), and rebuilding it
|
|
37
|
+
* from bare defaults here would silently downgrade the live session's wiring.
|
|
38
|
+
*/
|
|
39
|
+
/**
|
|
40
|
+
* Rebuild ONE provider's factory after its credentials changed mid-session.
|
|
41
|
+
*
|
|
42
|
+
* `createProviderFactoryAsync` reads OAuth tokens at CONSTRUCTION and bakes the
|
|
43
|
+
* resulting auth headers into the factory (runtime.ts: `loadTokensWithRefresh()`
|
|
44
|
+
* then `authHeaders(tokens)`). Boot warms openai/xai even with no tokens —
|
|
45
|
+
* `getOAuthProviderConfig` only reports that a provider SUPPORTS OAuth — so the
|
|
46
|
+
* entry built at boot is an API-key-path factory. Signing in later saved tokens
|
|
47
|
+
* that nothing re-read: the stale factory stayed registered and the provider
|
|
48
|
+
* kept failing until the next process start. That is the "OAuth only works
|
|
49
|
+
* after I restart the session" report; the same held for a key set via `K` on a
|
|
50
|
+
* provider skipped at boot for "no credentials".
|
|
51
|
+
*
|
|
52
|
+
* warmProviderFactories() cannot be reused for this: it deliberately SKIPS a
|
|
53
|
+
* provider that already has a factory. The registry is last-built-wins, so
|
|
54
|
+
* building again is what replaces the stale entry.
|
|
55
|
+
*/
|
|
56
|
+
export async function rewarmProviderFactory(id) {
|
|
57
|
+
try {
|
|
58
|
+
const { loadUserSettings } = await import("../utils/settings.js");
|
|
59
|
+
const baseURL = loadUserSettings()?.providers?.[id]?.baseURL;
|
|
60
|
+
let apiKey;
|
|
61
|
+
try {
|
|
62
|
+
const { loadKeyForProvider } = await import("./keychain.js");
|
|
63
|
+
apiKey = (await loadKeyForProvider(id)) || undefined;
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
// No stored key is the normal OAuth case, so this is not an error —
|
|
67
|
+
// but log it: a keychain fault here silently downgrades auth.
|
|
68
|
+
logger.debug("cli", `[provider-warm] key read failed for ${id}: ${err?.message}`, { error: err });
|
|
69
|
+
apiKey = undefined;
|
|
70
|
+
}
|
|
71
|
+
await createProviderFactoryAsync(id, { ...(apiKey ? { apiKey } : {}), ...(baseURL ? { baseURL } : {}) });
|
|
72
|
+
logger.info("cli", `[provider-warm] rebuilt ${id} factory after a credential change`, { providerId: id });
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
logger.warn("cli", `[provider-warm] failed to rebuild factory for ${id}: ${err?.message}`, {
|
|
77
|
+
error: err,
|
|
78
|
+
providerId: id,
|
|
79
|
+
});
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
export async function warmProviderFactories() {
|
|
84
|
+
const warmed = [];
|
|
85
|
+
const skipped = [];
|
|
86
|
+
const { isProviderDisabled } = await import("../utils/settings.js");
|
|
87
|
+
const { loadUserSettings } = await import("../utils/settings.js");
|
|
88
|
+
const userSettings = loadUserSettings();
|
|
89
|
+
await Promise.all(ALL_PROVIDER_IDS.map(async (id) => {
|
|
90
|
+
try {
|
|
91
|
+
if (hasProviderFactory(id)) {
|
|
92
|
+
skipped.push({ id, reason: "already built" });
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (isProviderDisabled(id)) {
|
|
96
|
+
skipped.push({ id, reason: "disabled" });
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
let apiKey;
|
|
100
|
+
try {
|
|
101
|
+
const { loadKeyForProvider } = await import("./keychain.js");
|
|
102
|
+
apiKey = (await loadKeyForProvider(id)) || undefined;
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
// No stored key for this provider — normal; OAuth may still cover it.
|
|
106
|
+
apiKey = undefined;
|
|
107
|
+
}
|
|
108
|
+
let hasOAuth = false;
|
|
109
|
+
try {
|
|
110
|
+
const { getOAuthProviderConfig } = await import("./auth/registry.js");
|
|
111
|
+
hasOAuth = !!(await getOAuthProviderConfig(id));
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
logger.debug("cli", `[provider-warm] OAuth probe failed for ${id}: ${err?.message}`, {
|
|
115
|
+
error: err,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
if (!apiKey && !hasOAuth) {
|
|
119
|
+
skipped.push({ id, reason: "no credentials" });
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
// Honour a user-configured endpoint; otherwise each strategy falls back
|
|
123
|
+
// to its own provider's apiBase, which is what a non-session provider
|
|
124
|
+
// should use.
|
|
125
|
+
const baseURL = userSettings?.providers?.[id]?.baseURL;
|
|
126
|
+
await createProviderFactoryAsync(id, { ...(apiKey ? { apiKey } : {}), ...(baseURL ? { baseURL } : {}) });
|
|
127
|
+
warmed.push(id);
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
// Never let one provider's credential problem break boot: absent from
|
|
131
|
+
// the registry is exactly the pre-warm status quo.
|
|
132
|
+
logger.warn("cli", `[provider-warm] failed to build factory for ${id}: ${err?.message}`, {
|
|
133
|
+
error: err,
|
|
134
|
+
providerId: id,
|
|
135
|
+
});
|
|
136
|
+
skipped.push({ id, reason: `error: ${err?.message ?? "unknown"}` });
|
|
137
|
+
}
|
|
138
|
+
}));
|
|
139
|
+
logger.info("cli", `[provider-warm] registry warmed: ${warmed.join(", ") || "(none)"}`, {
|
|
140
|
+
warmed,
|
|
141
|
+
skipped,
|
|
142
|
+
});
|
|
143
|
+
return { warmed, skipped };
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=warm.js.map
|
|
@@ -90,6 +90,95 @@ function summarizeMessage(m) {
|
|
|
90
90
|
}
|
|
91
91
|
return { role, contentKind: "string", textChars: 0 };
|
|
92
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* Reduce a request body (from AI SDK's `error.requestBodyValues`) to a
|
|
95
|
+
* PII-safe shape: top-level param key list + each assistant message's field
|
|
96
|
+
* key list. Values are NEVER persisted — only key names. This is the
|
|
97
|
+
* diagnostic evidence needed when a provider rejects "an invalid parameter"
|
|
98
|
+
* (Z.ai 1210, SiliconFlow 20015) and we must see which field was present or
|
|
99
|
+
* missing on each assistant turn in a multi-step tool loop.
|
|
100
|
+
*/
|
|
101
|
+
function summarizeRequestBodyShape(body) {
|
|
102
|
+
if (!body || typeof body !== "object")
|
|
103
|
+
return undefined;
|
|
104
|
+
const b = body;
|
|
105
|
+
const paramKeys = Object.keys(b).sort();
|
|
106
|
+
const configParamValues = extractConfigParamValues(b);
|
|
107
|
+
const messages = b.messages;
|
|
108
|
+
if (!Array.isArray(messages)) {
|
|
109
|
+
return {
|
|
110
|
+
paramKeys,
|
|
111
|
+
assistantFieldKeys: [],
|
|
112
|
+
assistantCount: 0,
|
|
113
|
+
assistantLens: [],
|
|
114
|
+
totalReasoningChars: 0,
|
|
115
|
+
responseFormat: b.response_format ?? undefined,
|
|
116
|
+
configParamValues,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
const assistantMsgs = messages.filter((m) => m?.role === "assistant");
|
|
120
|
+
// De-duplicate the field-key signature across assistant messages so a long
|
|
121
|
+
// history doesn't bloat the log — we only care WHICH fields co-occur.
|
|
122
|
+
const signatures = new Set();
|
|
123
|
+
const assistantLens = [];
|
|
124
|
+
let totalReasoningChars = 0;
|
|
125
|
+
for (const m of assistantMsgs) {
|
|
126
|
+
const msg = m;
|
|
127
|
+
const keys = Object.keys(msg ?? {})
|
|
128
|
+
.sort()
|
|
129
|
+
.join(",");
|
|
130
|
+
signatures.add(keys);
|
|
131
|
+
const rc = msg?.reasoning_content;
|
|
132
|
+
const rcLen = typeof rc === "string" ? rc.length : null;
|
|
133
|
+
if (rcLen !== null)
|
|
134
|
+
totalReasoningChars += rcLen;
|
|
135
|
+
const contentLen = typeof msg?.content === "string"
|
|
136
|
+
? msg.content.length
|
|
137
|
+
: Array.isArray(msg?.content)
|
|
138
|
+
? msg.content.reduce((n, p) => n + (typeof p?.text === "string" ? p.text.length : 0), 0)
|
|
139
|
+
: 0;
|
|
140
|
+
const toolCallsLen = Array.isArray(msg?.tool_calls) ? msg.tool_calls.length : 0;
|
|
141
|
+
assistantLens.push({ rc: rcLen, content: contentLen, toolCalls: toolCallsLen });
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
paramKeys,
|
|
145
|
+
assistantFieldKeys: [...signatures],
|
|
146
|
+
assistantCount: assistantMsgs.length,
|
|
147
|
+
assistantLens,
|
|
148
|
+
totalReasoningChars,
|
|
149
|
+
responseFormat: b.response_format ?? undefined,
|
|
150
|
+
configParamValues,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Scalar SDK-config params whose VALUES are PII-safe (generation config, not
|
|
155
|
+
* user prompt content) and which are the likely culprits when a provider
|
|
156
|
+
* rejects with a generic "Invalid API parameter" (Z.ai 1210, SiliconFlow
|
|
157
|
+
* 20015). `messages` and `tools` are deliberately excluded — their values may
|
|
158
|
+
* carry prompts/PII, and counts are already captured elsewhere.
|
|
159
|
+
*/
|
|
160
|
+
const CONFIG_PARAM_KEYS = [
|
|
161
|
+
"reasoning_effort",
|
|
162
|
+
"verbosity",
|
|
163
|
+
"tool_choice",
|
|
164
|
+
"response_format",
|
|
165
|
+
"max_tokens",
|
|
166
|
+
"temperature",
|
|
167
|
+
"top_p",
|
|
168
|
+
"frequency_penalty",
|
|
169
|
+
"presence_penalty",
|
|
170
|
+
"seed",
|
|
171
|
+
"stop",
|
|
172
|
+
"parallel_tool_calls",
|
|
173
|
+
];
|
|
174
|
+
function extractConfigParamValues(body) {
|
|
175
|
+
const out = {};
|
|
176
|
+
for (const k of CONFIG_PARAM_KEYS) {
|
|
177
|
+
if (k in body)
|
|
178
|
+
out[k] = body[k] ?? null;
|
|
179
|
+
}
|
|
180
|
+
return out;
|
|
181
|
+
}
|
|
93
182
|
export const wireDebug = {
|
|
94
183
|
enabled: ENABLED,
|
|
95
184
|
/** Log an outgoing streamText/streamObject call. */
|
|
@@ -129,6 +218,12 @@ export const wireDebug = {
|
|
|
129
218
|
statusCode: typeof e?.statusCode === "number" ? e.statusCode : undefined,
|
|
130
219
|
url: typeof e?.url === "string" ? e.url : undefined,
|
|
131
220
|
responseBody: typeof e?.responseBody === "string" ? e.responseBody.slice(0, 4000) : undefined,
|
|
221
|
+
// Evidence for "Invalid API parameter" (e.g. Z.ai code 1210,
|
|
222
|
+
// SiliconFlow 20015): capture the SHAPE (key names only — no values,
|
|
223
|
+
// PII-safe) of every assistant message in the request body so we can
|
|
224
|
+
// see which field the provider rejected and whether reasoning_content
|
|
225
|
+
// was present/missing across the multi-step tool-loop history.
|
|
226
|
+
requestBodyShape: summarizeRequestBodyShape(e?.requestBodyValues),
|
|
132
227
|
cause: e?.cause && typeof e.cause === "object"
|
|
133
228
|
? {
|
|
134
229
|
message: typeof e.cause.message === "string"
|
|
@@ -14,6 +14,14 @@ export interface DecideOpts {
|
|
|
14
14
|
signal?: AbortSignal;
|
|
15
15
|
defaultModel: string;
|
|
16
16
|
defaultProvider: string;
|
|
17
|
+
/**
|
|
18
|
+
* Optional session id for audit logging. When provided, a `routing`
|
|
19
|
+
* interaction event is emitted whenever the turn's routed model differs from
|
|
20
|
+
* `defaultModel` (the stored session.model) — making per-turn overrides
|
|
21
|
+
* observable instead of silent. Fixes the "session.model lie": a user on
|
|
22
|
+
* flash could not see when the router silently promoted them to pro.
|
|
23
|
+
*/
|
|
24
|
+
sessionId?: string;
|
|
17
25
|
/** Override home directory for ledger (testing). */
|
|
18
26
|
homeOverride?: string;
|
|
19
27
|
/** PIL enrichment signals — forwarded to EE context. */
|
|
@@ -27,6 +35,11 @@ export interface DecideOpts {
|
|
|
27
35
|
projectSize?: "small" | "medium" | "large" | null;
|
|
28
36
|
filesTouched?: number;
|
|
29
37
|
mode?: string | null;
|
|
38
|
+
turnIndex?: number;
|
|
39
|
+
messageCount?: number;
|
|
40
|
+
compactionCount?: number;
|
|
41
|
+
totalSavedTokens?: number;
|
|
42
|
+
compactionSummary?: string | null;
|
|
30
43
|
};
|
|
31
44
|
}
|
|
32
45
|
export declare function clearRouteCache(): void;
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* If cap breach detected, downgrade chain overrides classifier output (ROUTE-06).
|
|
7
7
|
*/
|
|
8
8
|
import { getDefaultEEClient } from "../ee/intercept.js";
|
|
9
|
-
import {
|
|
9
|
+
import { getModelInfo, getModelsForProvider } from "../models/registry.js";
|
|
10
10
|
import { taskTypeToRole } from "../pil/task-tier-map.js";
|
|
11
11
|
import { detectProviderForModel } from "../providers/runtime.js";
|
|
12
12
|
import { ALL_PROVIDER_IDS } from "../providers/types.js";
|
|
@@ -14,9 +14,10 @@ import { downgradeChain, emitDowngrade, getDowngradeChain } from "../usage/downg
|
|
|
14
14
|
import { release, reserve } from "../usage/ledger.js";
|
|
15
15
|
import { midstreamPolicy } from "../usage/midstream.js";
|
|
16
16
|
import { CapBreachError } from "../usage/types.js";
|
|
17
|
-
import { getRoleModel, isCouncilMultiProviderPreferred, isProviderDisabled } from "../utils/settings.js";
|
|
17
|
+
import { getRoleModel, getRoutingPromoteMax, isCouncilMultiProviderPreferred, isProviderDisabled, } from "../utils/settings.js";
|
|
18
18
|
import { classify } from "./classifier/index.js";
|
|
19
19
|
import { callColdRoute } from "./cold.js";
|
|
20
|
+
import { adjustPeakHourModel, getRoutedModelByTier } from "./peak-hour.js";
|
|
20
21
|
import { isInheritProvider } from "./provider-sentinel.js";
|
|
21
22
|
import { routerStore } from "./store.js";
|
|
22
23
|
import { callWarmRoute } from "./warm.js";
|
|
@@ -75,6 +76,16 @@ function buildRouteContext(cwd, pil) {
|
|
|
75
76
|
ctx.filesTouched = pil.filesTouched;
|
|
76
77
|
if (pil?.mode)
|
|
77
78
|
ctx.mode = pil.mode;
|
|
79
|
+
if (pil?.turnIndex !== undefined)
|
|
80
|
+
ctx.turnIndex = pil.turnIndex;
|
|
81
|
+
if (pil?.messageCount !== undefined)
|
|
82
|
+
ctx.messageCount = pil.messageCount;
|
|
83
|
+
if (pil?.compactionCount !== undefined)
|
|
84
|
+
ctx.compactionCount = pil.compactionCount;
|
|
85
|
+
if (pil?.totalSavedTokens !== undefined)
|
|
86
|
+
ctx.totalSavedTokens = pil.totalSavedTokens;
|
|
87
|
+
if (pil?.compactionSummary)
|
|
88
|
+
ctx.compactionSummary = pil.compactionSummary;
|
|
78
89
|
return ctx;
|
|
79
90
|
}
|
|
80
91
|
// ─── Disabled-provider guard: fallback providers ────────────────────────────
|
|
@@ -90,7 +101,7 @@ function resolveEffectiveDefaults(opts) {
|
|
|
90
101
|
}
|
|
91
102
|
for (const p of FALLBACK_PROVIDERS) {
|
|
92
103
|
if (!isProviderDisabled(p)) {
|
|
93
|
-
const m =
|
|
104
|
+
const m = getRoutedModelByTier("balanced", p);
|
|
94
105
|
// Guard: getModelByTier may return a model from a different provider
|
|
95
106
|
// when the preferred provider has no model for the requested tier.
|
|
96
107
|
if (m && m.provider === p)
|
|
@@ -114,7 +125,7 @@ function resolveTierModel(tier, defaultProvider) {
|
|
|
114
125
|
}
|
|
115
126
|
for (const p of FALLBACK_PROVIDERS) {
|
|
116
127
|
if (!isProviderDisabled(p)) {
|
|
117
|
-
const m =
|
|
128
|
+
const m = getRoutedModelByTier(tier, p);
|
|
118
129
|
// Guard: getModelByTier may return a model from a different provider
|
|
119
130
|
// when the preferred provider has no model for the requested tier.
|
|
120
131
|
if (m && m.provider === p)
|
|
@@ -126,6 +137,17 @@ function resolveTierModel(tier, defaultProvider) {
|
|
|
126
137
|
}
|
|
127
138
|
return undefined;
|
|
128
139
|
}
|
|
140
|
+
function applyPeakHourRoute(dec) {
|
|
141
|
+
const adj = adjustPeakHourModel(dec.model);
|
|
142
|
+
if (!adj.adjusted)
|
|
143
|
+
return dec;
|
|
144
|
+
return {
|
|
145
|
+
...dec,
|
|
146
|
+
model: adj.modelId,
|
|
147
|
+
provider: adj.provider,
|
|
148
|
+
reason: `${dec.reason}|${adj.reason}`,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
129
151
|
// ─── Provider constraint: never route to a provider the user lacks a key for ─
|
|
130
152
|
function constrainToProvider(decision, opts) {
|
|
131
153
|
// Inherit-sentinel: warm path may emit an empty provider to signal
|
|
@@ -134,11 +156,11 @@ function constrainToProvider(decision, opts) {
|
|
|
134
156
|
if (isInheritProvider(decision.provider)) {
|
|
135
157
|
const resolved = detectProviderForModel(decision.model);
|
|
136
158
|
if (resolved && !isProviderDisabled(resolved))
|
|
137
|
-
return decision;
|
|
159
|
+
return applyPeakHourRoute(decision);
|
|
138
160
|
if (resolved && isProviderDisabled(resolved)) {
|
|
139
161
|
return constrainToProvider({ ...decision, provider: resolved }, opts);
|
|
140
162
|
}
|
|
141
|
-
return decision;
|
|
163
|
+
return applyPeakHourRoute(decision);
|
|
142
164
|
}
|
|
143
165
|
// Provider-only UX: the user enables N providers and pins one as default.
|
|
144
166
|
// Routing rules:
|
|
@@ -150,7 +172,7 @@ function constrainToProvider(decision, opts) {
|
|
|
150
172
|
// surface a config error elsewhere).
|
|
151
173
|
const decisionDisabled = isProviderDisabled(decision.provider);
|
|
152
174
|
if (!decisionDisabled) {
|
|
153
|
-
return decision;
|
|
175
|
+
return applyPeakHourRoute(decision);
|
|
154
176
|
}
|
|
155
177
|
if (isProviderDisabled(opts.defaultProvider)) {
|
|
156
178
|
return {
|
|
@@ -158,7 +180,7 @@ function constrainToProvider(decision, opts) {
|
|
|
158
180
|
reason: `${decision.reason}|provider-not-constrained(default-also-disabled)`,
|
|
159
181
|
};
|
|
160
182
|
}
|
|
161
|
-
const sameProviderModel =
|
|
183
|
+
const sameProviderModel = getRoutedModelByTier(decision.tier === "hot" ? "fast" : decision.tier === "cold" ? "premium" : "balanced", opts.defaultProvider);
|
|
162
184
|
if (sameProviderModel && sameProviderModel.provider !== opts.defaultProvider) {
|
|
163
185
|
return {
|
|
164
186
|
...decision,
|
|
@@ -167,12 +189,12 @@ function constrainToProvider(decision, opts) {
|
|
|
167
189
|
reason: `${decision.reason}|provider-constrained(forced-default)`,
|
|
168
190
|
};
|
|
169
191
|
}
|
|
170
|
-
return {
|
|
192
|
+
return applyPeakHourRoute({
|
|
171
193
|
...decision,
|
|
172
194
|
model: sameProviderModel?.id ?? opts.defaultModel,
|
|
173
195
|
provider: sameProviderModel?.provider ?? opts.defaultProvider,
|
|
174
196
|
reason: `${decision.reason}|provider-constrained`,
|
|
175
|
-
};
|
|
197
|
+
});
|
|
176
198
|
}
|
|
177
199
|
// ─── Route feedback (HTTP path) ─────────────────────────────────────────────
|
|
178
200
|
/**
|
|
@@ -194,12 +216,78 @@ export function reportRouteOutcome(taskHash, outcome, duration) {
|
|
|
194
216
|
duration: duration ?? null,
|
|
195
217
|
});
|
|
196
218
|
}
|
|
219
|
+
// ─── Tier-promotion cap (cost-ceiling guard) ───────────────────────────────
|
|
220
|
+
const TIER_RANK = {
|
|
221
|
+
fast: 0,
|
|
222
|
+
balanced: 1,
|
|
223
|
+
premium: 2,
|
|
224
|
+
};
|
|
225
|
+
/**
|
|
226
|
+
* Enforce the user's tier-promotion ceiling. The session default model is the
|
|
227
|
+
* cost ceiling: the router may downgrade per turn but may not silently promote
|
|
228
|
+
* beyond `routingPromoteMax` (default "balanced"). See settings.ts.
|
|
229
|
+
*
|
|
230
|
+
* When the decision would promote, clamp down to the max allowed tier on the
|
|
231
|
+
* SAME provider. If no same-provider model exists at the ceiling tier, fall
|
|
232
|
+
* back to the session default model (the user's explicit pick). The clamp is
|
|
233
|
+
* skipped for: the `"any"` opt-in, the role path (explicit user roleModels
|
|
234
|
+
* config is itself the opt-in), cap-halt decisions, and provider-constrained
|
|
235
|
+
* disabled-provider recoveries (those already move toward the default).
|
|
236
|
+
*/
|
|
237
|
+
function applyPromotionCap(dec, defaultModel) {
|
|
238
|
+
if (dec.model === "HALT" || dec.model === defaultModel)
|
|
239
|
+
return dec;
|
|
240
|
+
const cap = getRoutingPromoteMax();
|
|
241
|
+
if (cap === "any")
|
|
242
|
+
return dec;
|
|
243
|
+
const capRank = cap === "off" ? null : TIER_RANK[cap]; // "balanced" → 1
|
|
244
|
+
const defaultTier = getModelInfo(defaultModel)?.tier;
|
|
245
|
+
// "off" means ceiling = the default model's own tier.
|
|
246
|
+
const maxAllowedRank = capRank === null ? (defaultTier ? TIER_RANK[defaultTier] : 0) : capRank;
|
|
247
|
+
const decInfo = getModelInfo(dec.model);
|
|
248
|
+
const decTier = decInfo?.tier;
|
|
249
|
+
if (!decTier || TIER_RANK[decTier] <= maxAllowedRank)
|
|
250
|
+
return dec;
|
|
251
|
+
// Promotion exceeds the ceiling — clamp DOWN to the max allowed tier on the
|
|
252
|
+
// same provider. Walk down from the ceiling so we pick the highest permitted.
|
|
253
|
+
const provider = decInfo?.provider ?? detectProviderForModel(dec.model);
|
|
254
|
+
const targetTiers = capRank === null
|
|
255
|
+
? defaultTier
|
|
256
|
+
? [defaultTier]
|
|
257
|
+
: ["fast"]
|
|
258
|
+
: maxAllowedRank >= 1
|
|
259
|
+
? ["balanced", "fast"]
|
|
260
|
+
: ["fast"];
|
|
261
|
+
for (const t of targetTiers) {
|
|
262
|
+
if (TIER_RANK[t] > maxAllowedRank)
|
|
263
|
+
continue;
|
|
264
|
+
const m = getRoutedModelByTier(t, provider);
|
|
265
|
+
if (m && m.provider === provider) {
|
|
266
|
+
return {
|
|
267
|
+
...dec,
|
|
268
|
+
model: m.id,
|
|
269
|
+
reason: `${dec.reason} | promo-cap(${decTier}→${t})`,
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
// No cheaper model on the same provider — fall back to the session default.
|
|
274
|
+
return {
|
|
275
|
+
...dec,
|
|
276
|
+
model: defaultModel,
|
|
277
|
+
reason: `${dec.reason} | promo-cap(${decTier}→default:${defaultModel})`,
|
|
278
|
+
};
|
|
279
|
+
}
|
|
197
280
|
/**
|
|
198
281
|
* Apply cap-check to a RouteDecision. Walks the downgrade chain if
|
|
199
282
|
* the reservation would breach the cap. Returns the (possibly downgraded) decision.
|
|
283
|
+
*
|
|
284
|
+
* `opts` carries both the ledger homeOverride and the session defaultModel used
|
|
285
|
+
* by the promotion cap. `exempt` skips the promotion cap — used only for the
|
|
286
|
+
* role path, where the user's explicit roleModels config is itself the opt-in.
|
|
200
287
|
*/
|
|
201
|
-
async function capCheck(dec,
|
|
202
|
-
let current = { ...dec };
|
|
288
|
+
async function capCheck(dec, opts, exempt) {
|
|
289
|
+
let current = exempt ? { ...dec } : applyPromotionCap({ ...dec }, opts.defaultModel);
|
|
290
|
+
const homeOverride = opts.homeOverride;
|
|
203
291
|
let attempts = 0;
|
|
204
292
|
while (attempts++ < getDowngradeChain().length) {
|
|
205
293
|
// If midstream policy already refuses, halt immediately
|
|
@@ -305,14 +393,15 @@ export async function decide(prompt, opts) {
|
|
|
305
393
|
providerDisabled: isProviderDisabled(provider),
|
|
306
394
|
multiProviderPreferred: isCouncilMultiProviderPreferred(),
|
|
307
395
|
})) {
|
|
396
|
+
const peak = adjustPeakHourModel(roleModelId);
|
|
308
397
|
const d = {
|
|
309
398
|
tier: "hot",
|
|
310
|
-
model:
|
|
311
|
-
provider,
|
|
312
|
-
reason: `role:${role}→${roleModelId}`,
|
|
399
|
+
model: peak.modelId,
|
|
400
|
+
provider: peak.provider,
|
|
401
|
+
reason: peak.adjusted ? `role:${role}→${peak.modelId}|${peak.reason}` : `role:${role}→${roleModelId}`,
|
|
313
402
|
source: "role",
|
|
314
403
|
};
|
|
315
|
-
const checked = await capCheck(d, opts
|
|
404
|
+
const checked = await capCheck(d, opts, /* exempt */ true);
|
|
316
405
|
routerStore.setState({ tier: checked.tier, lastDecision: checked, taskHash: null, source: "role" });
|
|
317
406
|
if (cacheKey && !checked.cap_overridden)
|
|
318
407
|
setCachedRoute(cacheKey, checked);
|
|
@@ -328,7 +417,7 @@ export async function decide(prompt, opts) {
|
|
|
328
417
|
if (pilTier && pilConf >= 0.6) {
|
|
329
418
|
// Use effective (non-disabled) provider when default is disabled
|
|
330
419
|
const effective = resolveTierModel(pilTier, opts.defaultProvider);
|
|
331
|
-
let tierModel = effective ??
|
|
420
|
+
let tierModel = effective ?? getRoutedModelByTier(pilTier, opts.defaultProvider);
|
|
332
421
|
// Guard: getModelByTier may cross to another provider when defaultProvider
|
|
333
422
|
// has no model for the requested tier. If that cross-provider is disabled,
|
|
334
423
|
// pin to the default model on the default provider instead.
|
|
@@ -338,17 +427,21 @@ export async function decide(prompt, opts) {
|
|
|
338
427
|
isProviderDisabled(tierModel.provider)) {
|
|
339
428
|
tierModel = undefined;
|
|
340
429
|
}
|
|
430
|
+
const pilModel = tierModel?.id ?? opts.defaultModel;
|
|
431
|
+
const peak = adjustPeakHourModel(pilModel);
|
|
341
432
|
const d = {
|
|
342
433
|
tier: "hot",
|
|
343
|
-
model:
|
|
344
|
-
provider: tierModel?.provider ??
|
|
345
|
-
reason:
|
|
346
|
-
? `pil:${pilTier}(${pilConf.toFixed(2)})-rerouted(disabled-default)`
|
|
347
|
-
:
|
|
434
|
+
model: peak.modelId,
|
|
435
|
+
provider: tierModel?.provider ?? peak.provider,
|
|
436
|
+
reason: peak.adjusted
|
|
437
|
+
? `${effective ? `pil:${pilTier}(${pilConf.toFixed(2)})-rerouted(disabled-default)` : `pil:${pilTier}(${pilConf.toFixed(2)})`}|${peak.reason}`
|
|
438
|
+
: effective
|
|
439
|
+
? `pil:${pilTier}(${pilConf.toFixed(2)})-rerouted(disabled-default)`
|
|
440
|
+
: `pil:${pilTier}(${pilConf.toFixed(2)})`,
|
|
348
441
|
confidence: pilConf,
|
|
349
442
|
source: "pil",
|
|
350
443
|
};
|
|
351
|
-
const checked = await capCheck(d, opts
|
|
444
|
+
const checked = await capCheck(d, opts);
|
|
352
445
|
routerStore.setState({
|
|
353
446
|
tier: checked.tier,
|
|
354
447
|
lastDecision: checked,
|
|
@@ -364,7 +457,7 @@ export async function decide(prompt, opts) {
|
|
|
364
457
|
if (c.tier === "hot") {
|
|
365
458
|
// Use effective (non-disabled) provider when default is disabled
|
|
366
459
|
const effective = c.tierHint ? resolveTierModel(c.tierHint, opts.defaultProvider) : undefined;
|
|
367
|
-
let tierModel = effective ?? (c.tierHint ?
|
|
460
|
+
let tierModel = effective ?? (c.tierHint ? getRoutedModelByTier(c.tierHint, opts.defaultProvider) : undefined);
|
|
368
461
|
// Same guard as the PIL branch above: drop cross-provider fallback when
|
|
369
462
|
// the cross-provider is disabled, so we don't switch to a provider the
|
|
370
463
|
// user has turned off in the splash modal.
|
|
@@ -374,14 +467,20 @@ export async function decide(prompt, opts) {
|
|
|
374
467
|
isProviderDisabled(tierModel.provider)) {
|
|
375
468
|
tierModel = undefined;
|
|
376
469
|
}
|
|
470
|
+
const hotModel = tierModel?.id ?? opts.defaultModel;
|
|
471
|
+
const peak = adjustPeakHourModel(hotModel);
|
|
377
472
|
const d = {
|
|
378
473
|
tier: "hot",
|
|
379
|
-
model:
|
|
380
|
-
provider: tierModel?.provider ??
|
|
381
|
-
reason:
|
|
474
|
+
model: peak.modelId,
|
|
475
|
+
provider: tierModel?.provider ?? peak.provider,
|
|
476
|
+
reason: peak.adjusted
|
|
477
|
+
? `${effective ? `${c.reason}-rerouted(disabled-default)` : c.reason}|${peak.reason}`
|
|
478
|
+
: effective
|
|
479
|
+
? `${c.reason}-rerouted(disabled-default)`
|
|
480
|
+
: c.reason,
|
|
382
481
|
confidence: c.confidence,
|
|
383
482
|
};
|
|
384
|
-
const checked = await capCheck(d, opts
|
|
483
|
+
const checked = await capCheck(d, opts);
|
|
385
484
|
routerStore.setState({
|
|
386
485
|
tier: checked.tier,
|
|
387
486
|
lastDecision: checked,
|
|
@@ -395,7 +494,7 @@ export async function decide(prompt, opts) {
|
|
|
395
494
|
// Step 2: Warm path (EE /api/route-model, 250ms timeout)
|
|
396
495
|
const w = await callWarmRoute(prompt, { ...opts, context: routeCtx });
|
|
397
496
|
if (w) {
|
|
398
|
-
const checked = await capCheck(constrainToProvider(w, opts), opts
|
|
497
|
+
const checked = await capCheck(constrainToProvider(w, opts), opts);
|
|
399
498
|
routerStore.setState({
|
|
400
499
|
tier: checked.tier,
|
|
401
500
|
lastDecision: checked,
|
|
@@ -409,7 +508,7 @@ export async function decide(prompt, opts) {
|
|
|
409
508
|
// Step 3: Cold path (EE /api/cold-route, 1s timeout)
|
|
410
509
|
const cd = await callColdRoute(prompt, { ...opts, context: routeCtx });
|
|
411
510
|
if (cd) {
|
|
412
|
-
const checked = await capCheck(constrainToProvider(cd, opts), opts
|
|
511
|
+
const checked = await capCheck(constrainToProvider(cd, opts), opts);
|
|
413
512
|
routerStore.setState({
|
|
414
513
|
tier: "cold",
|
|
415
514
|
lastDecision: checked,
|
|
@@ -422,15 +521,18 @@ export async function decide(prompt, opts) {
|
|
|
422
521
|
}
|
|
423
522
|
// Step 4: Final fallback when EE entirely unreachable
|
|
424
523
|
const effective = resolveEffectiveDefaults(opts);
|
|
524
|
+
const peak = adjustPeakHourModel(effective.model);
|
|
425
525
|
const fallback = {
|
|
426
526
|
tier: routerStore.getState().degraded ? "degraded" : "hot",
|
|
427
|
-
model:
|
|
428
|
-
provider:
|
|
429
|
-
reason:
|
|
430
|
-
? "fallback:ee-unreachable+rerouted(disabled-default)"
|
|
431
|
-
:
|
|
527
|
+
model: peak.modelId,
|
|
528
|
+
provider: peak.provider,
|
|
529
|
+
reason: peak.adjusted
|
|
530
|
+
? `${effective.provider !== opts.defaultProvider ? "fallback:ee-unreachable+rerouted(disabled-default)" : "fallback:ee-unreachable"}|${peak.reason}`
|
|
531
|
+
: effective.provider !== opts.defaultProvider
|
|
532
|
+
? "fallback:ee-unreachable+rerouted(disabled-default)"
|
|
533
|
+
: "fallback:ee-unreachable",
|
|
432
534
|
};
|
|
433
|
-
const checked = await capCheck(fallback, opts
|
|
535
|
+
const checked = await capCheck(fallback, opts);
|
|
434
536
|
routerStore.setState({
|
|
435
537
|
lastDecision: checked,
|
|
436
538
|
taskHash: null,
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Peak-hour routing — rules loaded from catalog API `provider_policies.peak_hour`
|
|
3
|
+
* (vendor-sourced metadata). User settings only toggle enabled + switch/downgrade mode.
|
|
4
|
+
*/
|
|
5
|
+
import type { CatalogProviderPeakHour } from "../models/catalog-client.js";
|
|
6
|
+
import type { ProviderId } from "../providers/types.js";
|
|
7
|
+
import type { ModelInfo } from "../types/index.js";
|
|
8
|
+
import { type PeakHourPolicy } from "../utils/settings.js";
|
|
9
|
+
export type PeakHourMode = "downgrade" | "switch";
|
|
10
|
+
export interface PeakHourAdjustment {
|
|
11
|
+
modelId: string;
|
|
12
|
+
provider: ProviderId;
|
|
13
|
+
adjusted: boolean;
|
|
14
|
+
reason?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function hourInTimezone(now: Date, timezone: string): number;
|
|
17
|
+
/** @deprecated Use hourInTimezone — kept for tests referencing UTC+8. */
|
|
18
|
+
export declare function hourUtc8(now: Date): number;
|
|
19
|
+
export declare function peakHourWindows(rule: CatalogProviderPeakHour): Array<{
|
|
20
|
+
start_hour: number;
|
|
21
|
+
end_hour: number;
|
|
22
|
+
}>;
|
|
23
|
+
export declare function isPeakHourForProvider(provider: ProviderId, now: Date, userPolicy?: PeakHourPolicy): boolean;
|
|
24
|
+
/** @deprecated Use isPeakHourForProvider(provider, ...) — window is per-provider from catalog. */
|
|
25
|
+
export declare function isPeakHourUtc8(now: Date, userPolicy: PeakHourPolicy): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Adjust a concrete model id for peak-hour policy. No-op outside the provider's
|
|
28
|
+
* catalog-defined window or when user policy is disabled.
|
|
29
|
+
*/
|
|
30
|
+
export declare function adjustPeakHourModel(modelId: string, opts?: {
|
|
31
|
+
now?: Date;
|
|
32
|
+
policy?: PeakHourPolicy;
|
|
33
|
+
}): PeakHourAdjustment;
|
|
34
|
+
/** Tier lookup with peak-hour adjustment applied to the resolved model. */
|
|
35
|
+
export declare function getRoutedModelByTier(tier: "fast" | "balanced" | "premium", preferProvider?: string, opts?: {
|
|
36
|
+
now?: Date;
|
|
37
|
+
policy?: PeakHourPolicy;
|
|
38
|
+
}): ModelInfo | undefined;
|