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
package/dist/src/council/llm.js
CHANGED
|
@@ -1,20 +1,31 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
|
-
import { generateText, stepCountIs } from "ai";
|
|
2
|
+
import { generateText, stepCountIs, streamText } from "ai";
|
|
3
3
|
import { getDefaultEEClient } from "../ee/intercept.js";
|
|
4
4
|
import { emitMatches } from "../ee/render.js";
|
|
5
|
+
import { getMcpKey } from "../mcp/mcp-keychain.js";
|
|
5
6
|
import { buildMcpToolSet } from "../mcp/runtime.js";
|
|
6
|
-
import {
|
|
7
|
+
import { getModelInfo } from "../models/registry.js";
|
|
8
|
+
import { getProviderCapabilities, resolveTemperature } from "../providers/capabilities.js";
|
|
7
9
|
import { loadKeyForProvider, ProviderKeyMissingError } from "../providers/keychain.js";
|
|
8
|
-
import { createProviderFactoryAsync, detectProviderForModel, resolveModelRuntime } from "../providers/runtime.js";
|
|
10
|
+
import { createProviderFactoryAsync, detectProviderForModel, resolveModelRuntime, shouldDropParam, } from "../providers/runtime.js";
|
|
11
|
+
import { wireDebug } from "../providers/wire-debug.js";
|
|
12
|
+
import { statusBarStore } from "../state/status-bar-store.js";
|
|
13
|
+
import { recordUsageEvent } from "../storage/index.js";
|
|
9
14
|
import { createBuiltinTools as createTools } from "../tools/registry.js";
|
|
10
15
|
import { appendCostLog } from "../usage/cost-log.js";
|
|
11
16
|
import { projectCostUSD } from "../usage/estimator.js";
|
|
12
17
|
import { withDeadlineRace, withTimeoutSignal } from "../utils/llm-deadline.js";
|
|
18
|
+
import { logger } from "../utils/logger.js";
|
|
13
19
|
import { loadMcpServers } from "../utils/settings.js";
|
|
14
20
|
import { withVisibleRetry } from "../utils/visible-retry.js";
|
|
15
21
|
import { buildResearchSystemPrompt } from "./prompts.js";
|
|
22
|
+
import { stripThinkBlocks } from "./strip-think.js";
|
|
16
23
|
/**
|
|
17
|
-
*
|
|
24
|
+
* Register a provider factory for a council sub-call, OAuth-aware.
|
|
25
|
+
*
|
|
26
|
+
* A council roster routes stances to providers the session itself never built,
|
|
27
|
+
* so their factory must exist in the registry before `resolveModelRuntime` can
|
|
28
|
+
* derive it from the model id.
|
|
18
29
|
*
|
|
19
30
|
* The council reachability gate (`isProviderReachable` in leader.ts) counts
|
|
20
31
|
* OAuth-authenticated providers as usable (via `getConfiguredProviders`), so a
|
|
@@ -27,7 +38,7 @@ import { buildResearchSystemPrompt } from "./prompts.js";
|
|
|
27
38
|
* refreshes the stored OAuth bearer token. Only the expected missing-key case
|
|
28
39
|
* is swallowed; unexpected errors propagate.
|
|
29
40
|
*/
|
|
30
|
-
async function
|
|
41
|
+
async function ensureCouncilFactory(providerId) {
|
|
31
42
|
let apiKey;
|
|
32
43
|
try {
|
|
33
44
|
apiKey = await loadKeyForProvider(providerId);
|
|
@@ -37,8 +48,7 @@ async function resolveCouncilFactory(providerId) {
|
|
|
37
48
|
throw err;
|
|
38
49
|
// OAuth-only provider — createProviderFactoryAsync injects the bearer token.
|
|
39
50
|
}
|
|
40
|
-
|
|
41
|
-
return factory;
|
|
51
|
+
await createProviderFactoryAsync(providerId, apiKey ? { apiKey } : {});
|
|
42
52
|
}
|
|
43
53
|
function getDebugLogPath() {
|
|
44
54
|
const p = process.env.MUONROI_COUNCIL_DEBUG_LOG;
|
|
@@ -186,6 +196,62 @@ function logCouncilCost(args) {
|
|
|
186
196
|
}).catch(() => undefined);
|
|
187
197
|
return usage;
|
|
188
198
|
}
|
|
199
|
+
/**
|
|
200
|
+
* Record a council LLM call into the `usage_events` table with source="council".
|
|
201
|
+
*
|
|
202
|
+
* This is the SINGLE source of truth for council usage accounting: it fires from
|
|
203
|
+
* inside every council generate/debate/research call so ALL council entry points
|
|
204
|
+
* (the /council slash path, auto-council, and every /ideal phase — clarifier,
|
|
205
|
+
* research, generate, sprint) land in usage_events. Before this existed, only
|
|
206
|
+
* the loop-driver's `runDebate` call site externally wrapped usage recording, so
|
|
207
|
+
* `runCouncilV2` (/council + auto-council) and the non-debate /ideal phases never
|
|
208
|
+
* recorded — their token cost was invisible to session totals, the StatusBar,
|
|
209
|
+
* `usage forensics`, and the cost caps (root cause of session f24c28b6dcb3:
|
|
210
|
+
* council ran but produced 0 source="council" usage_events).
|
|
211
|
+
*
|
|
212
|
+
* Best-effort: a null sessionId (no chat session FK) or a DB failure must never
|
|
213
|
+
* break the council run, but per the No-Silent-Catch rule we log the failure.
|
|
214
|
+
*/
|
|
215
|
+
export function recordCouncilUsage(sessionId, modelId, usage) {
|
|
216
|
+
if (!sessionId)
|
|
217
|
+
return;
|
|
218
|
+
try {
|
|
219
|
+
recordUsageEvent(sessionId, "council", modelId, {
|
|
220
|
+
inputTokens: usage.inputTokens,
|
|
221
|
+
outputTokens: usage.outputTokens,
|
|
222
|
+
cacheReadTokens: usage.cachedInputTokens,
|
|
223
|
+
});
|
|
224
|
+
// Mirror council billing into the live StatusBar so cache-hit% / tokens /
|
|
225
|
+
// cost reflect the WHOLE session (council calls have ~0 cache; excluding
|
|
226
|
+
// them overstated the message-only cache ratio — session f24c28b6dcb3).
|
|
227
|
+
// ONLY the five cumulative billing counters — NEVER ctx_tokens/ctx_pct/
|
|
228
|
+
// model/provider, which describe the current MAIN-conversation call and
|
|
229
|
+
// would be clobbered by a small council sub-call.
|
|
230
|
+
const totalInput = usage.inputTokens;
|
|
231
|
+
const output = usage.outputTokens;
|
|
232
|
+
const cacheRead = usage.cachedInputTokens;
|
|
233
|
+
const info = getModelInfo(modelId);
|
|
234
|
+
const priceIn = info?.inputPrice ?? 0;
|
|
235
|
+
const priceCached = info?.cachedInputPrice ?? priceIn * 0.1;
|
|
236
|
+
const priceOut = info?.outputPrice ?? 0;
|
|
237
|
+
const nonCachedInput = Math.max(0, totalInput - cacheRead);
|
|
238
|
+
const turnCostMicros = nonCachedInput * priceIn + cacheRead * priceCached + output * priceOut;
|
|
239
|
+
const prev = statusBarStore.getState();
|
|
240
|
+
statusBarStore.setState({
|
|
241
|
+
in_tokens: prev.in_tokens + totalInput,
|
|
242
|
+
out_tokens: prev.out_tokens + output,
|
|
243
|
+
cache_read_tokens: (prev.cache_read_tokens ?? 0) + cacheRead,
|
|
244
|
+
session_usd: prev.session_usd + turnCostMicros / 1_000_000,
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
catch (err) {
|
|
248
|
+
logger.error("storage", "recordUsageEvent(council) failed — token cost not accounted", {
|
|
249
|
+
sessionId,
|
|
250
|
+
modelId,
|
|
251
|
+
message: err instanceof Error ? err.message : String(err),
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
}
|
|
189
255
|
function getMockLlm() {
|
|
190
256
|
// biome-ignore lint/suspicious/noExplicitAny: intentionally untyped global access
|
|
191
257
|
return globalThis.__muonroiMockLlm ?? null;
|
|
@@ -209,6 +275,154 @@ const COUNCIL_LLM_TIMEOUT_MS = (() => {
|
|
|
209
275
|
// withTimeoutSignal + withDeadlineRace moved to ../utils/llm-deadline.js so all
|
|
210
276
|
// pre-flight LLM call sites (council, debate-planner, scope-ceiling) share one
|
|
211
277
|
// implementation. Imported at the top of this file.
|
|
278
|
+
/**
|
|
279
|
+
* Run a single-shot LLM call over the STREAMING transport and collect the full
|
|
280
|
+
* result, returning a `generateText`-shaped object ({ text, usage, finishReason,
|
|
281
|
+
* reasoningText }).
|
|
282
|
+
*
|
|
283
|
+
* Why stream a one-shot generate? The OpenAI codex/oauth endpoint
|
|
284
|
+
* (chatgpt.com/backend-api/codex/responses, used by gpt-5.*-codex subscription
|
|
285
|
+
* auth) HARD-REJECTS non-streaming requests with 400 `{"detail":"Stream must be
|
|
286
|
+
* set to true"}`. `generateText` issues a non-stream POST, so every council
|
|
287
|
+
* sub-task that ran through it (leader round evaluation, clarify, spec
|
|
288
|
+
* synthesis, running summary) failed on a codex session — surfacing to the user
|
|
289
|
+
* as the opaque "Decision: evaluation unavailable" round card (diagnosed from
|
|
290
|
+
* session 8191ecaee149: gpt-5.4-mini → codex/responses → "Stream must be set to
|
|
291
|
+
* true"). The panel debate never hit this because it streams. Streaming is the
|
|
292
|
+
* universal transport (every provider + the whole TUI already use it), so
|
|
293
|
+
* collecting a streamed result fixes codex without special-casing it.
|
|
294
|
+
*
|
|
295
|
+
* A provider `error` part is re-thrown so the caller's retry / cross-provider
|
|
296
|
+
* fallback treats it as a failure exactly as a thrown `generateText` did.
|
|
297
|
+
*
|
|
298
|
+
* Also used by `debate()` (the panel pair turns) with the tiny verification
|
|
299
|
+
* toolset: pass `tools`/`stopWhen`/`prepareStep` and the collected `toolCalls`
|
|
300
|
+
* (toolName + input + matched result) come back in the same shape the old
|
|
301
|
+
* `generateText` result exposed. A debater on the codex/oauth endpoint hit the
|
|
302
|
+
* exact same non-stream 400 as the eval path — streaming fixes it uniformly.
|
|
303
|
+
*/
|
|
304
|
+
/**
|
|
305
|
+
* Spread for the `maxOutputTokens` param, omitted when the resolved runtime
|
|
306
|
+
* rejects it. The ChatGPT Codex OAuth endpoint (chatgpt.com/backend-api/codex/
|
|
307
|
+
* responses) 400s with `{"detail":"Unsupported parameter: max_output_tokens"}`
|
|
308
|
+
* on EVERY council sub-call (clarify / debate / research) — every council
|
|
309
|
+
* generate on a Codex-OAuth session was failing wholesale. Mirrors the
|
|
310
|
+
* orchestrator + classify paths, which already gate this param via
|
|
311
|
+
* `shouldDropParam`.
|
|
312
|
+
*/
|
|
313
|
+
function maxOutSpread(runtime, n) {
|
|
314
|
+
return shouldDropParam(runtime, "maxOutputTokens") ? {} : { maxOutputTokens: n };
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Push-based stream liveness — module-level because the only readers
|
|
318
|
+
* (`tracedAsync` wrappers in debate.ts) sit OUTSIDE the `CouncilLLM` interface
|
|
319
|
+
* and cannot reach the in-flight `collectStreamText` any other way.
|
|
320
|
+
*
|
|
321
|
+
* Why it exists. `tracedAsync`'s 1s tick only materializes when the CONSUMER
|
|
322
|
+
* pulls `.next()`; a round that awaits its pairs via `Promise.all` stops
|
|
323
|
+
* pumping the tick generator, so `elapsedMs` FREEZES and a slow-but-alive run
|
|
324
|
+
* is indistinguishable from a hung one (observed: tick frozen at 33142ms for
|
|
325
|
+
* 8+ minutes while status was still "tick"). Token deltas are PUSHED here as
|
|
326
|
+
* they arrive, so liveness survives any back-pressure on the generator.
|
|
327
|
+
*/
|
|
328
|
+
let councilStreamedCharsTotal = 0;
|
|
329
|
+
let councilLastDeltaAt = 0;
|
|
330
|
+
/** Record `chars` of streamed output (text OR reasoning) against the live window. */
|
|
331
|
+
export function noteCouncilStreamDelta(chars) {
|
|
332
|
+
if (chars <= 0)
|
|
333
|
+
return;
|
|
334
|
+
councilStreamedCharsTotal += chars;
|
|
335
|
+
councilLastDeltaAt = Date.now();
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Open a liveness window and return a reader for it.
|
|
339
|
+
*
|
|
340
|
+
* `streamedChars` counts only what streamed SINCE the window opened, and
|
|
341
|
+
* `lastDeltaAgeMs` is measured from the window's own start until the first
|
|
342
|
+
* delta lands — so a cold stall reads as an age growing from 0, never as a
|
|
343
|
+
* bogus epoch-sized number. Reasoning-delta counts toward both: a reasoning
|
|
344
|
+
* model emits reasoning tokens for minutes before any text, and that is
|
|
345
|
+
* exactly the window an operator must not mistake for a hang.
|
|
346
|
+
*/
|
|
347
|
+
export function councilStreamLivenessReader() {
|
|
348
|
+
const baseChars = councilStreamedCharsTotal;
|
|
349
|
+
const windowStart = Date.now();
|
|
350
|
+
return () => ({
|
|
351
|
+
streamedChars: councilStreamedCharsTotal - baseChars,
|
|
352
|
+
lastDeltaAgeMs: Date.now() - (councilLastDeltaAt > windowStart ? councilLastDeltaAt : windowStart),
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
async function collectStreamText(args) {
|
|
356
|
+
const hasTools = !!args.tools && Object.keys(args.tools).length > 0;
|
|
357
|
+
const result = streamText({
|
|
358
|
+
model: args.model,
|
|
359
|
+
system: args.system,
|
|
360
|
+
prompt: args.prompt,
|
|
361
|
+
...(args.maxOutputTokens === undefined ? {} : { maxOutputTokens: args.maxOutputTokens }),
|
|
362
|
+
maxRetries: 0,
|
|
363
|
+
...(args.temperature === undefined ? {} : { temperature: args.temperature }),
|
|
364
|
+
...(args.providerOptions ? { providerOptions: args.providerOptions } : {}),
|
|
365
|
+
...(hasTools ? { tools: args.tools, stopWhen: args.stopWhen, prepareStep: args.prepareStep } : {}),
|
|
366
|
+
abortSignal: args.abortSignal,
|
|
367
|
+
});
|
|
368
|
+
let text = "";
|
|
369
|
+
let reasoningText = "";
|
|
370
|
+
let usage;
|
|
371
|
+
let finishReason;
|
|
372
|
+
const toolCalls = [];
|
|
373
|
+
const byId = new Map();
|
|
374
|
+
for await (const part of result.fullStream) {
|
|
375
|
+
switch (part.type) {
|
|
376
|
+
case "text-delta": {
|
|
377
|
+
const d = part.text ?? "";
|
|
378
|
+
text += d;
|
|
379
|
+
args.onDelta?.(d.length);
|
|
380
|
+
break;
|
|
381
|
+
}
|
|
382
|
+
case "reasoning-delta": {
|
|
383
|
+
// Reasoning deltas count as liveness: a reasoning model streams these
|
|
384
|
+
// for minutes before its first text-delta, and that silent-on-text
|
|
385
|
+
// window is precisely what gets misread as a hang.
|
|
386
|
+
const d = part.text ?? "";
|
|
387
|
+
reasoningText += d;
|
|
388
|
+
args.onDelta?.(d.length);
|
|
389
|
+
break;
|
|
390
|
+
}
|
|
391
|
+
case "tool-call": {
|
|
392
|
+
const p = part;
|
|
393
|
+
const tc = { toolName: p.toolName, input: p.input };
|
|
394
|
+
byId.set(p.toolCallId, tc);
|
|
395
|
+
toolCalls.push(tc);
|
|
396
|
+
break;
|
|
397
|
+
}
|
|
398
|
+
case "tool-result": {
|
|
399
|
+
const p = part;
|
|
400
|
+
const tc = byId.get(p.toolCallId);
|
|
401
|
+
if (tc)
|
|
402
|
+
tc.result = p.output;
|
|
403
|
+
break;
|
|
404
|
+
}
|
|
405
|
+
case "finish":
|
|
406
|
+
usage = part.totalUsage ?? part.usage;
|
|
407
|
+
finishReason = part.finishReason;
|
|
408
|
+
break;
|
|
409
|
+
case "error": {
|
|
410
|
+
const raw = part.error;
|
|
411
|
+
throw raw instanceof Error ? raw : new Error(String(raw));
|
|
412
|
+
}
|
|
413
|
+
default:
|
|
414
|
+
break;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
return { text, usage, finishReason, reasoningText: reasoningText || undefined, toolCalls };
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Test-only handle on the private stream collector, so `onDelta` (the liveness
|
|
421
|
+
* signal that tells a slow reasoning call from a hung one) is directly
|
|
422
|
+
* assertable without standing up a full council run. Not for production use.
|
|
423
|
+
* @internal
|
|
424
|
+
*/
|
|
425
|
+
export const __testCollectStreamText = collectStreamText;
|
|
212
426
|
export function createCouncilLLM(bash, mode, sessionId, stats) {
|
|
213
427
|
return {
|
|
214
428
|
async generate(modelId, system, prompt, maxTokens = 4096, onUsage, signal) {
|
|
@@ -216,11 +430,11 @@ export function createCouncilLLM(bash, mode, sessionId, stats) {
|
|
|
216
430
|
if (mock) {
|
|
217
431
|
stats.calls++;
|
|
218
432
|
const result = await mock.complete({ prompt });
|
|
219
|
-
return result.text;
|
|
433
|
+
return stripThinkBlocks(result.text);
|
|
220
434
|
}
|
|
221
435
|
const providerId = detectProviderForModel(modelId);
|
|
222
|
-
|
|
223
|
-
const runtime = resolveModelRuntime(
|
|
436
|
+
await ensureCouncilFactory(providerId);
|
|
437
|
+
const runtime = resolveModelRuntime(modelId);
|
|
224
438
|
const t0 = Date.now();
|
|
225
439
|
// Combine the user-abort signal (when threaded from runCouncil) with the
|
|
226
440
|
// per-call wall-clock deadline. Without the parent signal, an Esc/Ctrl-C
|
|
@@ -228,19 +442,25 @@ export function createCouncilLLM(bash, mode, sessionId, stats) {
|
|
|
228
442
|
// eval) was a no-op — the call ran to completion or hit the 5-min timeout.
|
|
229
443
|
const { signal: timedSignal, cleanup: cleanupTimeout } = withTimeoutSignal(signal, COUNCIL_LLM_TIMEOUT_MS);
|
|
230
444
|
try {
|
|
231
|
-
const result = await withDeadlineRace(() => withVisibleRetry(() =>
|
|
445
|
+
const result = await withDeadlineRace(() => withVisibleRetry(() =>
|
|
446
|
+
// Stream + collect (NOT generateText). The codex/oauth endpoint
|
|
447
|
+
// 400s on non-stream requests ("Stream must be set to true"),
|
|
448
|
+
// which nulled every council eval/clarify/synthesis on a codex
|
|
449
|
+
// session → the opaque "evaluation unavailable" card. See
|
|
450
|
+
// collectStreamText's doc for the full diagnosis.
|
|
451
|
+
collectStreamText({
|
|
232
452
|
model: runtime.model,
|
|
233
453
|
system,
|
|
234
454
|
prompt,
|
|
235
|
-
|
|
236
|
-
temperature:
|
|
237
|
-
//
|
|
238
|
-
//
|
|
239
|
-
//
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
...(runtime.providerOptions ? { providerOptions: runtime.providerOptions } : {}),
|
|
455
|
+
...maxOutSpread(runtime, maxTokens),
|
|
456
|
+
// Never hardcode temperature: some upstreams (Moonshot/Kimi via
|
|
457
|
+
// opencode-go) reject any value but their pinned one, which
|
|
458
|
+
// failed every clarify/spec call on a Kimi session. resolveTemperature
|
|
459
|
+
// omits the field or clamps to the model's fixed value.
|
|
460
|
+
temperature: resolveTemperature(providerId, runtime.modelInfo, 0.7),
|
|
461
|
+
providerOptions: runtime.providerOptions,
|
|
243
462
|
abortSignal: timedSignal,
|
|
463
|
+
onDelta: noteCouncilStreamDelta,
|
|
244
464
|
}), { label: "council.generate" }), COUNCIL_LLM_TIMEOUT_MS + 5_000, "council.generate", signal);
|
|
245
465
|
cleanupTimeout();
|
|
246
466
|
stats.calls++;
|
|
@@ -255,6 +475,7 @@ export function createCouncilLLM(bash, mode, sessionId, stats) {
|
|
|
255
475
|
durationMs: durMs,
|
|
256
476
|
});
|
|
257
477
|
onUsage?.(callUsage);
|
|
478
|
+
recordCouncilUsage(sessionId, modelId, callUsage);
|
|
258
479
|
writeDebugRecord({
|
|
259
480
|
ts: new Date().toISOString(),
|
|
260
481
|
kind: "generate",
|
|
@@ -273,10 +494,16 @@ export function createCouncilLLM(bash, mode, sessionId, stats) {
|
|
|
273
494
|
finishReason: result.finishReason,
|
|
274
495
|
usage: result.usage,
|
|
275
496
|
});
|
|
276
|
-
return result.text;
|
|
497
|
+
return stripThinkBlocks(result.text);
|
|
277
498
|
}
|
|
278
499
|
catch (err) {
|
|
279
500
|
cleanupTimeout();
|
|
501
|
+
// Capture the provider-side detail (status code + response body +
|
|
502
|
+
// request param shape) that `err.message` alone drops — a generic
|
|
503
|
+
// "Bad Request" on the council path was previously undiagnosable
|
|
504
|
+
// because collectStreamText re-throws only the message. PII-safe,
|
|
505
|
+
// no-op unless MUONROI_DEBUG_LLM_WIRE=1. (No-Silent-Catch.)
|
|
506
|
+
wireDebug.logError(providerId, err);
|
|
280
507
|
writeDebugRecord({
|
|
281
508
|
ts: new Date().toISOString(),
|
|
282
509
|
kind: "generate",
|
|
@@ -300,11 +527,11 @@ export function createCouncilLLM(bash, mode, sessionId, stats) {
|
|
|
300
527
|
if (mock) {
|
|
301
528
|
stats.calls++;
|
|
302
529
|
const result = await mock.complete({ prompt });
|
|
303
|
-
return { text: result.text, toolCalls: [] };
|
|
530
|
+
return { text: stripThinkBlocks(result.text), toolCalls: [] };
|
|
304
531
|
}
|
|
305
532
|
const providerId = detectProviderForModel(modelId);
|
|
306
|
-
|
|
307
|
-
const runtime = resolveModelRuntime(
|
|
533
|
+
await ensureCouncilFactory(providerId);
|
|
534
|
+
const runtime = resolveModelRuntime(modelId);
|
|
308
535
|
// Verification tools — re-introduced after the no-tools fix (session
|
|
309
536
|
// a7a5690d2049). The original failure was stepCountIs(4) + full toolset
|
|
310
537
|
// letting reasoning models exhaust steps on exploratory tool chains and
|
|
@@ -335,13 +562,16 @@ export function createCouncilLLM(bash, mode, sessionId, stats) {
|
|
|
335
562
|
}
|
|
336
563
|
}
|
|
337
564
|
}
|
|
338
|
-
catch {
|
|
339
|
-
|
|
565
|
+
catch (err) {
|
|
566
|
+
// MCP is optional here — debate continues with builtins only — but a
|
|
567
|
+
// silent swallow hid which server failed and why. (No-Silent-Catch.)
|
|
568
|
+
console.error(`[council/llm] debate MCP tool discovery failed, continuing with builtins only: ${err instanceof Error ? err.message : String(err)}`, { modelId, provider: providerId });
|
|
340
569
|
}
|
|
341
570
|
verificationTools = wrapToolsWithEeCheck(filtered, sessionId ?? "council-debate");
|
|
342
571
|
}
|
|
343
|
-
catch {
|
|
344
|
-
|
|
572
|
+
catch (err) {
|
|
573
|
+
// fail-open: the debate turn still runs, just without verification tools.
|
|
574
|
+
console.error(`[council/llm] debate verification toolset build failed, running without tools: ${err instanceof Error ? err.message : String(err)}`, { modelId, provider: providerId });
|
|
345
575
|
}
|
|
346
576
|
}
|
|
347
577
|
// sanitizeHistory is identity for every provider (kept as a hook for
|
|
@@ -351,10 +581,30 @@ export function createCouncilLLM(bash, mode, sessionId, stats) {
|
|
|
351
581
|
const t0 = Date.now();
|
|
352
582
|
const { signal: timedSignal, cleanup: cleanupTimeout } = withTimeoutSignal(signal, COUNCIL_LLM_TIMEOUT_MS);
|
|
353
583
|
try {
|
|
354
|
-
const result = await withDeadlineRace(() => withVisibleRetry(() =>
|
|
584
|
+
const result = await withDeadlineRace(() => withVisibleRetry(() =>
|
|
585
|
+
// Stream + collect (NOT generateText). A debater on the codex/oauth
|
|
586
|
+
// endpoint hits the same non-stream 400 ("Stream must be set to
|
|
587
|
+
// true") that nulled the eval path; streaming is uniform across
|
|
588
|
+
// providers. Tools (when the tier + circuit breaker allow) ride
|
|
589
|
+
// through with stepCountIs(2) + the same sanitizeHistory prepareStep.
|
|
590
|
+
collectStreamText({
|
|
355
591
|
model: runtime.model,
|
|
356
592
|
system,
|
|
357
593
|
prompt,
|
|
594
|
+
// Reasoning models (deepseek-v4-*, anthropic thinking) consume part
|
|
595
|
+
// of this budget on reasoning_tokens before producing user-visible
|
|
596
|
+
// text. E2E showed 2048 caused finishReason=length on 3KB debate
|
|
597
|
+
// prompts. 6144 leaves ~4000 tokens for text after typical reasoning
|
|
598
|
+
// overhead and avoids cuts mid-thought.
|
|
599
|
+
...maxOutSpread(runtime, 6144),
|
|
600
|
+
// See generate(): capability-aware temperature (omit / clamp).
|
|
601
|
+
temperature: resolveTemperature(providerId, runtime.modelInfo, 0.7),
|
|
602
|
+
providerOptions: runtime.providerOptions,
|
|
603
|
+
abortSignal: timedSignal,
|
|
604
|
+
// Push liveness for the round wrapper: a debate turn on a
|
|
605
|
+
// reasoning model runs near the 5-min ceiling, and the tick
|
|
606
|
+
// generator is not being pumped while Promise.all awaits.
|
|
607
|
+
onDelta: noteCouncilStreamDelta,
|
|
358
608
|
...(verificationTools && Object.keys(verificationTools).length > 0
|
|
359
609
|
? {
|
|
360
610
|
tools: verificationTools,
|
|
@@ -367,20 +617,6 @@ export function createCouncilLLM(bash, mode, sessionId, stats) {
|
|
|
367
617
|
},
|
|
368
618
|
}
|
|
369
619
|
: {}),
|
|
370
|
-
// Reasoning models (deepseek-v4-*, anthropic thinking) consume part
|
|
371
|
-
// of this budget on reasoning_tokens before producing user-visible
|
|
372
|
-
// text. E2E showed 2048 caused finishReason=length on 3KB debate
|
|
373
|
-
// prompts. 6144 leaves ~4000 tokens for text after typical reasoning
|
|
374
|
-
// overhead and avoids cuts mid-thought.
|
|
375
|
-
maxOutputTokens: 6144,
|
|
376
|
-
temperature: 0.7,
|
|
377
|
-
// Visible retry (src/utils/visible-retry.ts) replaces SDK's silent
|
|
378
|
-
// exponential backoff (2,4,8,16,32s). When SiliconFlow rate-limits
|
|
379
|
-
// with 429, user now sees "[retry] rate-limited (429) — waiting Xs
|
|
380
|
-
// before attempt N/6" instead of a 62s blank window that looks hung.
|
|
381
|
-
maxRetries: 0,
|
|
382
|
-
...(runtime.providerOptions ? { providerOptions: runtime.providerOptions } : {}),
|
|
383
|
-
abortSignal: timedSignal,
|
|
384
620
|
}), { label: "council.debate" }), COUNCIL_LLM_TIMEOUT_MS + 5_000, "council.debate", signal);
|
|
385
621
|
cleanupTimeout();
|
|
386
622
|
stats.calls++;
|
|
@@ -402,6 +638,7 @@ export function createCouncilLLM(bash, mode, sessionId, stats) {
|
|
|
402
638
|
stepCount: toolCalls.length,
|
|
403
639
|
});
|
|
404
640
|
onUsage?.(debateUsage);
|
|
641
|
+
recordCouncilUsage(sessionId, modelId, debateUsage);
|
|
405
642
|
writeDebugRecord({
|
|
406
643
|
ts: new Date().toISOString(),
|
|
407
644
|
kind: "debate",
|
|
@@ -423,7 +660,7 @@ export function createCouncilLLM(bash, mode, sessionId, stats) {
|
|
|
423
660
|
usage: result.usage,
|
|
424
661
|
});
|
|
425
662
|
return {
|
|
426
|
-
text: result.text,
|
|
663
|
+
text: stripThinkBlocks(result.text),
|
|
427
664
|
toolCalls: toolCalls,
|
|
428
665
|
};
|
|
429
666
|
}
|
|
@@ -456,11 +693,11 @@ export function createCouncilLLM(bash, mode, sessionId, stats) {
|
|
|
456
693
|
if (mock) {
|
|
457
694
|
stats.calls++;
|
|
458
695
|
const result = await mock.complete({ prompt: topic });
|
|
459
|
-
return result.text;
|
|
696
|
+
return stripThinkBlocks(result.text);
|
|
460
697
|
}
|
|
461
698
|
const providerId = detectProviderForModel(modelId);
|
|
462
|
-
|
|
463
|
-
const runtime = resolveModelRuntime(
|
|
699
|
+
await ensureCouncilFactory(providerId);
|
|
700
|
+
const runtime = resolveModelRuntime(modelId);
|
|
464
701
|
const builtinTools = createTools(bash, mode);
|
|
465
702
|
// CQ-03: Lazy MCP bundle per research call — fail-open so builtins remain available
|
|
466
703
|
let mcpBundle = null;
|
|
@@ -476,12 +713,21 @@ export function createCouncilLLM(bash, mode, sessionId, stats) {
|
|
|
476
713
|
const hasUrl = /https?:\/\/\S+/.test(topic);
|
|
477
714
|
const internetFirst = options?.internetFirst === true;
|
|
478
715
|
const systemPrompt = buildResearchSystemPrompt(hasUrl, internetFirst);
|
|
479
|
-
// Warn early if internet-first mode is requested but no
|
|
480
|
-
|
|
716
|
+
// Warn early if internet-first mode is requested but no *working* web
|
|
717
|
+
// research capability exists. The builtin `web_search`/`fetch_url` tools
|
|
718
|
+
// are ALWAYS registered, so the old tool-NAME check was always true — even
|
|
719
|
+
// when `web_search` will just return `ERROR no_tavily_key`, so the warning
|
|
720
|
+
// never fired and internet-first research failed silently. Gate on real
|
|
721
|
+
// capability: a Tavily key, or an MCP search/browser tool actually loaded
|
|
722
|
+
// (builtins alone don't count — open-ended search needs the key).
|
|
723
|
+
const hasTavilyKey = ((await getMcpKey("tavily")) || process.env.TAVILY_API_KEY || "").trim().length >= 10;
|
|
724
|
+
const mcpSearchTool = Object.keys(mcpBundle?.tools ?? {}).some((n) => /tavily|web[_-]?search|web[_-]?fetch|playwright|chrome|context7|firecrawl|exa|browser/i.test(n));
|
|
725
|
+
const internetToolAvailable = hasTavilyKey || mcpSearchTool;
|
|
481
726
|
const internetGapWarning = internetFirst && !internetToolAvailable
|
|
482
|
-
? `\n\n## Research Gap\n- Internet-first mode requested but no
|
|
483
|
-
`(
|
|
484
|
-
|
|
727
|
+
? `\n\n## Research Gap\n- Internet-first mode requested but no working web-search capability ` +
|
|
728
|
+
`(a Tavily API key or an MCP search/browser tool) is available. ` +
|
|
729
|
+
`\`fetch_url\` still works for explicit URLs, but open-ended search is unavailable — ` +
|
|
730
|
+
`findings will be limited to what the model already knows.`
|
|
485
731
|
: "";
|
|
486
732
|
const userPrompt = conversationContext
|
|
487
733
|
? `## Context\n${conversationContext}\n\n---\n\n## Research Topic\n${topic}\n\nInvestigate and report findings.`
|
|
@@ -507,8 +753,12 @@ export function createCouncilLLM(bash, mode, sessionId, stats) {
|
|
|
507
753
|
const stripped = researchCaps.sanitizeHistory(messages);
|
|
508
754
|
return stripped === messages ? {} : { messages: stripped };
|
|
509
755
|
},
|
|
510
|
-
|
|
511
|
-
|
|
756
|
+
...maxOutSpread(runtime, 4096),
|
|
757
|
+
// See generate(): capability-aware temperature (omit / clamp).
|
|
758
|
+
...(() => {
|
|
759
|
+
const t = resolveTemperature(providerId, runtime.modelInfo, 0.3);
|
|
760
|
+
return t === undefined ? {} : { temperature: t };
|
|
761
|
+
})(),
|
|
512
762
|
// Visible retry (src/utils/visible-retry.ts) replaces SDK's silent
|
|
513
763
|
// exponential backoff (2,4,8,16,32s). When SiliconFlow rate-limits
|
|
514
764
|
// with 429, user now sees "[retry] rate-limited (429) — waiting Xs
|
|
@@ -530,6 +780,7 @@ export function createCouncilLLM(bash, mode, sessionId, stats) {
|
|
|
530
780
|
stepCount: (result.toolCalls ?? []).length,
|
|
531
781
|
});
|
|
532
782
|
onUsage?.(researchUsage);
|
|
783
|
+
recordCouncilUsage(sessionId, modelId, researchUsage);
|
|
533
784
|
writeDebugRecord({
|
|
534
785
|
ts: new Date().toISOString(),
|
|
535
786
|
kind: "research",
|
|
@@ -558,7 +809,7 @@ export function createCouncilLLM(bash, mode, sessionId, stats) {
|
|
|
558
809
|
// CQ-04: When URL present, verify at least one browser tool was invoked
|
|
559
810
|
if (hasUrl) {
|
|
560
811
|
// Use result.toolCalls (flat array across all steps) — more reliably typed than steps[].toolCalls
|
|
561
|
-
const browserUsed = researchToolCalls.some((tc) => tc.toolName.includes("playwright") || tc.toolName.includes("chrome"));
|
|
812
|
+
const browserUsed = researchToolCalls.some((tc) => tc.toolName.includes("playwright") || tc.toolName.includes("chrome") || tc.toolName === "fetch_url");
|
|
562
813
|
if (!browserUsed) {
|
|
563
814
|
stats.calls++;
|
|
564
815
|
return (result.text +
|
|
@@ -568,7 +819,7 @@ export function createCouncilLLM(bash, mode, sessionId, stats) {
|
|
|
568
819
|
}
|
|
569
820
|
}
|
|
570
821
|
stats.calls++;
|
|
571
|
-
return result.text + internetGapWarning;
|
|
822
|
+
return stripThinkBlocks(result.text) + internetGapWarning;
|
|
572
823
|
}
|
|
573
824
|
catch (err) {
|
|
574
825
|
cleanupTimeout();
|
|
@@ -691,6 +942,33 @@ export async function* tracedGenerate(llm, args) {
|
|
|
691
942
|
};
|
|
692
943
|
return resultText;
|
|
693
944
|
}
|
|
945
|
+
/**
|
|
946
|
+
* Run {@link tracedGenerate} across a list of models, returning the first
|
|
947
|
+
* non-empty completion. A model that throws (e.g. a flaky proxy returning
|
|
948
|
+
* "Upstream request failed") or yields only whitespace advances to the next
|
|
949
|
+
* candidate; fallback attempts are labelled so the timeline shows the retry.
|
|
950
|
+
* Returns null when every candidate fails — the caller decides the degraded
|
|
951
|
+
* fallback (e.g. a single-criterion spec). Dedupes the model list in order.
|
|
952
|
+
*/
|
|
953
|
+
export async function* tracedGenerateWithFallback(llm, args) {
|
|
954
|
+
const seen = new Set();
|
|
955
|
+
const models = args.models.filter((m) => m && !seen.has(m) && (seen.add(m), true));
|
|
956
|
+
for (let i = 0; i < models.length; i++) {
|
|
957
|
+
try {
|
|
958
|
+
const raw = yield* tracedGenerate(llm, {
|
|
959
|
+
...args,
|
|
960
|
+
modelId: models[i],
|
|
961
|
+
label: i > 0 ? `${args.label} (fallback: ${models[i]})` : args.label,
|
|
962
|
+
});
|
|
963
|
+
if (raw?.trim())
|
|
964
|
+
return raw;
|
|
965
|
+
}
|
|
966
|
+
catch {
|
|
967
|
+
/* try the next candidate */
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
return null;
|
|
971
|
+
}
|
|
694
972
|
/**
|
|
695
973
|
* Generic version of {@link tracedGenerate} for arbitrary async work
|
|
696
974
|
* (e.g. `llm.research`, `Promise.all` over multiple model calls).
|
|
@@ -701,6 +979,19 @@ export async function* tracedAsync(fn, args) {
|
|
|
701
979
|
: `status-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
|
|
702
980
|
const start = Date.now();
|
|
703
981
|
const tickInterval = args.tickIntervalMs ?? 1000;
|
|
982
|
+
/** Never let a liveness read break the heartbeat it is meant to enrich. */
|
|
983
|
+
const livenessFields = () => {
|
|
984
|
+
if (!args.liveness)
|
|
985
|
+
return {};
|
|
986
|
+
try {
|
|
987
|
+
const l = args.liveness();
|
|
988
|
+
return { streamedChars: l.streamedChars, lastDeltaAgeMs: l.lastDeltaAgeMs };
|
|
989
|
+
}
|
|
990
|
+
catch (err) {
|
|
991
|
+
console.error(`[council/llm] tracedAsync liveness read failed: ${err instanceof Error ? err.message : String(err)}`, { phase: args.phase, label: args.label });
|
|
992
|
+
return {};
|
|
993
|
+
}
|
|
994
|
+
};
|
|
704
995
|
yield {
|
|
705
996
|
type: "council_status",
|
|
706
997
|
councilStatus: {
|
|
@@ -746,6 +1037,7 @@ export async function* tracedAsync(fn, args) {
|
|
|
746
1037
|
detail: args.detail,
|
|
747
1038
|
role: args.role,
|
|
748
1039
|
elapsedMs: Date.now() - start,
|
|
1040
|
+
...livenessFields(),
|
|
749
1041
|
},
|
|
750
1042
|
};
|
|
751
1043
|
}
|
|
@@ -777,6 +1069,7 @@ export async function* tracedAsync(fn, args) {
|
|
|
777
1069
|
detail: args.detail,
|
|
778
1070
|
role: args.role,
|
|
779
1071
|
elapsedMs: Date.now() - start,
|
|
1072
|
+
...livenessFields(),
|
|
780
1073
|
},
|
|
781
1074
|
};
|
|
782
1075
|
return result;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/council/panel-select.ts
|
|
3
|
+
*
|
|
4
|
+
* U3 — task-aware debate panel selection. Instead of a fixed capability roster
|
|
5
|
+
* (resolveParticipants picks by tier, blind to the prompt), the leader reads the
|
|
6
|
+
* task and CHOOSES which reachable models should debate it. Fail-open: any parse
|
|
7
|
+
* / provider failure returns null and the caller keeps the default roster. The
|
|
8
|
+
* internal implement/verify/research routing slots are assigned here purely for
|
|
9
|
+
* downstream compatibility — they are never surfaced to the user (the UI shows
|
|
10
|
+
* the task-adaptive persona / model, per U1.1).
|
|
11
|
+
*/
|
|
12
|
+
import type { StreamChunk } from "../types/index.js";
|
|
13
|
+
import type { ModelRole } from "../utils/settings.js";
|
|
14
|
+
import type { CouncilCandidate } from "./leader.js";
|
|
15
|
+
import type { CouncilLLM } from "./types.js";
|
|
16
|
+
/**
|
|
17
|
+
* Ask the leader to select a task-appropriate debate panel from `pool`.
|
|
18
|
+
* Returns a roster (models mapped onto internal routing roles) or null when the
|
|
19
|
+
* leader is unavailable / returns an unusable selection — the caller then keeps
|
|
20
|
+
* its default roster.
|
|
21
|
+
*/
|
|
22
|
+
export declare function selectTaskAwarePanel(opts: {
|
|
23
|
+
topic: string;
|
|
24
|
+
pool: CouncilCandidate[];
|
|
25
|
+
leaderModelId: string;
|
|
26
|
+
llm: CouncilLLM;
|
|
27
|
+
}): AsyncGenerator<StreamChunk, Array<{
|
|
28
|
+
role: ModelRole;
|
|
29
|
+
model: string;
|
|
30
|
+
}> | null, unknown>;
|