@caupulican/pi-adaptative 0.80.103 → 0.81.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +120 -0
- package/dist/cli/session-picker.d.ts +1 -1
- package/dist/cli/session-picker.d.ts.map +1 -1
- package/dist/cli/session-picker.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +7 -1
- package/dist/cli.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts +1 -1
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +6 -6
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +1 -1
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +152 -512
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +635 -4590
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/autonomy/session-lane-record.d.ts +1 -1
- package/dist/core/autonomy/session-lane-record.d.ts.map +1 -1
- package/dist/core/autonomy/session-lane-record.js.map +1 -1
- package/dist/core/autonomy/status.d.ts +1 -0
- package/dist/core/autonomy/status.d.ts.map +1 -1
- package/dist/core/autonomy/status.js +1 -0
- package/dist/core/autonomy/status.js.map +1 -1
- package/dist/core/autonomy-telemetry.d.ts +80 -0
- package/dist/core/autonomy-telemetry.d.ts.map +1 -0
- package/dist/core/autonomy-telemetry.js +266 -0
- package/dist/core/autonomy-telemetry.js.map +1 -0
- package/dist/core/background-lane-controller.d.ts +186 -0
- package/dist/core/background-lane-controller.d.ts.map +1 -0
- package/dist/core/background-lane-controller.js +691 -0
- package/dist/core/background-lane-controller.js.map +1 -0
- package/dist/core/bash-execution-controller.d.ts +51 -0
- package/dist/core/bash-execution-controller.d.ts.map +1 -0
- package/dist/core/bash-execution-controller.js +96 -0
- package/dist/core/bash-execution-controller.js.map +1 -0
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +9 -2
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/compaction-support.d.ts +56 -0
- package/dist/core/compaction-support.d.ts.map +1 -0
- package/dist/core/compaction-support.js +99 -0
- package/dist/core/compaction-support.js.map +1 -0
- package/dist/core/context/artifact-retrieval.d.ts +1 -1
- package/dist/core/context/artifact-retrieval.d.ts.map +1 -1
- package/dist/core/context/artifact-retrieval.js +1 -1
- package/dist/core/context/artifact-retrieval.js.map +1 -1
- package/dist/core/context/context-composition.d.ts.map +1 -1
- package/dist/core/context/context-composition.js +1 -1
- package/dist/core/context/context-composition.js.map +1 -1
- package/dist/core/context/tool-output-packer.d.ts +1 -1
- package/dist/core/context/tool-output-packer.d.ts.map +1 -1
- package/dist/core/context/tool-output-packer.js +1 -1
- package/dist/core/context/tool-output-packer.js.map +1 -1
- package/dist/core/context-gc.d.ts.map +1 -1
- package/dist/core/context-gc.js +1 -1
- package/dist/core/context-gc.js.map +1 -1
- package/dist/core/context-pipeline.d.ts +223 -0
- package/dist/core/context-pipeline.d.ts.map +1 -0
- package/dist/core/context-pipeline.js +594 -0
- package/dist/core/context-pipeline.js.map +1 -0
- package/dist/core/cost/daily-usage.d.ts +1 -1
- package/dist/core/cost/daily-usage.d.ts.map +1 -1
- package/dist/core/cost/daily-usage.js +1 -1
- package/dist/core/cost/daily-usage.js.map +1 -1
- package/dist/core/cost/session-usage.d.ts +1 -1
- package/dist/core/cost/session-usage.d.ts.map +1 -1
- package/dist/core/cost/session-usage.js +1 -1
- package/dist/core/cost/session-usage.js.map +1 -1
- package/dist/core/delegation/session-worker-result.d.ts +1 -1
- package/dist/core/delegation/session-worker-result.d.ts.map +1 -1
- package/dist/core/delegation/session-worker-result.js.map +1 -1
- package/dist/core/exec.d.ts +2 -0
- package/dist/core/exec.d.ts.map +1 -1
- package/dist/core/exec.js +15 -9
- package/dist/core/exec.js.map +1 -1
- package/dist/core/export-html/index.d.ts +1 -1
- package/dist/core/export-html/index.d.ts.map +1 -1
- package/dist/core/export-html/index.js +2 -2
- package/dist/core/export-html/index.js.map +1 -1
- package/dist/core/extensions/builtin.d.ts.map +1 -1
- package/dist/core/extensions/builtin.js +2 -2
- package/dist/core/extensions/builtin.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +1 -1
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +2 -4
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/goal-loop-controller.d.ts +24 -0
- package/dist/core/goal-loop-controller.d.ts.map +1 -0
- package/dist/core/goal-loop-controller.js +83 -0
- package/dist/core/goal-loop-controller.js.map +1 -0
- package/dist/core/goals/goal-runtime-snapshot.d.ts +1 -1
- package/dist/core/goals/goal-runtime-snapshot.d.ts.map +1 -1
- package/dist/core/goals/goal-runtime-snapshot.js.map +1 -1
- package/dist/core/goals/session-goal-state.d.ts +1 -1
- package/dist/core/goals/session-goal-state.d.ts.map +1 -1
- package/dist/core/goals/session-goal-state.js.map +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/learning/learning-audit.d.ts +1 -1
- package/dist/core/learning/learning-audit.d.ts.map +1 -1
- package/dist/core/learning/learning-audit.js.map +1 -1
- package/dist/core/learning/session-learning-decision.d.ts +1 -1
- package/dist/core/learning/session-learning-decision.d.ts.map +1 -1
- package/dist/core/learning/session-learning-decision.js.map +1 -1
- package/dist/core/local-runtime-controller.d.ts +99 -0
- package/dist/core/local-runtime-controller.d.ts.map +1 -0
- package/dist/core/local-runtime-controller.js +214 -0
- package/dist/core/local-runtime-controller.js.map +1 -0
- package/dist/core/memory/providers/transcript-recall.d.ts.map +1 -1
- package/dist/core/memory/providers/transcript-recall.js +1 -1
- package/dist/core/memory/providers/transcript-recall.js.map +1 -1
- package/dist/core/memory-controller.d.ts +139 -0
- package/dist/core/memory-controller.d.ts.map +1 -0
- package/dist/core/memory-controller.js +323 -0
- package/dist/core/memory-controller.js.map +1 -0
- package/dist/core/model-router/status.d.ts +1 -1
- package/dist/core/model-router/status.d.ts.map +1 -1
- package/dist/core/model-router/status.js.map +1 -1
- package/dist/core/model-router-controller.d.ts +140 -0
- package/dist/core/model-router-controller.d.ts.map +1 -0
- package/dist/core/model-router-controller.js +623 -0
- package/dist/core/model-router-controller.js.map +1 -0
- package/dist/core/model-selection-controller.d.ts +95 -0
- package/dist/core/model-selection-controller.d.ts.map +1 -0
- package/dist/core/model-selection-controller.js +252 -0
- package/dist/core/model-selection-controller.js.map +1 -0
- package/dist/core/models/model-ref.d.ts +13 -0
- package/dist/core/models/model-ref.d.ts.map +1 -1
- package/dist/core/models/model-ref.js +22 -0
- package/dist/core/models/model-ref.js.map +1 -1
- package/dist/core/profile-filter-controller.d.ts +77 -0
- package/dist/core/profile-filter-controller.d.ts.map +1 -0
- package/dist/core/profile-filter-controller.js +159 -0
- package/dist/core/profile-filter-controller.js.map +1 -0
- package/dist/core/reflection-controller.d.ts +111 -0
- package/dist/core/reflection-controller.d.ts.map +1 -0
- package/dist/core/reflection-controller.js +412 -0
- package/dist/core/reflection-controller.js.map +1 -0
- package/dist/core/research/model-fitness.d.ts +12 -0
- package/dist/core/research/model-fitness.d.ts.map +1 -1
- package/dist/core/research/model-fitness.js +21 -0
- package/dist/core/research/model-fitness.js.map +1 -1
- package/dist/core/research/session-evidence-bundle.d.ts +1 -1
- package/dist/core/research/session-evidence-bundle.d.ts.map +1 -1
- package/dist/core/research/session-evidence-bundle.js.map +1 -1
- package/dist/core/runtime-builder.d.ts +222 -0
- package/dist/core/runtime-builder.d.ts.map +1 -0
- package/dist/core/runtime-builder.js +640 -0
- package/dist/core/runtime-builder.js.map +1 -0
- package/dist/core/sdk.d.ts +2 -2
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +3 -4
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-analytics.d.ts +96 -0
- package/dist/core/session-analytics.d.ts.map +1 -0
- package/dist/core/session-analytics.js +331 -0
- package/dist/core/session-analytics.js.map +1 -0
- package/dist/core/session-manager-factory.d.ts +18 -0
- package/dist/core/session-manager-factory.d.ts.map +1 -0
- package/dist/core/session-manager-factory.js +32 -0
- package/dist/core/session-manager-factory.js.map +1 -0
- package/dist/core/session-tree-navigator.d.ts +68 -0
- package/dist/core/session-tree-navigator.d.ts.map +1 -0
- package/dist/core/session-tree-navigator.js +217 -0
- package/dist/core/session-tree-navigator.js.map +1 -0
- package/dist/core/system-prompt-builder.d.ts +63 -0
- package/dist/core/system-prompt-builder.d.ts.map +1 -0
- package/dist/core/system-prompt-builder.js +181 -0
- package/dist/core/system-prompt-builder.js.map +1 -0
- package/dist/core/tool-gate-controller.d.ts +36 -0
- package/dist/core/tool-gate-controller.d.ts.map +1 -0
- package/dist/core/tool-gate-controller.js +94 -0
- package/dist/core/tool-gate-controller.js.map +1 -0
- package/dist/core/tools/artifact-retrieve.d.ts.map +1 -1
- package/dist/core/tools/artifact-retrieve.js +1 -1
- package/dist/core/tools/artifact-retrieve.js.map +1 -1
- package/dist/core/tools/bash.d.ts +4 -2
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +49 -7
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/file-mutation-queue.d.ts +6 -0
- package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
- package/dist/core/tools/file-mutation-queue.js +61 -1
- package/dist/core/tools/file-mutation-queue.js.map +1 -1
- package/dist/core/tools/find.d.ts +1 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +1 -1
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +1 -1
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/index.d.ts +1 -1
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +1 -1
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/ls.d.ts +1 -1
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js +1 -1
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/output-accumulator.d.ts +1 -1
- package/dist/core/tools/output-accumulator.d.ts.map +1 -1
- package/dist/core/tools/output-accumulator.js +1 -1
- package/dist/core/tools/output-accumulator.js.map +1 -1
- package/dist/core/tools/read.d.ts +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +1 -1
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/render-utils.d.ts.map +1 -1
- package/dist/core/tools/render-utils.js +1 -1
- package/dist/core/tools/render-utils.js.map +1 -1
- package/dist/index.d.ts +2 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -4
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +13 -12
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/auth-dialogs-controller.d.ts +59 -0
- package/dist/modes/interactive/auth-dialogs-controller.d.ts.map +1 -0
- package/dist/modes/interactive/auth-dialogs-controller.js +398 -0
- package/dist/modes/interactive/auth-dialogs-controller.js.map +1 -0
- package/dist/modes/interactive/auto-learn-controller.d.ts +168 -0
- package/dist/modes/interactive/auto-learn-controller.d.ts.map +1 -0
- package/dist/modes/interactive/auto-learn-controller.js +1239 -0
- package/dist/modes/interactive/auto-learn-controller.js.map +1 -0
- package/dist/modes/interactive/autocomplete-provider.d.ts +26 -0
- package/dist/modes/interactive/autocomplete-provider.d.ts.map +1 -0
- package/dist/modes/interactive/autocomplete-provider.js +103 -0
- package/dist/modes/interactive/autocomplete-provider.js.map +1 -0
- package/dist/modes/interactive/autonomy-commands.d.ts +38 -0
- package/dist/modes/interactive/autonomy-commands.d.ts.map +1 -0
- package/dist/modes/interactive/autonomy-commands.js +142 -0
- package/dist/modes/interactive/autonomy-commands.js.map +1 -0
- package/dist/modes/interactive/clipboard-input.d.ts +37 -0
- package/dist/modes/interactive/clipboard-input.d.ts.map +1 -0
- package/dist/modes/interactive/clipboard-input.js +59 -0
- package/dist/modes/interactive/clipboard-input.js.map +1 -0
- package/dist/modes/interactive/compaction-queue.d.ts +30 -0
- package/dist/modes/interactive/compaction-queue.d.ts.map +1 -0
- package/dist/modes/interactive/compaction-queue.js +91 -0
- package/dist/modes/interactive/compaction-queue.js.map +1 -0
- package/dist/modes/interactive/components/bash-execution.d.ts +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +1 -1
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts +1 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/custom-message.d.ts +1 -1
- package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-message.js.map +1 -1
- package/dist/modes/interactive/components/session-selector-search.d.ts +1 -1
- package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +2 -2
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector.d.ts +1 -1
- package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector.js.map +1 -1
- package/dist/modes/interactive/config-backup.d.ts +27 -0
- package/dist/modes/interactive/config-backup.d.ts.map +1 -0
- package/dist/modes/interactive/config-backup.js +146 -0
- package/dist/modes/interactive/config-backup.js.map +1 -0
- package/dist/modes/interactive/editor-overlay-host.d.ts +48 -0
- package/dist/modes/interactive/editor-overlay-host.d.ts.map +1 -0
- package/dist/modes/interactive/editor-overlay-host.js +43 -0
- package/dist/modes/interactive/editor-overlay-host.js.map +1 -0
- package/dist/modes/interactive/extension-ui-host.d.ts +165 -0
- package/dist/modes/interactive/extension-ui-host.d.ts.map +1 -0
- package/dist/modes/interactive/extension-ui-host.js +610 -0
- package/dist/modes/interactive/extension-ui-host.js.map +1 -0
- package/dist/modes/interactive/external-editor.d.ts +18 -0
- package/dist/modes/interactive/external-editor.d.ts.map +1 -0
- package/dist/modes/interactive/external-editor.js +107 -0
- package/dist/modes/interactive/external-editor.js.map +1 -0
- package/dist/modes/interactive/history-reload-math.d.ts +24 -0
- package/dist/modes/interactive/history-reload-math.d.ts.map +1 -0
- package/dist/modes/interactive/history-reload-math.js +129 -0
- package/dist/modes/interactive/history-reload-math.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts +22 -238
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +714 -5910
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/key-handlers.d.ts +46 -0
- package/dist/modes/interactive/key-handlers.d.ts.map +1 -0
- package/dist/modes/interactive/key-handlers.js +80 -0
- package/dist/modes/interactive/key-handlers.js.map +1 -0
- package/dist/modes/interactive/local-model-commands.d.ts +68 -0
- package/dist/modes/interactive/local-model-commands.d.ts.map +1 -0
- package/dist/modes/interactive/local-model-commands.js +288 -0
- package/dist/modes/interactive/local-model-commands.js.map +1 -0
- package/dist/modes/interactive/profile-menu-controller.d.ts +77 -0
- package/dist/modes/interactive/profile-menu-controller.d.ts.map +1 -0
- package/dist/modes/interactive/profile-menu-controller.js +917 -0
- package/dist/modes/interactive/profile-menu-controller.js.map +1 -0
- package/dist/modes/interactive/report-commands.d.ts +46 -0
- package/dist/modes/interactive/report-commands.d.ts.map +1 -0
- package/dist/modes/interactive/report-commands.js +255 -0
- package/dist/modes/interactive/report-commands.js.map +1 -0
- package/dist/modes/interactive/resource-display.d.ts +73 -0
- package/dist/modes/interactive/resource-display.d.ts.map +1 -0
- package/dist/modes/interactive/resource-display.js +278 -0
- package/dist/modes/interactive/resource-display.js.map +1 -0
- package/dist/modes/interactive/resource-shell-commands.d.ts +64 -0
- package/dist/modes/interactive/resource-shell-commands.d.ts.map +1 -0
- package/dist/modes/interactive/resource-shell-commands.js +202 -0
- package/dist/modes/interactive/resource-shell-commands.js.map +1 -0
- package/dist/modes/interactive/session-flow-commands.d.ts +139 -0
- package/dist/modes/interactive/session-flow-commands.d.ts.map +1 -0
- package/dist/modes/interactive/session-flow-commands.js +458 -0
- package/dist/modes/interactive/session-flow-commands.js.map +1 -0
- package/dist/modes/interactive/session-io-commands.d.ts +73 -0
- package/dist/modes/interactive/session-io-commands.d.ts.map +1 -0
- package/dist/modes/interactive/session-io-commands.js +202 -0
- package/dist/modes/interactive/session-io-commands.js.map +1 -0
- package/dist/modes/interactive/settings-selector-flow.d.ts +42 -0
- package/dist/modes/interactive/settings-selector-flow.d.ts.map +1 -0
- package/dist/modes/interactive/settings-selector-flow.js +287 -0
- package/dist/modes/interactive/settings-selector-flow.js.map +1 -0
- package/dist/modes/interactive/signal-lifecycle.d.ts +55 -0
- package/dist/modes/interactive/signal-lifecycle.d.ts.map +1 -0
- package/dist/modes/interactive/signal-lifecycle.js +177 -0
- package/dist/modes/interactive/signal-lifecycle.js.map +1 -0
- package/dist/modes/interactive/startup-checks.d.ts +38 -0
- package/dist/modes/interactive/startup-checks.d.ts.map +1 -0
- package/dist/modes/interactive/startup-checks.js +189 -0
- package/dist/modes/interactive/startup-checks.js.map +1 -0
- package/dist/modes/rpc/rpc-client.d.ts +1 -1
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +1 -1
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/utils/paths.d.ts +2 -14
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +5 -30
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/process-memory.d.ts +8 -0
- package/dist/utils/process-memory.d.ts.map +1 -0
- package/dist/utils/process-memory.js +11 -0
- package/dist/utils/process-memory.js.map +1 -0
- package/dist/utils/shell.d.ts +0 -9
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/shell.js +0 -37
- package/dist/utils/shell.js.map +1 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/sdk/11-sessions.ts +8 -8
- package/examples/sdk/13-session-runtime.ts +1 -1
- package/npm-shrinkwrap.json +12 -12
- package/package.json +4 -4
- package/dist/core/compaction/branch-summarization.d.ts +0 -88
- package/dist/core/compaction/branch-summarization.d.ts.map +0 -1
- package/dist/core/compaction/branch-summarization.js +0 -243
- package/dist/core/compaction/branch-summarization.js.map +0 -1
- package/dist/core/compaction/compaction.d.ts +0 -143
- package/dist/core/compaction/compaction.d.ts.map +0 -1
- package/dist/core/compaction/compaction.js +0 -659
- package/dist/core/compaction/compaction.js.map +0 -1
- package/dist/core/compaction/index.d.ts +0 -7
- package/dist/core/compaction/index.d.ts.map +0 -1
- package/dist/core/compaction/index.js +0 -7
- package/dist/core/compaction/index.js.map +0 -1
- package/dist/core/compaction/utils.d.ts +0 -38
- package/dist/core/compaction/utils.d.ts.map +0 -1
- package/dist/core/compaction/utils.js +0 -153
- package/dist/core/compaction/utils.js.map +0 -1
- package/dist/core/message-retention.d.ts +0 -26
- package/dist/core/message-retention.d.ts.map +0 -1
- package/dist/core/message-retention.js +0 -95
- package/dist/core/message-retention.js.map +0 -1
- package/dist/core/messages.d.ts +0 -77
- package/dist/core/messages.d.ts.map +0 -1
- package/dist/core/messages.js +0 -123
- package/dist/core/messages.js.map +0 -1
- package/dist/core/session-manager.d.ts +0 -337
- package/dist/core/session-manager.d.ts.map +0 -1
- package/dist/core/session-manager.js +0 -1328
- package/dist/core/session-manager.js.map +0 -1
- package/dist/core/tools/truncate.d.ts +0 -70
- package/dist/core/tools/truncate.d.ts.map +0 -1
- package/dist/core/tools/truncate.js +0 -215
- package/dist/core/tools/truncate.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-router-controller.js","sourceRoot":"","sources":["../../src/core/model-router-controller.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Model-router turn routing: the session's per-turn model-selection subsystem — the regex/executor\n * route resolver, the optional bounded routing judge, the executor lane (Level-0 toolkit direct hit\n * + speculative brain-refined retry), the per-tier thinking/tool-surface swap around a routed turn,\n * the cheap-research-turn session buffer with mutating-tool escalation to an expensive retry, and\n * the router status/diagnostics report.\n *\n * Extracted verbatim from agent-session.ts (god-file decomposition). Owns the transient per-turn\n * route state — the active intent/route, the cheap-turn session buffer, the escalation-requested and\n * retry-in-flight flags — and the sticky last-decision/last-skip-reason/last-intent used by the\n * status report. Everything else it needs — the live agent + its state, the current model, the\n * session/settings managers, the model registry, the agent dir, the reflection abort signal, the\n * base system prompt, the isolated-completion primitive, spawned-usage accounting, the event/telemetry\n * emitters, and the recently-extracted BackgroundLaneController (resolveLaneModel) / ContextPipeline\n * (resolveCurationModelIfFit) collaborators — is reached through narrow deps accessors rather than the\n * whole AgentSession.\n *\n * Drive-path boundary (deliberate): the actual agent.prompt()/continue() loop stays host-side in\n * AgentSession._runAgentPrompt; this controller's parallel routed drive path ({@link runRoutedTurn})\n * owns only the route decision/escalation/tier bookkeeping and delegates every agent turn back through\n * {@link ModelRouterControllerDeps.runAgentPrompt}, so the drive-loop logic is never duplicated. The\n * host keeps a one-line delegation at each call-in: the routing prep + routed-turn entry in\n * _promptUnserialized, the beforeToolCall escalation branch ({@link maybeEscalateToolCall}), the\n * message_end cheap-turn buffering ({@link captureSessionMessage}), the retry-event suppression\n * ({@link isRetryInFlight}), and the public getModelRouterStatus / autonomy-telemetry reads.\n */\n\nimport type { Agent, AgentMessage, ThinkingLevel } from \"@caupulican/pi-agent-core\";\nimport type { SessionManager } from \"@caupulican/pi-agent-core/node\";\nimport type { Api, Message, Model, Usage } from \"@caupulican/pi-ai\";\nimport { clampThinkingLevel, modelsAreEqual } from \"@caupulican/pi-ai\";\nimport type { AgentSessionEvent, IsolatedCompletionOptions, IsolatedCompletionResult } from \"./agent-session.ts\";\nimport type { RouteDecision } from \"./autonomy/contracts.ts\";\nimport { AUTONOMY_TELEMETRY_EVENT_TYPES, type AutonomyTelemetryEvent } from \"./autonomy/telemetry-events.ts\";\nimport { latestUserPromptText } from \"./context-pipeline.ts\";\nimport { deriveModelCapabilityProfile, filterToolNamesForCapability } from \"./model-capability.ts\";\nimport type { ModelRegistry } from \"./model-registry.ts\";\nimport { resolveCliModel } from \"./model-resolver.ts\";\nimport { collectModelRouterConfigDiagnostics } from \"./model-router/config-diagnostics.ts\";\nimport { classifyExecutorTurn } from \"./model-router/executor-route.ts\";\nimport { classifyModelRouterRoute, type ModelRouterIntent } from \"./model-router/intent-classifier.ts\";\nimport { ROUTE_JUDGE_MAX_OUTPUT_TOKENS, runRouteJudge } from \"./model-router/route-judge.ts\";\nimport {\n\tbufferModelRouterSessionCustomMessage,\n\tbufferModelRouterSessionMessage,\n\tcreateModelRouterSessionBuffer,\n\tflushModelRouterSessionBuffer,\n\ttype ModelRouterSessionBuffer,\n} from \"./model-router/session-buffer.ts\";\nimport {\n\tformatModelRouterStatus,\n\tgetRecentModelRouterDecisions,\n\tMODEL_ROUTER_DECISION_CUSTOM_TYPE,\n\ttype ModelRouterDecisionStatus,\n} from \"./model-router/status.ts\";\nimport { shouldEscalateModelRouterTool } from \"./model-router/tool-escalation.ts\";\nimport { FitnessStore } from \"./models/fitness-store.ts\";\nimport type { SettingsManager } from \"./settings-manager.ts\";\nimport {\n\tbuildReflexUserPrompt,\n\tparseReflexPlan,\n\tREFLEX_INTERPRETER_SYSTEM_PROMPT,\n} from \"./toolkit/reflex-interpreter.ts\";\n\n/** Canonical `provider/id` label for a routed/resolved model, as it appears in decisions and status. */\nexport function formatModelRouterModel(model: Model<Api>): string {\n\treturn `${model.provider}/${model.id}`;\n}\n\nfunction persistModelRouterDecision(\n\tsessionManager: Pick<SessionManager, \"appendCustomEntry\">,\n\tdecision: ModelRouterDecisionStatus,\n): void {\n\tsessionManager.appendCustomEntry(MODEL_ROUTER_DECISION_CUSTOM_TYPE, decision);\n}\n\nexport interface ModelRouterControllerDeps {\n\t/** Live agent — the controller reads/writes agent.state.{model,thinkingLevel,tools,systemPrompt,messages}\n\t * for the per-turn tier swap and aborts it on a mutating-tool escalation. */\n\tgetAgent(): Agent;\n\t/** Current session model, used to decide whether a routed turn actually swaps the model. */\n\tgetModel(): Model<Api> | undefined;\n\t/** Router/executor/judge/thinking settings + capability mode (all opt-in gates). */\n\tgetSettingsManager(): SettingsManager;\n\t/** Session log: routed-turn message buffering/persistence, decision persistence, recent-decision status. */\n\tgetSessionManager(): SessionManager;\n\t/** Resolves configured route/judge/executor model patterns against configured auth. */\n\tgetModelRegistry(): ModelRegistry;\n\t/** Root dir the host-keyed {@link FitnessStore} lives under (executor tool-call fitness gate). */\n\tgetAgentDir(): string;\n\t/** Aborts the judge's bounded completion when the session is disposed. */\n\tgetReflectionSignal(): AbortSignal;\n\t/** Base (extension-free) system prompt — the tier swap only sheds tools when the turn is on it. */\n\tgetBaseSystemPrompt(): string;\n\t/** The host-side drive loop (agent.prompt()/continue()); the routed drive path delegates every turn here. */\n\trunAgentPrompt(messages: AgentMessage | AgentMessage[]): Promise<void>;\n\t/** Rebuilds the system prompt for a filtered tool surface (routed-model capability shedding). */\n\tbuildSystemPromptForToolNames(toolNames: string[]): string;\n\t/** Re-resolves the restored model against the registry after a routed turn (provider override safety). */\n\trefreshCurrentModelFromRegistry(): void;\n\t/** One-shot, tool-less LLM call — the routing judge and the executor reflex-brain warmup ride this. */\n\trunIsolatedCompletion(opts: IsolatedCompletionOptions): Promise<IsolatedCompletionResult>;\n\t/** Rolls judge/brain spend into spawned-usage accounting. */\n\taddSpawnedUsage(\n\t\tusage: Usage,\n\t\topts?: { label?: string; sourceSessionId?: string; reportId?: string },\n\t): string | undefined;\n\t/** Session event stream (executor-miss warning). */\n\temit(event: AgentSessionEvent): void;\n\t/** Autonomy telemetry stream (one route-decision event per user-facing routed turn). */\n\temitAutonomyTelemetry(event: AutonomyTelemetryEvent): void;\n\t/** Resolves the judge model pattern via {@link BackgroundLaneController}. */\n\tresolveLaneModel(pattern: string): Model<Api> | undefined;\n\t/** Fitness-gated reflex-brain model via {@link ContextPipeline} (executor speculative refinement). */\n\tresolveCurationModelIfFit(): Model<Api> | undefined;\n}\n\n/**\n * Owns the model-router turn routing extracted from {@link AgentSession}. See the module header for the\n * drive-path boundary that keeps the agent.prompt()/continue() loop host-side.\n */\nexport class ModelRouterController {\n\t/** Active model-router intent for the current transient routed turn, if any. */\n\tprivate _activeModelRouterIntent?: ModelRouterIntent;\n\tprivate _activeModelRouterRoute?: RouteDecision;\n\tprivate _modelRouterSessionBuffer?: ModelRouterSessionBuffer;\n\tprivate _modelRouterEscalationRequested = false;\n\tprivate _isModelRouterRetry = false;\n\tprivate _lastModelRouterDecision?: ModelRouterDecisionStatus;\n\tprivate _lastModelRouterSkipReason?: string;\n\tprivate _lastModelRouterIntent?: ModelRouterIntent;\n\n\tprivate readonly deps: ModelRouterControllerDeps;\n\n\tconstructor(deps: ModelRouterControllerDeps) {\n\t\tthis.deps = deps;\n\t}\n\n\t/** True while the escalation retry turn is running, so the host can suppress its duplicate prompt events. */\n\tisRetryInFlight(): boolean {\n\t\treturn this._isModelRouterRetry;\n\t}\n\n\t/** Latest completed route decision (sticky), for the autonomy telemetry snapshot. */\n\tgetLastDecision(): ModelRouterDecisionStatus | undefined {\n\t\treturn this._lastModelRouterDecision;\n\t}\n\n\t/**\n\t * beforeToolCall escalation gate: a cheap research turn that reaches for a mutating tool aborts the\n\t * turn and requests a retry on the expensive model. Returns the block result the host hook forwards,\n\t * or undefined when no escalation is required.\n\t */\n\tmaybeEscalateToolCall(toolName: string, args: unknown): { block: true; reason: string } | undefined {\n\t\tif (\n\t\t\tthis._activeModelRouterRoute &&\n\t\t\tshouldEscalateModelRouterTool({\n\t\t\t\ttier: this._activeModelRouterRoute.tier,\n\t\t\t\ttoolName,\n\t\t\t\targs,\n\t\t\t\treasonCode: this._activeModelRouterRoute.reasonCode,\n\t\t\t})\n\t\t) {\n\t\t\tthis._modelRouterEscalationRequested = true;\n\t\t\tthis.deps.getAgent().abort();\n\t\t\treturn {\n\t\t\t\tblock: true,\n\t\t\t\treason:\n\t\t\t\t\t\"Model router escalation required: a cheap research turn attempted a mutating tool. Retry the turn on the configured expensive model.\",\n\t\t\t};\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * message_end hook: while a cheap routed turn is buffering, capture its messages into the session\n\t * buffer instead of persisting them (they are flushed on success or discarded on escalation).\n\t * Returns true when the message was buffered, so the host skips its own persistence.\n\t */\n\tcaptureSessionMessage(message: AgentMessage): boolean {\n\t\tconst modelRouterBuffer = this._modelRouterSessionBuffer;\n\t\tif (!modelRouterBuffer) return false;\n\t\tif (message.role === \"custom\") {\n\t\t\tbufferModelRouterSessionCustomMessage(modelRouterBuffer, message);\n\t\t\treturn true;\n\t\t}\n\t\tif (message.role === \"user\" || message.role === \"assistant\" || message.role === \"toolResult\") {\n\t\t\tbufferModelRouterSessionMessage(modelRouterBuffer, message as Message);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate _isModelAvailableAndAuthed(pattern: string): boolean {\n\t\tconst resolved = resolveCliModel({ cliModel: pattern, modelRegistry: this.deps.getModelRegistry() });\n\t\tif (!resolved.model) return false;\n\t\treturn this.deps.getModelRegistry().hasConfiguredAuth(resolved.model);\n\t}\n\n\tprivate _resolveExecutorRoute(\n\t\tprompt: string,\n\t\texecutorPattern: string | undefined,\n\t): { decision: RouteDecision; model: Model<Api> } | undefined {\n\t\tif (!executorPattern) return undefined;\n\t\ttry {\n\t\t\tconst verdict = classifyExecutorTurn(prompt, this.deps.getSettingsManager().getToolkitScripts());\n\t\t\tif (!verdict.execute) return undefined;\n\t\t\tconst resolved = resolveCliModel({ cliModel: executorPattern, modelRegistry: this.deps.getModelRegistry() });\n\t\t\tif (!resolved.model || !this.deps.getModelRegistry().hasConfiguredAuth(resolved.model)) return undefined;\n\t\t\t// Fitness gate: the executor must have PROVEN tool-calling on this host (same\n\t\t\t// canonical-ref discipline as the curation gate).\n\t\t\tconst canonicalRef = `${resolved.model.provider}/${resolved.model.id}`;\n\t\t\tconst fitness = FitnessStore.forAgentDir(this.deps.getAgentDir())\n\t\t\t\t.getForHost()\n\t\t\t\t.find((entry) => entry.model === canonicalRef);\n\t\t\tconst toolCall = fitness?.report.toolCall;\n\t\t\tif (!toolCall || toolCall.succeeded < Math.ceil(toolCall.total * (2 / 3))) return undefined;\n\t\t\tthis._lastModelRouterIntent = \"research\";\n\t\t\treturn {\n\t\t\t\tdecision: {\n\t\t\t\t\ttier: \"cheap\",\n\t\t\t\t\trisk: \"scoped-write\",\n\t\t\t\t\tconfidence: 1,\n\t\t\t\t\treasonCode: \"executor_direct\",\n\t\t\t\t\treasons: [`Executor lane: Level-0 direct hit on toolkit script \"${verdict.scriptName}\"`],\n\t\t\t\t},\n\t\t\t\tmodel: resolved.model,\n\t\t\t};\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\t/** True if a run_toolkit_script tool result since `fromIndex` actually EXECUTED (not error/ambiguous). */\n\tprivate _executorTurnExecutedScript(fromIndex: number): boolean {\n\t\tfor (const message of this.deps.getAgent().state.messages.slice(fromIndex)) {\n\t\t\tif ((message as { role?: string }).role !== \"toolResult\") continue;\n\t\t\tif ((message as { toolName?: string }).toolName !== \"run_toolkit_script\") continue;\n\t\t\tif ((message as { isError?: boolean }).isError === true) continue;\n\t\t\tconst outcome = (message as { details?: { outcome?: unknown } }).details?.outcome;\n\t\t\tif (outcome === \"executed\") return true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t/** Ask the reflex brain to refine the last user request into an explicit toolkit instruction. */\n\tprivate async _buildExecutorRefinedPrompt(messages: AgentMessage | AgentMessage[]): Promise<string | undefined> {\n\t\ttry {\n\t\t\tconst model = this.deps.resolveCurationModelIfFit();\n\t\t\tif (!model) return undefined;\n\t\t\tconst list = Array.isArray(messages) ? messages : [messages];\n\t\t\tconst request = latestUserPromptText(list.filter((m): m is AgentMessage => true));\n\t\t\tif (!request) return undefined;\n\t\t\tconst scripts = this.deps.getSettingsManager().getToolkitScripts();\n\t\t\tconst completion = await this.deps.runIsolatedCompletion({\n\t\t\t\tsystemPrompt: REFLEX_INTERPRETER_SYSTEM_PROMPT,\n\t\t\t\tmessages: [\n\t\t\t\t\t{\n\t\t\t\t\t\trole: \"user\",\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: buildReflexUserPrompt(request, scripts) }],\n\t\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tmodel,\n\t\t\t\tthinkingLevel: \"off\",\n\t\t\t\tmaxTokens: 256,\n\t\t\t\tcacheRetention: \"short\",\n\t\t\t});\n\t\t\tif (completion.usage.cost.total > 0 || completion.usage.totalTokens > 0) {\n\t\t\t\tthis.deps.addSpawnedUsage(completion.usage, { label: \"executor-brain-warmup\" });\n\t\t\t}\n\t\t\tconst plan = parseReflexPlan(completion.text);\n\t\t\tif (!plan || plan.script === \"none\") return undefined;\n\t\t\tconst argHint = plan.args.length > 0 ? ` with args ${JSON.stringify(plan.args)}` : \"\";\n\t\t\treturn `Run the toolkit script \"${plan.script}\"${argHint} using run_toolkit_script, then report its result exactly.`;\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tprivate _resolveModelRouterTurnRoute(prompt: string): { decision: RouteDecision; model: Model<Api> } | undefined {\n\t\tconst settings = this.deps.getSettingsManager().getModelRouterSettings();\n\t\tif (!settings.enabled) {\n\t\t\tthis._lastModelRouterSkipReason = \"disabled\";\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// G16 executor lane: a Level-0 DIRECT toolkit hit on a command-shaped prompt routes the\n\t\t// whole turn to the configured local executor (tool-call-fitness-gated) instead of\n\t\t// spending the frontier model on a one-tool reflex. Ambiguity never routes here — it\n\t\t// stays with the big model and the reflex brain. Deterministic, so the judge is skipped.\n\t\tconst executorRoute = this._resolveExecutorRoute(prompt, settings.executorModel);\n\t\tif (executorRoute) return executorRoute;\n\n\t\tconst decision = classifyModelRouterRoute(prompt);\n\t\tthis._lastModelRouterIntent = decision.tier === \"cheap\" ? \"research\" : \"modify\";\n\n\t\t// Learning tier must not be selected for normal user prompts\n\t\tif (decision.tier === \"learning\") {\n\t\t\tthis._lastModelRouterSkipReason = \"learning tier not supported for user prompts\";\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst modelPattern =\n\t\t\tsettings[\n\t\t\t\tdecision.tier === \"cheap\" ? \"cheapModel\" : decision.tier === \"medium\" ? \"mediumModel\" : \"expensiveModel\"\n\t\t\t];\n\t\tconst label =\n\t\t\tdecision.tier === \"cheap\" ? \"cheap model\" : decision.tier === \"medium\" ? \"medium model\" : \"expensive model\";\n\n\t\tif (decision.tier === \"medium\" && (!modelPattern || !this._isModelAvailableAndAuthed(modelPattern))) {\n\t\t\tconst expensivePattern = settings.expensiveModel;\n\t\t\tif (expensivePattern && this._isModelAvailableAndAuthed(expensivePattern)) {\n\t\t\t\tconst resolvedExpensive = resolveCliModel({\n\t\t\t\t\tcliModel: expensivePattern,\n\t\t\t\t\tmodelRegistry: this.deps.getModelRegistry(),\n\t\t\t\t});\n\t\t\t\tif (resolvedExpensive.model) {\n\t\t\t\t\tdecision.fallbackFrom = \"medium\";\n\t\t\t\t\tdecision.tier = \"expensive\";\n\t\t\t\t\tdecision.reasonCode = \"medium_unavailable_fallback_expensive\";\n\t\t\t\t\tdecision.reasons = [...decision.reasons, \"Medium model is unavailable, falling back to expensive model\"];\n\t\t\t\t\tdecision.model = formatModelRouterModel(resolvedExpensive.model);\n\t\t\t\t\tthis._lastModelRouterSkipReason = undefined;\n\t\t\t\t\treturn { decision, model: resolvedExpensive.model };\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._lastModelRouterSkipReason = \"medium model and expensive fallback are unavailable\";\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (!modelPattern) {\n\t\t\tthis._lastModelRouterSkipReason = `${label} unset`;\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst resolved = resolveCliModel({ cliModel: modelPattern, modelRegistry: this.deps.getModelRegistry() });\n\t\tif (!resolved.model) {\n\t\t\tthis._lastModelRouterSkipReason = `${label} unresolved: ${modelPattern}`;\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst resolvedName = formatModelRouterModel(resolved.model);\n\t\tif (!this.deps.getModelRegistry().hasConfiguredAuth(resolved.model)) {\n\t\t\tthis._lastModelRouterSkipReason = `${label} missing auth: ${resolvedName}`;\n\t\t\treturn undefined;\n\t\t}\n\n\t\tthis._lastModelRouterSkipReason = undefined;\n\t\tdecision.model = resolvedName;\n\t\treturn { decision, model: resolved.model };\n\t}\n\n\tprivate _resolveModelRouterModelForIntent(intent: ModelRouterIntent): Model<Api> | undefined {\n\t\tconst settings = this.deps.getSettingsManager().getModelRouterSettings();\n\t\tconst modelPattern = intent === \"research\" ? settings.cheapModel : settings.expensiveModel;\n\t\tif (!modelPattern) return undefined;\n\t\tconst resolved = resolveCliModel({ cliModel: modelPattern, modelRegistry: this.deps.getModelRegistry() });\n\t\tif (!resolved.model) return undefined;\n\t\tif (!this.deps.getModelRegistry().hasConfiguredAuth(resolved.model)) return undefined;\n\t\treturn resolved.model;\n\t}\n\n\tresolveConfiguredTierModel(tier: \"cheap\" | \"medium\" | \"expensive\"): Model<Api> | undefined {\n\t\tconst settings = this.deps.getSettingsManager().getModelRouterSettings();\n\t\tconst pattern =\n\t\t\ttier === \"cheap\" ? settings.cheapModel : tier === \"medium\" ? settings.mediumModel : settings.expensiveModel;\n\t\tif (!pattern) return undefined;\n\t\tconst resolved = resolveCliModel({ cliModel: pattern, modelRegistry: this.deps.getModelRegistry() });\n\t\tif (!resolved.model) return undefined;\n\t\tif (!this.deps.getModelRegistry().hasConfiguredAuth(resolved.model)) return undefined;\n\t\treturn resolved.model;\n\t}\n\n\t/**\n\t * Router resolution with the routing judge (auto-on with the router): the regex classifier's\n\t * decision is the baseline; when a judge model resolves (judgeModel, else mediumModel), one\n\t * bounded, tool-less completion may move the tier between cheap/medium/expensive — never to\n\t * learning. Core rule encoded in the judge prompt: planning is never cheap unless genuinely\n\t * trivial. Every fallback stays visible in the decision reasons, and judge spend reports\n\t * through spawned-usage accounting.\n\t */\n\tasync resolveTurnRouteJudged(\n\t\tprompt: string,\n\t\toptions?: { skipJudge?: boolean },\n\t): Promise<{ decision: RouteDecision; model: Model<Api> } | undefined> {\n\t\tconst baseline = this._resolveModelRouterTurnRoute(prompt);\n\t\tif (!baseline) return undefined;\n\t\tif (options?.skipJudge) return baseline;\n\t\t// Deterministic executor routes need no judge (Level-0 already decided).\n\t\tif (baseline.decision.reasonCode === \"executor_direct\") return baseline;\n\n\t\tconst settings = this.deps.getSettingsManager().getModelRouterSettings();\n\t\tif (!settings.judgeEnabled) return baseline;\n\t\tconst judgePattern = settings.judgeModel ?? settings.mediumModel;\n\t\tif (!judgePattern) return baseline;\n\t\tconst judgeModel = this.deps.resolveLaneModel(judgePattern);\n\t\tif (!judgeModel) return baseline;\n\n\t\tlet spentUsage: Usage | undefined;\n\t\tconst judged = await runRouteJudge({\n\t\t\tprompt,\n\t\t\tbaseline: baseline.decision,\n\t\t\tsignal: this.deps.getReflectionSignal(),\n\t\t\tcomplete: async ({ systemPrompt, userPrompt, signal }) => {\n\t\t\t\tconst completion = await this.deps.runIsolatedCompletion({\n\t\t\t\t\tsystemPrompt,\n\t\t\t\t\tmessages: [{ role: \"user\", content: [{ type: \"text\", text: userPrompt }], timestamp: Date.now() }],\n\t\t\t\t\tmodel: judgeModel,\n\t\t\t\t\t// Per-tier thinking (R1): judgeThinking overrides the judge's own completion; unset\n\t\t\t\t\t// keeps today's \"off\" (the judge is a cheap classification call by default).\n\t\t\t\t\tthinkingLevel: settings.judgeThinking ?? \"off\",\n\t\t\t\t\tmaxTokens: ROUTE_JUDGE_MAX_OUTPUT_TOKENS,\n\t\t\t\t\tsignal,\n\t\t\t\t\t// The judge system prompt is static — the provider can cache the prefix.\n\t\t\t\t\tcacheRetention: \"short\",\n\t\t\t\t});\n\t\t\t\tspentUsage = completion.usage;\n\t\t\t\treturn {\n\t\t\t\t\ttext: completion.text,\n\t\t\t\t\tcostUsd: completion.usage.cost.total,\n\t\t\t\t\tstopReason: String(completion.stopReason),\n\t\t\t\t};\n\t\t\t},\n\t\t});\n\t\tif (spentUsage && (spentUsage.cost.total > 0 || spentUsage.totalTokens > 0)) {\n\t\t\tthis.deps.addSpawnedUsage(spentUsage, { label: \"router-judge\" });\n\t\t}\n\n\t\tif (!judged.verdict || judged.decision.tier === baseline.decision.tier) {\n\t\t\t// Same tier (or judge fell back): keep the baseline model, carry the annotated decision.\n\t\t\treturn { decision: judged.decision, model: baseline.model };\n\t\t}\n\n\t\tconst judgedTier = judged.decision.tier;\n\t\tif (judgedTier !== \"cheap\" && judgedTier !== \"medium\" && judgedTier !== \"expensive\") {\n\t\t\treturn { decision: baseline.decision, model: baseline.model };\n\t\t}\n\t\tconst judgedModel = this.resolveConfiguredTierModel(judgedTier);\n\t\tif (!judgedModel) {\n\t\t\treturn {\n\t\t\t\tdecision: {\n\t\t\t\t\t...baseline.decision,\n\t\t\t\t\treasons: [\n\t\t\t\t\t\t...baseline.decision.reasons,\n\t\t\t\t\t\t`Route judge chose ${judgedTier} but no model resolves for that tier; baseline kept`,\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t\tmodel: baseline.model,\n\t\t\t};\n\t\t}\n\t\treturn { decision: { ...judged.decision, model: formatModelRouterModel(judgedModel) }, model: judgedModel };\n\t}\n\n\t// biome-ignore lint/correctness/noUnusedPrivateClassMembers: test seam\n\tprivate _resolveModelRouterTurnModel(prompt: string): Model<Api> | undefined {\n\t\tconst resolved = this._resolveModelRouterTurnRoute(prompt);\n\t\treturn resolved?.model;\n\t}\n\n\tgetStatus(formatLabel?: (label: string) => string): string {\n\t\tconst recentDecisions = getRecentModelRouterDecisions(this.deps.getSessionManager().getEntries());\n\t\tconst lastDecision = this._lastModelRouterDecision ?? recentDecisions.at(-1);\n\t\tconst historicalDecisions = this._lastModelRouterDecision ? recentDecisions : recentDecisions.slice(0, -1);\n\t\tconst settings = this.deps.getSettingsManager().getModelRouterSettings();\n\t\tconst lines = [\n\t\t\tformatModelRouterStatus(\n\t\t\t\tsettings,\n\t\t\t\tlastDecision,\n\t\t\t\tformatLabel,\n\t\t\t\thistoricalDecisions,\n\t\t\t\tthis._lastModelRouterSkipReason,\n\t\t\t\tthis._lastModelRouterIntent ?? lastDecision?.intent,\n\t\t\t),\n\t\t];\n\t\tconst diagnostics = collectModelRouterConfigDiagnostics(settings, this.deps.getModelRegistry());\n\t\tif (diagnostics.length > 0) {\n\t\t\tlines.push(formatLabel ? formatLabel(\"Config diagnostics:\") : \"Config diagnostics:\");\n\t\t\tfor (const diagnostic of diagnostics) {\n\t\t\t\tlines.push(`- ${diagnostic}`);\n\t\t\t}\n\t\t}\n\t\treturn lines.join(\"\\n\");\n\t}\n\n\tasync runRoutedTurn(\n\t\tmessages: AgentMessage | AgentMessage[],\n\t\troutedModel: Model<Api> | undefined,\n\t\trouteDecision: RouteDecision | undefined,\n\t\tpersistDecision = true,\n\t): Promise<void> {\n\t\tif (!routedModel) {\n\t\t\tawait this.deps.runAgentPrompt(messages);\n\t\t\treturn;\n\t\t}\n\n\t\tconst agent = this.deps.getAgent();\n\t\tconst previousModel = agent.state.model;\n\t\tconst previousThinkingLevel = agent.state.thinkingLevel;\n\t\tconst previousTurnTools = agent.state.tools;\n\t\tconst previousSystemPrompt = agent.state.systemPrompt;\n\t\t// G4 swap bookkeeping (Bug G): the exact references the swap below assigns, so the finally can\n\t\t// restore ONLY what IT put there — never assigned when no swap happens (e.g. a full-class\n\t\t// routed profile).\n\t\tlet swappedTools: typeof previousTurnTools | undefined;\n\t\tlet swappedSystemPrompt: typeof previousSystemPrompt | undefined;\n\t\tconst previousActiveModelRouterIntent = this._activeModelRouterIntent;\n\t\tconst previousActiveModelRouterRoute = this._activeModelRouterRoute;\n\t\tconst previousModelRouterSessionBuffer = this._modelRouterSessionBuffer;\n\t\tconst previousModelRouterEscalationRequested = this._modelRouterEscalationRequested;\n\t\tconst bufferRoutedTurn = routeDecision?.tier === \"cheap\";\n\t\tconst originalHistoryLength = agent.state.messages.length;\n\t\tlet retryModel: Model<Api> | undefined;\n\t\tlet completedDecision: ModelRouterDecisionStatus | undefined = routeDecision\n\t\t\t? {\n\t\t\t\t\troute: routeDecision,\n\t\t\t\t\troutedModel: formatModelRouterModel(routedModel),\n\t\t\t\t\toutcome: \"routed\",\n\t\t\t\t\tintent: routeDecision.tier === \"cheap\" ? \"research\" : \"modify\",\n\t\t\t\t}\n\t\t\t: undefined;\n\t\tlet thrownError: unknown;\n\t\tif (routeDecision) {\n\t\t\tthis._lastModelRouterDecision = completedDecision;\n\t\t}\n\t\tthis._activeModelRouterIntent = routeDecision\n\t\t\t? routeDecision.tier === \"cheap\"\n\t\t\t\t? \"research\"\n\t\t\t\t: \"modify\"\n\t\t\t: undefined;\n\t\tthis._activeModelRouterRoute = routeDecision;\n\t\tif (bufferRoutedTurn) {\n\t\t\tthis._modelRouterSessionBuffer = createModelRouterSessionBuffer();\n\t\t\tthis._modelRouterEscalationRequested = false;\n\t\t}\n\t\tif (!modelsAreEqual(this.deps.getModel(), routedModel)) {\n\t\t\tagent.state.model = routedModel;\n\t\t\t// Per-tier thinking (R1): a configured tier/executor thinking level overrides the inherited\n\t\t\t// session thinking for THIS routed turn only; unset falls back to exactly today's\n\t\t\t// inherit-and-clamp behavior. Executor routes carry tier \"cheap\" too, so reasonCode is\n\t\t\t// checked first — otherwise an executor turn would silently pick up cheapThinking instead.\n\t\t\t// The judge's own completion has a separate knob (judgeThinking) applied at its call site.\n\t\t\tconst routerThinkingSettings = this.deps.getSettingsManager().getModelRouterSettings();\n\t\t\tconst configuredThinking = !routeDecision\n\t\t\t\t? undefined\n\t\t\t\t: routeDecision.reasonCode === \"executor_direct\"\n\t\t\t\t\t? routerThinkingSettings.executorThinking\n\t\t\t\t\t: routeDecision.tier === \"cheap\"\n\t\t\t\t\t\t? routerThinkingSettings.cheapThinking\n\t\t\t\t\t\t: routeDecision.tier === \"medium\"\n\t\t\t\t\t\t\t? routerThinkingSettings.mediumThinking\n\t\t\t\t\t\t\t: routeDecision.tier === \"expensive\"\n\t\t\t\t\t\t\t\t? routerThinkingSettings.expensiveThinking\n\t\t\t\t\t\t\t\t: undefined;\n\t\t\tagent.state.thinkingLevel = clampThinkingLevel(\n\t\t\t\troutedModel,\n\t\t\t\tconfiguredThinking ?? previousThinkingLevel,\n\t\t\t) as ThinkingLevel;\n\t\t\t// G4: capability tool-filtering follows the ROUTED model for the turn. Without this a\n\t\t\t// cheap/local routed model inherits the session model's full tool surface — schemas it\n\t\t\t// pays for on every request and may not be able to drive at all.\n\t\t\tconst routedProfile = deriveModelCapabilityProfile({\n\t\t\t\tcontextWindow: routedModel.contextWindow,\n\t\t\t\tmode: this.deps.getSettingsManager().getModelCapabilitySettings().mode,\n\t\t\t});\n\t\t\tif (routedProfile.class !== \"full\") {\n\t\t\t\tconst allowed = new Set(\n\t\t\t\t\tfilterToolNamesForCapability(\n\t\t\t\t\t\tpreviousTurnTools.map((tool) => tool.name),\n\t\t\t\t\t\troutedProfile,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t\tswappedTools = previousTurnTools.filter((tool) => allowed.has(tool.name));\n\t\t\t\tagent.state.tools = swappedTools;\n\t\t\t\t// G4: the system prompt follows the ROUTED model's filtered surface too — otherwise the\n\t\t\t\t// cheap/local model is billed for (and told about) tool guidelines/snippets it can't call.\n\t\t\t\t// Per-turn only; restored in the finally. A live extension override of the prompt is left\n\t\t\t\t// alone (only shed when we're on the base prompt).\n\t\t\t\tif (agent.state.systemPrompt === this.deps.getBaseSystemPrompt()) {\n\t\t\t\t\tswappedSystemPrompt = this.deps.buildSystemPromptForToolNames(\n\t\t\t\t\t\tagent.state.tools.map((tool) => tool.name),\n\t\t\t\t\t);\n\t\t\t\t\tagent.state.systemPrompt = swappedSystemPrompt;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\ttry {\n\t\t\tawait this.deps.runAgentPrompt(messages);\n\t\t\t// Speculative muscle-retry (G16 refinement): an executor-routed turn is a bet that the\n\t\t\t// small model can run the toolkit command directly. If it ends WITHOUT a successful\n\t\t\t// run_toolkit_script execution, retry ONCE on the same executor with the brain's\n\t\t\t// refined instruction injected — the brain warms while the muscle tries, so the retry\n\t\t\t// pays only when the muscle actually missed.\n\t\t\tif (\n\t\t\t\trouteDecision?.reasonCode === \"executor_direct\" &&\n\t\t\t\t!this._isModelRouterRetry &&\n\t\t\t\t!this._executorTurnExecutedScript(originalHistoryLength)\n\t\t\t) {\n\t\t\t\tconst refined = await this._buildExecutorRefinedPrompt(messages);\n\t\t\t\tif (refined) {\n\t\t\t\t\tagent.state.messages.splice(originalHistoryLength);\n\t\t\t\t\tawait this.deps.runAgentPrompt([\n\t\t\t\t\t\t{ role: \"user\", content: [{ type: \"text\", text: refined }], timestamp: Date.now() },\n\t\t\t\t\t]);\n\t\t\t\t\tcompletedDecision = {\n\t\t\t\t\t\troute: {\n\t\t\t\t\t\t\t...routeDecision,\n\t\t\t\t\t\t\treasonCode: \"executor_speculative_retry\",\n\t\t\t\t\t\t\treasons: [\n\t\t\t\t\t\t\t\t...routeDecision.reasons,\n\t\t\t\t\t\t\t\t\"Executor missed on first try; retried with brain-refined instruction\",\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t},\n\t\t\t\t\t\troutedModel: formatModelRouterModel(routedModel),\n\t\t\t\t\t\toutcome: \"routed\",\n\t\t\t\t\t\tintent: \"research\",\n\t\t\t\t\t};\n\t\t\t\t\tthis._lastModelRouterDecision = completedDecision;\n\t\t\t\t} else {\n\t\t\t\t\t// The muscle missed AND the reflex brain could not refine the request into a toolkit\n\t\t\t\t\t// instruction (no fit brain model, or no confident plan). There is deliberately NO\n\t\t\t\t\t// frontier fallback here, so surface the miss instead of letting it stand silently —\n\t\t\t\t\t// otherwise the routed turn just ends with an unrun command and no explanation.\n\t\t\t\t\tthis.deps.emit({\n\t\t\t\t\t\ttype: \"warning\",\n\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t\"Executor lane: the toolkit command did not run and the reflex brain could not refine it into an explicit instruction; leaving the turn as-is (no automatic escalation).\",\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (bufferRoutedTurn && this._modelRouterEscalationRequested) {\n\t\t\t\tagent.state.messages.splice(originalHistoryLength);\n\t\t\t\tretryModel = this._resolveModelRouterModelForIntent(\"modify\") ?? previousModel;\n\t\t\t\tcompletedDecision = {\n\t\t\t\t\troute: routeDecision!,\n\t\t\t\t\troutedModel: formatModelRouterModel(routedModel),\n\t\t\t\t\toutcome: \"escalated\",\n\t\t\t\t\tretryModel: formatModelRouterModel(retryModel),\n\t\t\t\t\tintent: routeDecision!.tier === \"cheap\" ? \"research\" : \"modify\",\n\t\t\t\t};\n\t\t\t\tthis._lastModelRouterDecision = completedDecision;\n\t\t\t} else if (bufferRoutedTurn && this._modelRouterSessionBuffer) {\n\t\t\t\tflushModelRouterSessionBuffer(\n\t\t\t\t\tthis._modelRouterSessionBuffer,\n\t\t\t\t\t(message) => {\n\t\t\t\t\t\tthis.deps.getSessionManager().appendMessage(message);\n\t\t\t\t\t},\n\t\t\t\t\t(customType, content, display, details) => {\n\t\t\t\t\t\tthis.deps.getSessionManager().appendCustomMessageEntry(customType, content, display, details);\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tthrownError = error;\n\t\t\tif (completedDecision) {\n\t\t\t\tcompletedDecision = { ...completedDecision, outcome: \"failed\" };\n\t\t\t\tthis._lastModelRouterDecision = completedDecision;\n\t\t\t}\n\t\t} finally {\n\t\t\t// Restore the pre-route model ONLY if the routed model is still in place: a command\n\t\t\t// handler may have legitimately changed the session model mid-turn (setModel or a\n\t\t\t// provider re-registration), and clobbering that would silently undo the change.\n\t\t\tif (modelsAreEqual(agent.state.model, routedModel)) {\n\t\t\t\tagent.state.model = previousModel;\n\t\t\t\tagent.state.thinkingLevel = previousThinkingLevel;\n\t\t\t\t// Symmetric restore (Bug G): undo tools/systemPrompt only if each is STILL the exact\n\t\t\t\t// reference/string the G4 swap above assigned (never assigned at all when the routed\n\t\t\t\t// profile was full-class — then there is nothing to restore either). An extension calling\n\t\t\t\t// setActiveToolsByName mid-turn reassigns both to its own values without touching the\n\t\t\t\t// model — the model guard above still passes, but that live change is legitimate and must\n\t\t\t\t// survive rather than being silently reverted to the stale pre-turn snapshot.\n\t\t\t\tif (swappedTools !== undefined && agent.state.tools === swappedTools) {\n\t\t\t\t\tagent.state.tools = previousTurnTools;\n\t\t\t\t}\n\t\t\t\tif (swappedSystemPrompt !== undefined && agent.state.systemPrompt === swappedSystemPrompt) {\n\t\t\t\t\tagent.state.systemPrompt = previousSystemPrompt;\n\t\t\t\t}\n\t\t\t\t// The registry may have changed mid-turn (command-time registerProvider): re-resolve\n\t\t\t\t// the restored model so a provider override is not dropped with the routed model.\n\t\t\t\tthis.deps.refreshCurrentModelFromRegistry();\n\t\t\t}\n\t\t\tthis._activeModelRouterIntent = previousActiveModelRouterIntent;\n\t\t\tthis._activeModelRouterRoute = previousActiveModelRouterRoute;\n\t\t\tthis._modelRouterSessionBuffer = previousModelRouterSessionBuffer;\n\t\t\tthis._modelRouterEscalationRequested = previousModelRouterEscalationRequested;\n\t\t}\n\n\t\tif (retryModel && !thrownError) {\n\t\t\tconst previousIsModelRouterRetry = this._isModelRouterRetry;\n\t\t\ttry {\n\t\t\t\tthis._isModelRouterRetry = true;\n\t\t\t\tconst retryDecision: RouteDecision = {\n\t\t\t\t\ttier: \"expensive\",\n\t\t\t\t\trisk: \"high-impact\",\n\t\t\t\t\tconfidence: 1.0,\n\t\t\t\t\treasonCode: \"cheap_mutating_tool_escalation\",\n\t\t\t\t\treasons: [\"Cheap research turn attempted a mutating tool and escalated\"],\n\t\t\t\t\tfallbackFrom: \"cheap\",\n\t\t\t\t\tmodel: formatModelRouterModel(retryModel),\n\t\t\t\t};\n\t\t\t\tawait this.runRoutedTurn(messages, retryModel, retryDecision, false);\n\t\t\t\tthis._lastModelRouterDecision = completedDecision;\n\t\t\t} catch (error) {\n\t\t\t\tthrownError = error;\n\t\t\t\tif (completedDecision) {\n\t\t\t\t\tcompletedDecision = { ...completedDecision, outcome: \"failed\" };\n\t\t\t\t\tthis._lastModelRouterDecision = completedDecision;\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tthis._isModelRouterRetry = previousIsModelRouterRetry;\n\t\t\t}\n\t\t}\n\n\t\tif (persistDecision && completedDecision) {\n\t\t\tpersistModelRouterDecision(this.deps.getSessionManager(), completedDecision);\n\t\t\t// G3: one route event per user-facing routed turn (the escalation retry runs with\n\t\t\t// persistDecision=false, so it does not double-emit). Codes/numbers only — no prompt text.\n\t\t\tthis.deps.emitAutonomyTelemetry({\n\t\t\t\ttype: AUTONOMY_TELEMETRY_EVENT_TYPES.routeDecision,\n\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\tpayload: {\n\t\t\t\t\ttier: completedDecision.route.tier,\n\t\t\t\t\trisk: completedDecision.route.risk,\n\t\t\t\t\treasonCode: completedDecision.route.reasonCode,\n\t\t\t\t\tconfidence: completedDecision.route.confidence,\n\t\t\t\t\toutcome: completedDecision.outcome,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\tif (thrownError) {\n\t\t\tthrow thrownError;\n\t\t}\n\t}\n}\n"]}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User-facing model + thinking-level selection.
|
|
3
|
+
*
|
|
4
|
+
* Extracted verbatim from agent-session.ts (god-file decomposition). Owns the manual/explicit model
|
|
5
|
+
* switch and cycle paths and the thinking-level set/cycle/clamp — the deliberate human choices, as
|
|
6
|
+
* opposed to the per-turn auto-routing owned by ModelRouterController. It mutates `agent.state.model`
|
|
7
|
+
* / `agent.state.thinkingLevel` through deps and re-derives the capability-scoped tool surface, but the
|
|
8
|
+
* session keeps the `model`/`thinkingLevel` GETTERS so the drive loop's reads are untouched. Model
|
|
9
|
+
* choice is advisory-only: it warns on a bad-fit fitness probe or an oversized local model, never blocks.
|
|
10
|
+
*/
|
|
11
|
+
import type { Agent, ThinkingLevel } from "@caupulican/pi-agent-core";
|
|
12
|
+
import type { SessionManager } from "@caupulican/pi-agent-core/node";
|
|
13
|
+
import type { Model } from "@caupulican/pi-ai";
|
|
14
|
+
import type { AgentSessionEvent, ModelCycleResult } from "./agent-session.ts";
|
|
15
|
+
import type { ExtensionRunner } from "./extensions/index.ts";
|
|
16
|
+
import type { ModelCapabilityProfile } from "./model-capability.ts";
|
|
17
|
+
import type { ModelRegistry } from "./model-registry.ts";
|
|
18
|
+
import type { OllamaRuntime } from "./models/local-runtime.ts";
|
|
19
|
+
import type { SettingsManager } from "./settings-manager.ts";
|
|
20
|
+
export interface ModelSelectionControllerDeps {
|
|
21
|
+
getAgent(): Agent;
|
|
22
|
+
getModel(): Model<any> | undefined;
|
|
23
|
+
getThinkingLevel(): ThinkingLevel;
|
|
24
|
+
getModelRegistry(): ModelRegistry;
|
|
25
|
+
getSessionManager(): SessionManager;
|
|
26
|
+
getSettingsManager(): SettingsManager;
|
|
27
|
+
getExtensionRunner(): ExtensionRunner;
|
|
28
|
+
getAgentDir(): string;
|
|
29
|
+
/** Scoped models (--models flag), used by the cycle path. */
|
|
30
|
+
getScopedModels(): Array<{
|
|
31
|
+
model: Model<any>;
|
|
32
|
+
thinkingLevel?: ThinkingLevel;
|
|
33
|
+
}>;
|
|
34
|
+
/** The user-requested active tool set, re-applied when the model's capability class changes. */
|
|
35
|
+
getRequestedActiveToolNames(): string[] | undefined;
|
|
36
|
+
getActiveToolNames(): string[];
|
|
37
|
+
setActiveToolsByName(toolNames: string[]): void;
|
|
38
|
+
getModelCapabilityProfile(): ModelCapabilityProfile;
|
|
39
|
+
/** Session event emit (warnings + thinking_level_changed; model_select goes via the extension runner). */
|
|
40
|
+
emit(event: AgentSessionEvent): void;
|
|
41
|
+
/** Context-window-usage warning check (session-owned, compaction-adjacent). */
|
|
42
|
+
checkContextWindowUsageWarning(): void;
|
|
43
|
+
/** Resolve the Ollama server URL for a model base URL (local-runtime controller). */
|
|
44
|
+
deriveOllamaServerUrl(modelBaseUrl: string): string;
|
|
45
|
+
/** Local Ollama runtime for the given server URL (used for the oversized-model risk check). */
|
|
46
|
+
getLocalRuntime(serverUrl: string): OllamaRuntime;
|
|
47
|
+
}
|
|
48
|
+
export declare class ModelSelectionController {
|
|
49
|
+
private readonly deps;
|
|
50
|
+
constructor(deps: ModelSelectionControllerDeps);
|
|
51
|
+
private _emitModelSelect;
|
|
52
|
+
/**
|
|
53
|
+
* Set model directly.
|
|
54
|
+
* Validates that auth is configured, saves to session and settings.
|
|
55
|
+
* @throws Error if no auth is configured for the model
|
|
56
|
+
*/
|
|
57
|
+
setModel(model: Model<any>, options?: {
|
|
58
|
+
persistSettings?: boolean;
|
|
59
|
+
}): Promise<void>;
|
|
60
|
+
private _warnIfManualModelChoiceIsRisky;
|
|
61
|
+
/**
|
|
62
|
+
* Cycle to next/previous model.
|
|
63
|
+
* Uses scoped models (from --models flag) if available, otherwise all available models.
|
|
64
|
+
* @param direction - "forward" (default) or "backward"
|
|
65
|
+
* @returns The new model info, or undefined if only one model available
|
|
66
|
+
*/
|
|
67
|
+
cycleModel(direction?: "forward" | "backward"): Promise<ModelCycleResult | undefined>;
|
|
68
|
+
private _cycleScopedModel;
|
|
69
|
+
private _cycleAvailableModel;
|
|
70
|
+
/**
|
|
71
|
+
* Set thinking level.
|
|
72
|
+
* Clamps to model capabilities based on available thinking levels.
|
|
73
|
+
* Saves to session and settings only if the level actually changes.
|
|
74
|
+
*/
|
|
75
|
+
setThinkingLevel(level: ThinkingLevel, options?: {
|
|
76
|
+
persistSettings?: boolean;
|
|
77
|
+
}): void;
|
|
78
|
+
/**
|
|
79
|
+
* Cycle to next thinking level.
|
|
80
|
+
* @returns New level, or undefined if model doesn't support thinking
|
|
81
|
+
*/
|
|
82
|
+
cycleThinkingLevel(): ThinkingLevel | undefined;
|
|
83
|
+
/**
|
|
84
|
+
* Get available thinking levels for current model.
|
|
85
|
+
* The provider will clamp to what the specific model supports internally.
|
|
86
|
+
*/
|
|
87
|
+
getAvailableThinkingLevels(): ThinkingLevel[];
|
|
88
|
+
/**
|
|
89
|
+
* Check if current model supports thinking/reasoning.
|
|
90
|
+
*/
|
|
91
|
+
supportsThinking(): boolean;
|
|
92
|
+
private _getThinkingLevelForModelSwitch;
|
|
93
|
+
private _clampThinkingLevel;
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=model-selection-controller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-selection-controller.d.ts","sourceRoot":"","sources":["../../src/core/model-selection-controller.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,KAAK,EAAO,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE9E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AACpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAG/D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAK7D,MAAM,WAAW,4BAA4B;IAC5C,QAAQ,IAAI,KAAK,CAAC;IAClB,QAAQ,IAAI,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;IACnC,gBAAgB,IAAI,aAAa,CAAC;IAClC,gBAAgB,IAAI,aAAa,CAAC;IAClC,iBAAiB,IAAI,cAAc,CAAC;IACpC,kBAAkB,IAAI,eAAe,CAAC;IACtC,kBAAkB,IAAI,eAAe,CAAC;IACtC,WAAW,IAAI,MAAM,CAAC;IACtB,6DAA6D;IAC7D,eAAe,IAAI,KAAK,CAAC;QAAE,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;QAAC,aAAa,CAAC,EAAE,aAAa,CAAA;KAAE,CAAC,CAAC;IAC/E,gGAAgG;IAChG,2BAA2B,IAAI,MAAM,EAAE,GAAG,SAAS,CAAC;IACpD,kBAAkB,IAAI,MAAM,EAAE,CAAC;IAC/B,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAChD,yBAAyB,IAAI,sBAAsB,CAAC;IACpD,0GAA0G;IAC1G,IAAI,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACrC,+EAA+E;IAC/E,8BAA8B,IAAI,IAAI,CAAC;IACvC,qFAAqF;IACrF,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAAC;IACpD,+FAA+F;IAC/F,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,CAAC;CAClD;AAED,qBAAa,wBAAwB;IACpC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA+B;IAEpD,YAAY,IAAI,EAAE,4BAA4B,EAE7C;YAEa,gBAAgB;IAc9B;;;;OAIG;IACG,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,OAAO,GAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAmC5F;YAYa,+BAA+B;IAoC7C;;;;;OAKG;IACG,UAAU,CAAC,SAAS,GAAE,SAAS,GAAG,UAAsB,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAKrG;YAEa,iBAAiB;YAkCjB,oBAAoB;IA4BlC;;;;OAIG;IACH,gBAAgB,CAAC,KAAK,EAAE,aAAa,EAAE,OAAO,GAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,IAAI,CAuBxF;IAED;;;OAGG;IACH,kBAAkB,IAAI,aAAa,GAAG,SAAS,CAU9C;IAED;;;OAGG;IACH,0BAA0B,IAAI,aAAa,EAAE,CAI5C;IAED;;OAEG;IACH,gBAAgB,IAAI,OAAO,CAE1B;IAED,OAAO,CAAC,+BAA+B;IAUvC,OAAO,CAAC,mBAAmB;CAI3B","sourcesContent":["/**\n * User-facing model + thinking-level selection.\n *\n * Extracted verbatim from agent-session.ts (god-file decomposition). Owns the manual/explicit model\n * switch and cycle paths and the thinking-level set/cycle/clamp — the deliberate human choices, as\n * opposed to the per-turn auto-routing owned by ModelRouterController. It mutates `agent.state.model`\n * / `agent.state.thinkingLevel` through deps and re-derives the capability-scoped tool surface, but the\n * session keeps the `model`/`thinkingLevel` GETTERS so the drive loop's reads are untouched. Model\n * choice is advisory-only: it warns on a bad-fit fitness probe or an oversized local model, never blocks.\n */\n\nimport { totalmem } from \"node:os\";\nimport type { Agent, ThinkingLevel } from \"@caupulican/pi-agent-core\";\nimport type { SessionManager } from \"@caupulican/pi-agent-core/node\";\nimport type { Api, Model } from \"@caupulican/pi-ai\";\nimport { clampThinkingLevel, getSupportedThinkingLevels, modelsAreEqual } from \"@caupulican/pi-ai\";\nimport type { AgentSessionEvent, ModelCycleResult } from \"./agent-session.ts\";\nimport { DEFAULT_THINKING_LEVEL } from \"./defaults.ts\";\nimport type { ExtensionRunner } from \"./extensions/index.ts\";\nimport type { ModelCapabilityProfile } from \"./model-capability.ts\";\nimport type { ModelRegistry } from \"./model-registry.ts\";\nimport { FitnessStore } from \"./models/fitness-store.ts\";\nimport { OLLAMA_PROVIDER } from \"./models/local-registration.ts\";\nimport type { OllamaRuntime } from \"./models/local-runtime.ts\";\nimport { matchesInstalledLocalModel } from \"./models/model-ref.ts\";\nimport { isProbeAllFailed } from \"./research/model-fitness.ts\";\nimport type { SettingsManager } from \"./settings-manager.ts\";\n\n/** Standard thinking levels (fallback set when the current model is unknown). */\nconst THINKING_LEVELS: ThinkingLevel[] = [\"off\", \"minimal\", \"low\", \"medium\", \"high\"];\n\nexport interface ModelSelectionControllerDeps {\n\tgetAgent(): Agent;\n\tgetModel(): Model<any> | undefined;\n\tgetThinkingLevel(): ThinkingLevel;\n\tgetModelRegistry(): ModelRegistry;\n\tgetSessionManager(): SessionManager;\n\tgetSettingsManager(): SettingsManager;\n\tgetExtensionRunner(): ExtensionRunner;\n\tgetAgentDir(): string;\n\t/** Scoped models (--models flag), used by the cycle path. */\n\tgetScopedModels(): Array<{ model: Model<any>; thinkingLevel?: ThinkingLevel }>;\n\t/** The user-requested active tool set, re-applied when the model's capability class changes. */\n\tgetRequestedActiveToolNames(): string[] | undefined;\n\tgetActiveToolNames(): string[];\n\tsetActiveToolsByName(toolNames: string[]): void;\n\tgetModelCapabilityProfile(): ModelCapabilityProfile;\n\t/** Session event emit (warnings + thinking_level_changed; model_select goes via the extension runner). */\n\temit(event: AgentSessionEvent): void;\n\t/** Context-window-usage warning check (session-owned, compaction-adjacent). */\n\tcheckContextWindowUsageWarning(): void;\n\t/** Resolve the Ollama server URL for a model base URL (local-runtime controller). */\n\tderiveOllamaServerUrl(modelBaseUrl: string): string;\n\t/** Local Ollama runtime for the given server URL (used for the oversized-model risk check). */\n\tgetLocalRuntime(serverUrl: string): OllamaRuntime;\n}\n\nexport class ModelSelectionController {\n\tprivate readonly deps: ModelSelectionControllerDeps;\n\n\tconstructor(deps: ModelSelectionControllerDeps) {\n\t\tthis.deps = deps;\n\t}\n\n\tprivate async _emitModelSelect(\n\t\tnextModel: Model<any>,\n\t\tpreviousModel: Model<any> | undefined,\n\t\tsource: \"set\" | \"cycle\" | \"restore\",\n\t): Promise<void> {\n\t\tif (modelsAreEqual(previousModel, nextModel)) return;\n\t\tawait this.deps.getExtensionRunner().emit({\n\t\t\ttype: \"model_select\",\n\t\t\tmodel: nextModel,\n\t\t\tpreviousModel,\n\t\t\tsource,\n\t\t});\n\t}\n\n\t/**\n\t * Set model directly.\n\t * Validates that auth is configured, saves to session and settings.\n\t * @throws Error if no auth is configured for the model\n\t */\n\tasync setModel(model: Model<any>, options: { persistSettings?: boolean } = {}): Promise<void> {\n\t\tif (!this.deps.getModelRegistry().hasConfiguredAuth(model)) {\n\t\t\tthrow new Error(`No API key for ${model.provider}/${model.id}`);\n\t\t}\n\n\t\tconst persistSettings = options.persistSettings ?? true;\n\t\tconst previousModel = this.deps.getModel();\n\t\tconst thinkingLevel = this._getThinkingLevelForModelSwitch();\n\t\tthis.deps.getAgent().state.model = model;\n\t\tthis.deps.getSessionManager().appendModelChange(model.provider, model.id);\n\t\tif (persistSettings) {\n\t\t\tthis.deps.getSettingsManager().setDefaultModelAndProvider(model.provider, model.id);\n\t\t}\n\n\t\t// Re-clamp thinking level for new model's capabilities\n\t\tthis.setThinkingLevel(thinkingLevel, { persistSettings });\n\n\t\tawait this._emitModelSelect(model, previousModel, \"set\");\n\t\tthis.deps.checkContextWindowUsageWarning();\n\t\tawait this._warnIfManualModelChoiceIsRisky(model);\n\n\t\t// Re-derive the model-capability tool surface for the new model (restores the full requested\n\t\t// set when moving small -> large, reduces it when moving large -> small).\n\t\tconst requestedActiveToolNames = this.deps.getRequestedActiveToolNames();\n\t\tif (requestedActiveToolNames) {\n\t\t\tconst before = this.deps.getActiveToolNames().join(\",\");\n\t\t\tthis.deps.setActiveToolsByName(requestedActiveToolNames);\n\t\t\tconst capability = this.deps.getModelCapabilityProfile();\n\t\t\tif (capability.class !== \"full\" && this.deps.getActiveToolNames().join(\",\") !== before) {\n\t\t\t\tthis.deps.emit({\n\t\t\t\t\ttype: \"warning\",\n\t\t\t\t\tmessage: `Small-context model detected (${capability.contextWindow ?? \"unknown\"} tokens, class '${capability.class}'): active tools reduced to [${this.deps.getActiveToolNames().join(\", \")}]; background lanes ${capability.backgroundLanesEnabled ? \"enabled\" : \"disabled\"}.`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Manual model choice is a deliberate human decision, not an auto-adoption flow — it is\n\t * ADVISORY ONLY: warn on evidence the model is a bad fit, but never block and never prompt\n\t * (print/RPC modes only ever see plain warning text through the existing `warning` event, the\n\t * same channel `_checkContextWindowUsageWarning` above uses). Two independent checks, both\n\t * best-effort:\n\t * - a recorded all-lanes-failed fitness probe on THIS host (see `isProbeAllFailed`);\n\t * - for an Ollama-served local model, weights that exceed ~90% of total system memory, which\n\t * is the exact failure the OOM report reproduced (llama-server needs the whole model resident).\n\t */\n\tprivate async _warnIfManualModelChoiceIsRisky(model: Model<Api>): Promise<void> {\n\t\tconst canonicalRef = `${model.provider}/${model.id}`;\n\t\ttry {\n\t\t\tconst fitness = FitnessStore.forAgentDir(this.deps.getAgentDir())\n\t\t\t\t.getForHost()\n\t\t\t\t.find((entry) => entry.model === canonicalRef);\n\t\t\tif (fitness && isProbeAllFailed(fitness.report)) {\n\t\t\t\tthis.deps.emit({\n\t\t\t\t\ttype: \"warning\",\n\t\t\t\t\tmessage: `${canonicalRef} failed its fitness probe on all surfaces on this host (probed ${fitness.at}) — it is likely to fail in production too. Proceeding because you set it manually.`,\n\t\t\t\t});\n\t\t\t}\n\t\t} catch {\n\t\t\t// advisory only; a lookup failure must never block a manual model choice\n\t\t}\n\n\t\tif (model.provider !== OLLAMA_PROVIDER) return;\n\t\ttry {\n\t\t\tconst serverUrl = this.deps.deriveOllamaServerUrl(model.baseUrl);\n\t\t\tconst installed = await this.deps.getLocalRuntime(serverUrl).list();\n\t\t\tconst entry = installed.find((candidate) => matchesInstalledLocalModel(model.id, candidate.name));\n\t\t\tif (!entry) return;\n\t\t\tconst memoryBudget = totalmem() * 0.9;\n\t\t\tif (entry.sizeBytes > memoryBudget) {\n\t\t\t\tconst sizeGb = (entry.sizeBytes / 1e9).toFixed(1);\n\t\t\t\tconst totalGb = (totalmem() / 1e9).toFixed(1);\n\t\t\t\tthis.deps.emit({\n\t\t\t\t\ttype: \"warning\",\n\t\t\t\t\tmessage: `${canonicalRef} is ~${sizeGb}GB, over 90% of this machine's ${totalGb}GB RAM — llama-server is likely to OOM when it runs. Proceeding because you set it manually.`,\n\t\t\t\t});\n\t\t\t}\n\t\t} catch {\n\t\t\t// advisory only; an unreachable local server must never block a manual model choice\n\t\t}\n\t}\n\n\t/**\n\t * Cycle to next/previous model.\n\t * Uses scoped models (from --models flag) if available, otherwise all available models.\n\t * @param direction - \"forward\" (default) or \"backward\"\n\t * @returns The new model info, or undefined if only one model available\n\t */\n\tasync cycleModel(direction: \"forward\" | \"backward\" = \"forward\"): Promise<ModelCycleResult | undefined> {\n\t\tif (this.deps.getScopedModels().length > 0) {\n\t\t\treturn this._cycleScopedModel(direction);\n\t\t}\n\t\treturn this._cycleAvailableModel(direction);\n\t}\n\n\tprivate async _cycleScopedModel(direction: \"forward\" | \"backward\"): Promise<ModelCycleResult | undefined> {\n\t\tconst scopedModels = this.deps\n\t\t\t.getScopedModels()\n\t\t\t.filter((scoped) => this.deps.getModelRegistry().hasConfiguredAuth(scoped.model));\n\t\tif (scopedModels.length <= 1) return undefined;\n\n\t\tconst currentModel = this.deps.getModel();\n\t\tlet currentIndex = scopedModels.findIndex((sm) => modelsAreEqual(sm.model, currentModel));\n\n\t\tif (currentIndex === -1) currentIndex = 0;\n\t\tconst len = scopedModels.length;\n\t\tconst nextIndex = direction === \"forward\" ? (currentIndex + 1) % len : (currentIndex - 1 + len) % len;\n\t\tconst next = scopedModels[nextIndex];\n\t\tconst thinkingLevel = this._getThinkingLevelForModelSwitch(next.thinkingLevel);\n\n\t\t// Apply model\n\t\tthis.deps.getAgent().state.model = next.model;\n\t\tthis.deps.getSessionManager().appendModelChange(next.model.provider, next.model.id);\n\t\tthis.deps.getSettingsManager().setDefaultModelAndProvider(next.model.provider, next.model.id);\n\n\t\t// Apply thinking level.\n\t\t// - Explicit scoped model thinking level overrides current session level\n\t\t// - Undefined scoped model thinking level inherits the current session preference\n\t\t// setThinkingLevel clamps to model capabilities.\n\t\tthis.setThinkingLevel(thinkingLevel);\n\n\t\tawait this._emitModelSelect(next.model, currentModel, \"cycle\");\n\n\t\tthis.deps.checkContextWindowUsageWarning();\n\t\tawait this._warnIfManualModelChoiceIsRisky(next.model);\n\n\t\treturn { model: next.model, thinkingLevel: this.deps.getThinkingLevel(), isScoped: true };\n\t}\n\n\tprivate async _cycleAvailableModel(direction: \"forward\" | \"backward\"): Promise<ModelCycleResult | undefined> {\n\t\tconst availableModels = await this.deps.getModelRegistry().getAvailable();\n\t\tif (availableModels.length <= 1) return undefined;\n\n\t\tconst currentModel = this.deps.getModel();\n\t\tlet currentIndex = availableModels.findIndex((m) => modelsAreEqual(m, currentModel));\n\n\t\tif (currentIndex === -1) currentIndex = 0;\n\t\tconst len = availableModels.length;\n\t\tconst nextIndex = direction === \"forward\" ? (currentIndex + 1) % len : (currentIndex - 1 + len) % len;\n\t\tconst nextModel = availableModels[nextIndex];\n\n\t\tconst thinkingLevel = this._getThinkingLevelForModelSwitch();\n\t\tthis.deps.getAgent().state.model = nextModel;\n\t\tthis.deps.getSessionManager().appendModelChange(nextModel.provider, nextModel.id);\n\t\tthis.deps.getSettingsManager().setDefaultModelAndProvider(nextModel.provider, nextModel.id);\n\n\t\t// Re-clamp thinking level for new model's capabilities\n\t\tthis.setThinkingLevel(thinkingLevel);\n\n\t\tawait this._emitModelSelect(nextModel, currentModel, \"cycle\");\n\n\t\tthis.deps.checkContextWindowUsageWarning();\n\t\tawait this._warnIfManualModelChoiceIsRisky(nextModel);\n\n\t\treturn { model: nextModel, thinkingLevel: this.deps.getThinkingLevel(), isScoped: false };\n\t}\n\n\t/**\n\t * Set thinking level.\n\t * Clamps to model capabilities based on available thinking levels.\n\t * Saves to session and settings only if the level actually changes.\n\t */\n\tsetThinkingLevel(level: ThinkingLevel, options: { persistSettings?: boolean } = {}): void {\n\t\tconst availableLevels = this.getAvailableThinkingLevels();\n\t\tconst effectiveLevel = availableLevels.includes(level) ? level : this._clampThinkingLevel(level, availableLevels);\n\n\t\t// Only persist if actually changing\n\t\tconst previousLevel = this.deps.getAgent().state.thinkingLevel;\n\t\tconst isChanging = effectiveLevel !== previousLevel;\n\t\tconst persistSettings = options.persistSettings ?? true;\n\n\t\tthis.deps.getAgent().state.thinkingLevel = effectiveLevel;\n\n\t\tif (isChanging) {\n\t\t\tthis.deps.getSessionManager().appendThinkingLevelChange(effectiveLevel);\n\t\t\tif (persistSettings && (this.supportsThinking() || effectiveLevel !== \"off\")) {\n\t\t\t\tthis.deps.getSettingsManager().setDefaultThinkingLevel(effectiveLevel);\n\t\t\t}\n\t\t\tthis.deps.emit({ type: \"thinking_level_changed\", level: effectiveLevel });\n\t\t\tvoid this.deps.getExtensionRunner().emit({\n\t\t\t\ttype: \"thinking_level_select\",\n\t\t\t\tlevel: effectiveLevel,\n\t\t\t\tpreviousLevel,\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Cycle to next thinking level.\n\t * @returns New level, or undefined if model doesn't support thinking\n\t */\n\tcycleThinkingLevel(): ThinkingLevel | undefined {\n\t\tif (!this.supportsThinking()) return undefined;\n\n\t\tconst levels = this.getAvailableThinkingLevels();\n\t\tconst currentIndex = levels.indexOf(this.deps.getThinkingLevel());\n\t\tconst nextIndex = (currentIndex + 1) % levels.length;\n\t\tconst nextLevel = levels[nextIndex];\n\n\t\tthis.setThinkingLevel(nextLevel);\n\t\treturn nextLevel;\n\t}\n\n\t/**\n\t * Get available thinking levels for current model.\n\t * The provider will clamp to what the specific model supports internally.\n\t */\n\tgetAvailableThinkingLevels(): ThinkingLevel[] {\n\t\tconst model = this.deps.getModel();\n\t\tif (!model) return THINKING_LEVELS;\n\t\treturn getSupportedThinkingLevels(model) as ThinkingLevel[];\n\t}\n\n\t/**\n\t * Check if current model supports thinking/reasoning.\n\t */\n\tsupportsThinking(): boolean {\n\t\treturn !!this.deps.getModel()?.reasoning;\n\t}\n\n\tprivate _getThinkingLevelForModelSwitch(explicitLevel?: ThinkingLevel): ThinkingLevel {\n\t\tif (explicitLevel !== undefined) {\n\t\t\treturn explicitLevel;\n\t\t}\n\t\tif (!this.supportsThinking()) {\n\t\t\treturn this.deps.getSettingsManager().getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL;\n\t\t}\n\t\treturn this.deps.getThinkingLevel();\n\t}\n\n\tprivate _clampThinkingLevel(level: ThinkingLevel, _availableLevels: ThinkingLevel[]): ThinkingLevel {\n\t\tconst model = this.deps.getModel();\n\t\treturn model ? (clampThinkingLevel(model, level) as ThinkingLevel) : \"off\";\n\t}\n}\n"]}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User-facing model + thinking-level selection.
|
|
3
|
+
*
|
|
4
|
+
* Extracted verbatim from agent-session.ts (god-file decomposition). Owns the manual/explicit model
|
|
5
|
+
* switch and cycle paths and the thinking-level set/cycle/clamp — the deliberate human choices, as
|
|
6
|
+
* opposed to the per-turn auto-routing owned by ModelRouterController. It mutates `agent.state.model`
|
|
7
|
+
* / `agent.state.thinkingLevel` through deps and re-derives the capability-scoped tool surface, but the
|
|
8
|
+
* session keeps the `model`/`thinkingLevel` GETTERS so the drive loop's reads are untouched. Model
|
|
9
|
+
* choice is advisory-only: it warns on a bad-fit fitness probe or an oversized local model, never blocks.
|
|
10
|
+
*/
|
|
11
|
+
import { totalmem } from "node:os";
|
|
12
|
+
import { clampThinkingLevel, getSupportedThinkingLevels, modelsAreEqual } from "@caupulican/pi-ai";
|
|
13
|
+
import { DEFAULT_THINKING_LEVEL } from "./defaults.js";
|
|
14
|
+
import { FitnessStore } from "./models/fitness-store.js";
|
|
15
|
+
import { OLLAMA_PROVIDER } from "./models/local-registration.js";
|
|
16
|
+
import { matchesInstalledLocalModel } from "./models/model-ref.js";
|
|
17
|
+
import { isProbeAllFailed } from "./research/model-fitness.js";
|
|
18
|
+
/** Standard thinking levels (fallback set when the current model is unknown). */
|
|
19
|
+
const THINKING_LEVELS = ["off", "minimal", "low", "medium", "high"];
|
|
20
|
+
export class ModelSelectionController {
|
|
21
|
+
deps;
|
|
22
|
+
constructor(deps) {
|
|
23
|
+
this.deps = deps;
|
|
24
|
+
}
|
|
25
|
+
async _emitModelSelect(nextModel, previousModel, source) {
|
|
26
|
+
if (modelsAreEqual(previousModel, nextModel))
|
|
27
|
+
return;
|
|
28
|
+
await this.deps.getExtensionRunner().emit({
|
|
29
|
+
type: "model_select",
|
|
30
|
+
model: nextModel,
|
|
31
|
+
previousModel,
|
|
32
|
+
source,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Set model directly.
|
|
37
|
+
* Validates that auth is configured, saves to session and settings.
|
|
38
|
+
* @throws Error if no auth is configured for the model
|
|
39
|
+
*/
|
|
40
|
+
async setModel(model, options = {}) {
|
|
41
|
+
if (!this.deps.getModelRegistry().hasConfiguredAuth(model)) {
|
|
42
|
+
throw new Error(`No API key for ${model.provider}/${model.id}`);
|
|
43
|
+
}
|
|
44
|
+
const persistSettings = options.persistSettings ?? true;
|
|
45
|
+
const previousModel = this.deps.getModel();
|
|
46
|
+
const thinkingLevel = this._getThinkingLevelForModelSwitch();
|
|
47
|
+
this.deps.getAgent().state.model = model;
|
|
48
|
+
this.deps.getSessionManager().appendModelChange(model.provider, model.id);
|
|
49
|
+
if (persistSettings) {
|
|
50
|
+
this.deps.getSettingsManager().setDefaultModelAndProvider(model.provider, model.id);
|
|
51
|
+
}
|
|
52
|
+
// Re-clamp thinking level for new model's capabilities
|
|
53
|
+
this.setThinkingLevel(thinkingLevel, { persistSettings });
|
|
54
|
+
await this._emitModelSelect(model, previousModel, "set");
|
|
55
|
+
this.deps.checkContextWindowUsageWarning();
|
|
56
|
+
await this._warnIfManualModelChoiceIsRisky(model);
|
|
57
|
+
// Re-derive the model-capability tool surface for the new model (restores the full requested
|
|
58
|
+
// set when moving small -> large, reduces it when moving large -> small).
|
|
59
|
+
const requestedActiveToolNames = this.deps.getRequestedActiveToolNames();
|
|
60
|
+
if (requestedActiveToolNames) {
|
|
61
|
+
const before = this.deps.getActiveToolNames().join(",");
|
|
62
|
+
this.deps.setActiveToolsByName(requestedActiveToolNames);
|
|
63
|
+
const capability = this.deps.getModelCapabilityProfile();
|
|
64
|
+
if (capability.class !== "full" && this.deps.getActiveToolNames().join(",") !== before) {
|
|
65
|
+
this.deps.emit({
|
|
66
|
+
type: "warning",
|
|
67
|
+
message: `Small-context model detected (${capability.contextWindow ?? "unknown"} tokens, class '${capability.class}'): active tools reduced to [${this.deps.getActiveToolNames().join(", ")}]; background lanes ${capability.backgroundLanesEnabled ? "enabled" : "disabled"}.`,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Manual model choice is a deliberate human decision, not an auto-adoption flow — it is
|
|
74
|
+
* ADVISORY ONLY: warn on evidence the model is a bad fit, but never block and never prompt
|
|
75
|
+
* (print/RPC modes only ever see plain warning text through the existing `warning` event, the
|
|
76
|
+
* same channel `_checkContextWindowUsageWarning` above uses). Two independent checks, both
|
|
77
|
+
* best-effort:
|
|
78
|
+
* - a recorded all-lanes-failed fitness probe on THIS host (see `isProbeAllFailed`);
|
|
79
|
+
* - for an Ollama-served local model, weights that exceed ~90% of total system memory, which
|
|
80
|
+
* is the exact failure the OOM report reproduced (llama-server needs the whole model resident).
|
|
81
|
+
*/
|
|
82
|
+
async _warnIfManualModelChoiceIsRisky(model) {
|
|
83
|
+
const canonicalRef = `${model.provider}/${model.id}`;
|
|
84
|
+
try {
|
|
85
|
+
const fitness = FitnessStore.forAgentDir(this.deps.getAgentDir())
|
|
86
|
+
.getForHost()
|
|
87
|
+
.find((entry) => entry.model === canonicalRef);
|
|
88
|
+
if (fitness && isProbeAllFailed(fitness.report)) {
|
|
89
|
+
this.deps.emit({
|
|
90
|
+
type: "warning",
|
|
91
|
+
message: `${canonicalRef} failed its fitness probe on all surfaces on this host (probed ${fitness.at}) — it is likely to fail in production too. Proceeding because you set it manually.`,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
// advisory only; a lookup failure must never block a manual model choice
|
|
97
|
+
}
|
|
98
|
+
if (model.provider !== OLLAMA_PROVIDER)
|
|
99
|
+
return;
|
|
100
|
+
try {
|
|
101
|
+
const serverUrl = this.deps.deriveOllamaServerUrl(model.baseUrl);
|
|
102
|
+
const installed = await this.deps.getLocalRuntime(serverUrl).list();
|
|
103
|
+
const entry = installed.find((candidate) => matchesInstalledLocalModel(model.id, candidate.name));
|
|
104
|
+
if (!entry)
|
|
105
|
+
return;
|
|
106
|
+
const memoryBudget = totalmem() * 0.9;
|
|
107
|
+
if (entry.sizeBytes > memoryBudget) {
|
|
108
|
+
const sizeGb = (entry.sizeBytes / 1e9).toFixed(1);
|
|
109
|
+
const totalGb = (totalmem() / 1e9).toFixed(1);
|
|
110
|
+
this.deps.emit({
|
|
111
|
+
type: "warning",
|
|
112
|
+
message: `${canonicalRef} is ~${sizeGb}GB, over 90% of this machine's ${totalGb}GB RAM — llama-server is likely to OOM when it runs. Proceeding because you set it manually.`,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
// advisory only; an unreachable local server must never block a manual model choice
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Cycle to next/previous model.
|
|
122
|
+
* Uses scoped models (from --models flag) if available, otherwise all available models.
|
|
123
|
+
* @param direction - "forward" (default) or "backward"
|
|
124
|
+
* @returns The new model info, or undefined if only one model available
|
|
125
|
+
*/
|
|
126
|
+
async cycleModel(direction = "forward") {
|
|
127
|
+
if (this.deps.getScopedModels().length > 0) {
|
|
128
|
+
return this._cycleScopedModel(direction);
|
|
129
|
+
}
|
|
130
|
+
return this._cycleAvailableModel(direction);
|
|
131
|
+
}
|
|
132
|
+
async _cycleScopedModel(direction) {
|
|
133
|
+
const scopedModels = this.deps
|
|
134
|
+
.getScopedModels()
|
|
135
|
+
.filter((scoped) => this.deps.getModelRegistry().hasConfiguredAuth(scoped.model));
|
|
136
|
+
if (scopedModels.length <= 1)
|
|
137
|
+
return undefined;
|
|
138
|
+
const currentModel = this.deps.getModel();
|
|
139
|
+
let currentIndex = scopedModels.findIndex((sm) => modelsAreEqual(sm.model, currentModel));
|
|
140
|
+
if (currentIndex === -1)
|
|
141
|
+
currentIndex = 0;
|
|
142
|
+
const len = scopedModels.length;
|
|
143
|
+
const nextIndex = direction === "forward" ? (currentIndex + 1) % len : (currentIndex - 1 + len) % len;
|
|
144
|
+
const next = scopedModels[nextIndex];
|
|
145
|
+
const thinkingLevel = this._getThinkingLevelForModelSwitch(next.thinkingLevel);
|
|
146
|
+
// Apply model
|
|
147
|
+
this.deps.getAgent().state.model = next.model;
|
|
148
|
+
this.deps.getSessionManager().appendModelChange(next.model.provider, next.model.id);
|
|
149
|
+
this.deps.getSettingsManager().setDefaultModelAndProvider(next.model.provider, next.model.id);
|
|
150
|
+
// Apply thinking level.
|
|
151
|
+
// - Explicit scoped model thinking level overrides current session level
|
|
152
|
+
// - Undefined scoped model thinking level inherits the current session preference
|
|
153
|
+
// setThinkingLevel clamps to model capabilities.
|
|
154
|
+
this.setThinkingLevel(thinkingLevel);
|
|
155
|
+
await this._emitModelSelect(next.model, currentModel, "cycle");
|
|
156
|
+
this.deps.checkContextWindowUsageWarning();
|
|
157
|
+
await this._warnIfManualModelChoiceIsRisky(next.model);
|
|
158
|
+
return { model: next.model, thinkingLevel: this.deps.getThinkingLevel(), isScoped: true };
|
|
159
|
+
}
|
|
160
|
+
async _cycleAvailableModel(direction) {
|
|
161
|
+
const availableModels = await this.deps.getModelRegistry().getAvailable();
|
|
162
|
+
if (availableModels.length <= 1)
|
|
163
|
+
return undefined;
|
|
164
|
+
const currentModel = this.deps.getModel();
|
|
165
|
+
let currentIndex = availableModels.findIndex((m) => modelsAreEqual(m, currentModel));
|
|
166
|
+
if (currentIndex === -1)
|
|
167
|
+
currentIndex = 0;
|
|
168
|
+
const len = availableModels.length;
|
|
169
|
+
const nextIndex = direction === "forward" ? (currentIndex + 1) % len : (currentIndex - 1 + len) % len;
|
|
170
|
+
const nextModel = availableModels[nextIndex];
|
|
171
|
+
const thinkingLevel = this._getThinkingLevelForModelSwitch();
|
|
172
|
+
this.deps.getAgent().state.model = nextModel;
|
|
173
|
+
this.deps.getSessionManager().appendModelChange(nextModel.provider, nextModel.id);
|
|
174
|
+
this.deps.getSettingsManager().setDefaultModelAndProvider(nextModel.provider, nextModel.id);
|
|
175
|
+
// Re-clamp thinking level for new model's capabilities
|
|
176
|
+
this.setThinkingLevel(thinkingLevel);
|
|
177
|
+
await this._emitModelSelect(nextModel, currentModel, "cycle");
|
|
178
|
+
this.deps.checkContextWindowUsageWarning();
|
|
179
|
+
await this._warnIfManualModelChoiceIsRisky(nextModel);
|
|
180
|
+
return { model: nextModel, thinkingLevel: this.deps.getThinkingLevel(), isScoped: false };
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Set thinking level.
|
|
184
|
+
* Clamps to model capabilities based on available thinking levels.
|
|
185
|
+
* Saves to session and settings only if the level actually changes.
|
|
186
|
+
*/
|
|
187
|
+
setThinkingLevel(level, options = {}) {
|
|
188
|
+
const availableLevels = this.getAvailableThinkingLevels();
|
|
189
|
+
const effectiveLevel = availableLevels.includes(level) ? level : this._clampThinkingLevel(level, availableLevels);
|
|
190
|
+
// Only persist if actually changing
|
|
191
|
+
const previousLevel = this.deps.getAgent().state.thinkingLevel;
|
|
192
|
+
const isChanging = effectiveLevel !== previousLevel;
|
|
193
|
+
const persistSettings = options.persistSettings ?? true;
|
|
194
|
+
this.deps.getAgent().state.thinkingLevel = effectiveLevel;
|
|
195
|
+
if (isChanging) {
|
|
196
|
+
this.deps.getSessionManager().appendThinkingLevelChange(effectiveLevel);
|
|
197
|
+
if (persistSettings && (this.supportsThinking() || effectiveLevel !== "off")) {
|
|
198
|
+
this.deps.getSettingsManager().setDefaultThinkingLevel(effectiveLevel);
|
|
199
|
+
}
|
|
200
|
+
this.deps.emit({ type: "thinking_level_changed", level: effectiveLevel });
|
|
201
|
+
void this.deps.getExtensionRunner().emit({
|
|
202
|
+
type: "thinking_level_select",
|
|
203
|
+
level: effectiveLevel,
|
|
204
|
+
previousLevel,
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Cycle to next thinking level.
|
|
210
|
+
* @returns New level, or undefined if model doesn't support thinking
|
|
211
|
+
*/
|
|
212
|
+
cycleThinkingLevel() {
|
|
213
|
+
if (!this.supportsThinking())
|
|
214
|
+
return undefined;
|
|
215
|
+
const levels = this.getAvailableThinkingLevels();
|
|
216
|
+
const currentIndex = levels.indexOf(this.deps.getThinkingLevel());
|
|
217
|
+
const nextIndex = (currentIndex + 1) % levels.length;
|
|
218
|
+
const nextLevel = levels[nextIndex];
|
|
219
|
+
this.setThinkingLevel(nextLevel);
|
|
220
|
+
return nextLevel;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Get available thinking levels for current model.
|
|
224
|
+
* The provider will clamp to what the specific model supports internally.
|
|
225
|
+
*/
|
|
226
|
+
getAvailableThinkingLevels() {
|
|
227
|
+
const model = this.deps.getModel();
|
|
228
|
+
if (!model)
|
|
229
|
+
return THINKING_LEVELS;
|
|
230
|
+
return getSupportedThinkingLevels(model);
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Check if current model supports thinking/reasoning.
|
|
234
|
+
*/
|
|
235
|
+
supportsThinking() {
|
|
236
|
+
return !!this.deps.getModel()?.reasoning;
|
|
237
|
+
}
|
|
238
|
+
_getThinkingLevelForModelSwitch(explicitLevel) {
|
|
239
|
+
if (explicitLevel !== undefined) {
|
|
240
|
+
return explicitLevel;
|
|
241
|
+
}
|
|
242
|
+
if (!this.supportsThinking()) {
|
|
243
|
+
return this.deps.getSettingsManager().getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL;
|
|
244
|
+
}
|
|
245
|
+
return this.deps.getThinkingLevel();
|
|
246
|
+
}
|
|
247
|
+
_clampThinkingLevel(level, _availableLevels) {
|
|
248
|
+
const model = this.deps.getModel();
|
|
249
|
+
return model ? clampThinkingLevel(model, level) : "off";
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
//# sourceMappingURL=model-selection-controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-selection-controller.js","sourceRoot":"","sources":["../../src/core/model-selection-controller.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * User-facing model + thinking-level selection.\n *\n * Extracted verbatim from agent-session.ts (god-file decomposition). Owns the manual/explicit model\n * switch and cycle paths and the thinking-level set/cycle/clamp — the deliberate human choices, as\n * opposed to the per-turn auto-routing owned by ModelRouterController. It mutates `agent.state.model`\n * / `agent.state.thinkingLevel` through deps and re-derives the capability-scoped tool surface, but the\n * session keeps the `model`/`thinkingLevel` GETTERS so the drive loop's reads are untouched. Model\n * choice is advisory-only: it warns on a bad-fit fitness probe or an oversized local model, never blocks.\n */\n\nimport { totalmem } from \"node:os\";\nimport type { Agent, ThinkingLevel } from \"@caupulican/pi-agent-core\";\nimport type { SessionManager } from \"@caupulican/pi-agent-core/node\";\nimport type { Api, Model } from \"@caupulican/pi-ai\";\nimport { clampThinkingLevel, getSupportedThinkingLevels, modelsAreEqual } from \"@caupulican/pi-ai\";\nimport type { AgentSessionEvent, ModelCycleResult } from \"./agent-session.ts\";\nimport { DEFAULT_THINKING_LEVEL } from \"./defaults.ts\";\nimport type { ExtensionRunner } from \"./extensions/index.ts\";\nimport type { ModelCapabilityProfile } from \"./model-capability.ts\";\nimport type { ModelRegistry } from \"./model-registry.ts\";\nimport { FitnessStore } from \"./models/fitness-store.ts\";\nimport { OLLAMA_PROVIDER } from \"./models/local-registration.ts\";\nimport type { OllamaRuntime } from \"./models/local-runtime.ts\";\nimport { matchesInstalledLocalModel } from \"./models/model-ref.ts\";\nimport { isProbeAllFailed } from \"./research/model-fitness.ts\";\nimport type { SettingsManager } from \"./settings-manager.ts\";\n\n/** Standard thinking levels (fallback set when the current model is unknown). */\nconst THINKING_LEVELS: ThinkingLevel[] = [\"off\", \"minimal\", \"low\", \"medium\", \"high\"];\n\nexport interface ModelSelectionControllerDeps {\n\tgetAgent(): Agent;\n\tgetModel(): Model<any> | undefined;\n\tgetThinkingLevel(): ThinkingLevel;\n\tgetModelRegistry(): ModelRegistry;\n\tgetSessionManager(): SessionManager;\n\tgetSettingsManager(): SettingsManager;\n\tgetExtensionRunner(): ExtensionRunner;\n\tgetAgentDir(): string;\n\t/** Scoped models (--models flag), used by the cycle path. */\n\tgetScopedModels(): Array<{ model: Model<any>; thinkingLevel?: ThinkingLevel }>;\n\t/** The user-requested active tool set, re-applied when the model's capability class changes. */\n\tgetRequestedActiveToolNames(): string[] | undefined;\n\tgetActiveToolNames(): string[];\n\tsetActiveToolsByName(toolNames: string[]): void;\n\tgetModelCapabilityProfile(): ModelCapabilityProfile;\n\t/** Session event emit (warnings + thinking_level_changed; model_select goes via the extension runner). */\n\temit(event: AgentSessionEvent): void;\n\t/** Context-window-usage warning check (session-owned, compaction-adjacent). */\n\tcheckContextWindowUsageWarning(): void;\n\t/** Resolve the Ollama server URL for a model base URL (local-runtime controller). */\n\tderiveOllamaServerUrl(modelBaseUrl: string): string;\n\t/** Local Ollama runtime for the given server URL (used for the oversized-model risk check). */\n\tgetLocalRuntime(serverUrl: string): OllamaRuntime;\n}\n\nexport class ModelSelectionController {\n\tprivate readonly deps: ModelSelectionControllerDeps;\n\n\tconstructor(deps: ModelSelectionControllerDeps) {\n\t\tthis.deps = deps;\n\t}\n\n\tprivate async _emitModelSelect(\n\t\tnextModel: Model<any>,\n\t\tpreviousModel: Model<any> | undefined,\n\t\tsource: \"set\" | \"cycle\" | \"restore\",\n\t): Promise<void> {\n\t\tif (modelsAreEqual(previousModel, nextModel)) return;\n\t\tawait this.deps.getExtensionRunner().emit({\n\t\t\ttype: \"model_select\",\n\t\t\tmodel: nextModel,\n\t\t\tpreviousModel,\n\t\t\tsource,\n\t\t});\n\t}\n\n\t/**\n\t * Set model directly.\n\t * Validates that auth is configured, saves to session and settings.\n\t * @throws Error if no auth is configured for the model\n\t */\n\tasync setModel(model: Model<any>, options: { persistSettings?: boolean } = {}): Promise<void> {\n\t\tif (!this.deps.getModelRegistry().hasConfiguredAuth(model)) {\n\t\t\tthrow new Error(`No API key for ${model.provider}/${model.id}`);\n\t\t}\n\n\t\tconst persistSettings = options.persistSettings ?? true;\n\t\tconst previousModel = this.deps.getModel();\n\t\tconst thinkingLevel = this._getThinkingLevelForModelSwitch();\n\t\tthis.deps.getAgent().state.model = model;\n\t\tthis.deps.getSessionManager().appendModelChange(model.provider, model.id);\n\t\tif (persistSettings) {\n\t\t\tthis.deps.getSettingsManager().setDefaultModelAndProvider(model.provider, model.id);\n\t\t}\n\n\t\t// Re-clamp thinking level for new model's capabilities\n\t\tthis.setThinkingLevel(thinkingLevel, { persistSettings });\n\n\t\tawait this._emitModelSelect(model, previousModel, \"set\");\n\t\tthis.deps.checkContextWindowUsageWarning();\n\t\tawait this._warnIfManualModelChoiceIsRisky(model);\n\n\t\t// Re-derive the model-capability tool surface for the new model (restores the full requested\n\t\t// set when moving small -> large, reduces it when moving large -> small).\n\t\tconst requestedActiveToolNames = this.deps.getRequestedActiveToolNames();\n\t\tif (requestedActiveToolNames) {\n\t\t\tconst before = this.deps.getActiveToolNames().join(\",\");\n\t\t\tthis.deps.setActiveToolsByName(requestedActiveToolNames);\n\t\t\tconst capability = this.deps.getModelCapabilityProfile();\n\t\t\tif (capability.class !== \"full\" && this.deps.getActiveToolNames().join(\",\") !== before) {\n\t\t\t\tthis.deps.emit({\n\t\t\t\t\ttype: \"warning\",\n\t\t\t\t\tmessage: `Small-context model detected (${capability.contextWindow ?? \"unknown\"} tokens, class '${capability.class}'): active tools reduced to [${this.deps.getActiveToolNames().join(\", \")}]; background lanes ${capability.backgroundLanesEnabled ? \"enabled\" : \"disabled\"}.`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Manual model choice is a deliberate human decision, not an auto-adoption flow — it is\n\t * ADVISORY ONLY: warn on evidence the model is a bad fit, but never block and never prompt\n\t * (print/RPC modes only ever see plain warning text through the existing `warning` event, the\n\t * same channel `_checkContextWindowUsageWarning` above uses). Two independent checks, both\n\t * best-effort:\n\t * - a recorded all-lanes-failed fitness probe on THIS host (see `isProbeAllFailed`);\n\t * - for an Ollama-served local model, weights that exceed ~90% of total system memory, which\n\t * is the exact failure the OOM report reproduced (llama-server needs the whole model resident).\n\t */\n\tprivate async _warnIfManualModelChoiceIsRisky(model: Model<Api>): Promise<void> {\n\t\tconst canonicalRef = `${model.provider}/${model.id}`;\n\t\ttry {\n\t\t\tconst fitness = FitnessStore.forAgentDir(this.deps.getAgentDir())\n\t\t\t\t.getForHost()\n\t\t\t\t.find((entry) => entry.model === canonicalRef);\n\t\t\tif (fitness && isProbeAllFailed(fitness.report)) {\n\t\t\t\tthis.deps.emit({\n\t\t\t\t\ttype: \"warning\",\n\t\t\t\t\tmessage: `${canonicalRef} failed its fitness probe on all surfaces on this host (probed ${fitness.at}) — it is likely to fail in production too. Proceeding because you set it manually.`,\n\t\t\t\t});\n\t\t\t}\n\t\t} catch {\n\t\t\t// advisory only; a lookup failure must never block a manual model choice\n\t\t}\n\n\t\tif (model.provider !== OLLAMA_PROVIDER) return;\n\t\ttry {\n\t\t\tconst serverUrl = this.deps.deriveOllamaServerUrl(model.baseUrl);\n\t\t\tconst installed = await this.deps.getLocalRuntime(serverUrl).list();\n\t\t\tconst entry = installed.find((candidate) => matchesInstalledLocalModel(model.id, candidate.name));\n\t\t\tif (!entry) return;\n\t\t\tconst memoryBudget = totalmem() * 0.9;\n\t\t\tif (entry.sizeBytes > memoryBudget) {\n\t\t\t\tconst sizeGb = (entry.sizeBytes / 1e9).toFixed(1);\n\t\t\t\tconst totalGb = (totalmem() / 1e9).toFixed(1);\n\t\t\t\tthis.deps.emit({\n\t\t\t\t\ttype: \"warning\",\n\t\t\t\t\tmessage: `${canonicalRef} is ~${sizeGb}GB, over 90% of this machine's ${totalGb}GB RAM — llama-server is likely to OOM when it runs. Proceeding because you set it manually.`,\n\t\t\t\t});\n\t\t\t}\n\t\t} catch {\n\t\t\t// advisory only; an unreachable local server must never block a manual model choice\n\t\t}\n\t}\n\n\t/**\n\t * Cycle to next/previous model.\n\t * Uses scoped models (from --models flag) if available, otherwise all available models.\n\t * @param direction - \"forward\" (default) or \"backward\"\n\t * @returns The new model info, or undefined if only one model available\n\t */\n\tasync cycleModel(direction: \"forward\" | \"backward\" = \"forward\"): Promise<ModelCycleResult | undefined> {\n\t\tif (this.deps.getScopedModels().length > 0) {\n\t\t\treturn this._cycleScopedModel(direction);\n\t\t}\n\t\treturn this._cycleAvailableModel(direction);\n\t}\n\n\tprivate async _cycleScopedModel(direction: \"forward\" | \"backward\"): Promise<ModelCycleResult | undefined> {\n\t\tconst scopedModels = this.deps\n\t\t\t.getScopedModels()\n\t\t\t.filter((scoped) => this.deps.getModelRegistry().hasConfiguredAuth(scoped.model));\n\t\tif (scopedModels.length <= 1) return undefined;\n\n\t\tconst currentModel = this.deps.getModel();\n\t\tlet currentIndex = scopedModels.findIndex((sm) => modelsAreEqual(sm.model, currentModel));\n\n\t\tif (currentIndex === -1) currentIndex = 0;\n\t\tconst len = scopedModels.length;\n\t\tconst nextIndex = direction === \"forward\" ? (currentIndex + 1) % len : (currentIndex - 1 + len) % len;\n\t\tconst next = scopedModels[nextIndex];\n\t\tconst thinkingLevel = this._getThinkingLevelForModelSwitch(next.thinkingLevel);\n\n\t\t// Apply model\n\t\tthis.deps.getAgent().state.model = next.model;\n\t\tthis.deps.getSessionManager().appendModelChange(next.model.provider, next.model.id);\n\t\tthis.deps.getSettingsManager().setDefaultModelAndProvider(next.model.provider, next.model.id);\n\n\t\t// Apply thinking level.\n\t\t// - Explicit scoped model thinking level overrides current session level\n\t\t// - Undefined scoped model thinking level inherits the current session preference\n\t\t// setThinkingLevel clamps to model capabilities.\n\t\tthis.setThinkingLevel(thinkingLevel);\n\n\t\tawait this._emitModelSelect(next.model, currentModel, \"cycle\");\n\n\t\tthis.deps.checkContextWindowUsageWarning();\n\t\tawait this._warnIfManualModelChoiceIsRisky(next.model);\n\n\t\treturn { model: next.model, thinkingLevel: this.deps.getThinkingLevel(), isScoped: true };\n\t}\n\n\tprivate async _cycleAvailableModel(direction: \"forward\" | \"backward\"): Promise<ModelCycleResult | undefined> {\n\t\tconst availableModels = await this.deps.getModelRegistry().getAvailable();\n\t\tif (availableModels.length <= 1) return undefined;\n\n\t\tconst currentModel = this.deps.getModel();\n\t\tlet currentIndex = availableModels.findIndex((m) => modelsAreEqual(m, currentModel));\n\n\t\tif (currentIndex === -1) currentIndex = 0;\n\t\tconst len = availableModels.length;\n\t\tconst nextIndex = direction === \"forward\" ? (currentIndex + 1) % len : (currentIndex - 1 + len) % len;\n\t\tconst nextModel = availableModels[nextIndex];\n\n\t\tconst thinkingLevel = this._getThinkingLevelForModelSwitch();\n\t\tthis.deps.getAgent().state.model = nextModel;\n\t\tthis.deps.getSessionManager().appendModelChange(nextModel.provider, nextModel.id);\n\t\tthis.deps.getSettingsManager().setDefaultModelAndProvider(nextModel.provider, nextModel.id);\n\n\t\t// Re-clamp thinking level for new model's capabilities\n\t\tthis.setThinkingLevel(thinkingLevel);\n\n\t\tawait this._emitModelSelect(nextModel, currentModel, \"cycle\");\n\n\t\tthis.deps.checkContextWindowUsageWarning();\n\t\tawait this._warnIfManualModelChoiceIsRisky(nextModel);\n\n\t\treturn { model: nextModel, thinkingLevel: this.deps.getThinkingLevel(), isScoped: false };\n\t}\n\n\t/**\n\t * Set thinking level.\n\t * Clamps to model capabilities based on available thinking levels.\n\t * Saves to session and settings only if the level actually changes.\n\t */\n\tsetThinkingLevel(level: ThinkingLevel, options: { persistSettings?: boolean } = {}): void {\n\t\tconst availableLevels = this.getAvailableThinkingLevels();\n\t\tconst effectiveLevel = availableLevels.includes(level) ? level : this._clampThinkingLevel(level, availableLevels);\n\n\t\t// Only persist if actually changing\n\t\tconst previousLevel = this.deps.getAgent().state.thinkingLevel;\n\t\tconst isChanging = effectiveLevel !== previousLevel;\n\t\tconst persistSettings = options.persistSettings ?? true;\n\n\t\tthis.deps.getAgent().state.thinkingLevel = effectiveLevel;\n\n\t\tif (isChanging) {\n\t\t\tthis.deps.getSessionManager().appendThinkingLevelChange(effectiveLevel);\n\t\t\tif (persistSettings && (this.supportsThinking() || effectiveLevel !== \"off\")) {\n\t\t\t\tthis.deps.getSettingsManager().setDefaultThinkingLevel(effectiveLevel);\n\t\t\t}\n\t\t\tthis.deps.emit({ type: \"thinking_level_changed\", level: effectiveLevel });\n\t\t\tvoid this.deps.getExtensionRunner().emit({\n\t\t\t\ttype: \"thinking_level_select\",\n\t\t\t\tlevel: effectiveLevel,\n\t\t\t\tpreviousLevel,\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Cycle to next thinking level.\n\t * @returns New level, or undefined if model doesn't support thinking\n\t */\n\tcycleThinkingLevel(): ThinkingLevel | undefined {\n\t\tif (!this.supportsThinking()) return undefined;\n\n\t\tconst levels = this.getAvailableThinkingLevels();\n\t\tconst currentIndex = levels.indexOf(this.deps.getThinkingLevel());\n\t\tconst nextIndex = (currentIndex + 1) % levels.length;\n\t\tconst nextLevel = levels[nextIndex];\n\n\t\tthis.setThinkingLevel(nextLevel);\n\t\treturn nextLevel;\n\t}\n\n\t/**\n\t * Get available thinking levels for current model.\n\t * The provider will clamp to what the specific model supports internally.\n\t */\n\tgetAvailableThinkingLevels(): ThinkingLevel[] {\n\t\tconst model = this.deps.getModel();\n\t\tif (!model) return THINKING_LEVELS;\n\t\treturn getSupportedThinkingLevels(model) as ThinkingLevel[];\n\t}\n\n\t/**\n\t * Check if current model supports thinking/reasoning.\n\t */\n\tsupportsThinking(): boolean {\n\t\treturn !!this.deps.getModel()?.reasoning;\n\t}\n\n\tprivate _getThinkingLevelForModelSwitch(explicitLevel?: ThinkingLevel): ThinkingLevel {\n\t\tif (explicitLevel !== undefined) {\n\t\t\treturn explicitLevel;\n\t\t}\n\t\tif (!this.supportsThinking()) {\n\t\t\treturn this.deps.getSettingsManager().getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL;\n\t\t}\n\t\treturn this.deps.getThinkingLevel();\n\t}\n\n\tprivate _clampThinkingLevel(level: ThinkingLevel, _availableLevels: ThinkingLevel[]): ThinkingLevel {\n\t\tconst model = this.deps.getModel();\n\t\treturn model ? (clampThinkingLevel(model, level) as ThinkingLevel) : \"off\";\n\t}\n}\n"]}
|
|
@@ -16,4 +16,17 @@ export type ModelSource = {
|
|
|
16
16
|
reason: string;
|
|
17
17
|
};
|
|
18
18
|
export declare function normalizeModelSource(rawInput: string): ModelSource;
|
|
19
|
+
/**
|
|
20
|
+
* Whether an installed-model listing entry (`installedName`, as `OllamaRuntime.list()` reports it)
|
|
21
|
+
* is the same model as `ref` (a user-typed reference, or a `models.json`-registered id). Ollama
|
|
22
|
+
* always reports installed models with an explicit tag — a pull with no tag is normalized to
|
|
23
|
+
* `:latest` server-side — but a `ref` is frequently bare ("llama3"), so an exact string compare
|
|
24
|
+
* alone misses that pairing. Exact match always counts; otherwise treat a bare ref against its
|
|
25
|
+
* `:latest`-tagged listing as the same model, and the reverse (a `ref` explicitly pinned to
|
|
26
|
+
* `:latest` against a bare listing), since the local-runtime interface is kept runtime-agnostic
|
|
27
|
+
* (see local-runtime.ts's module docstring) and a future/alternate runtime could list bare names.
|
|
28
|
+
* Shared by every ref-vs-installed-list comparison — see `AgentSession._warnIfManualModelChoiceIsRisky`
|
|
29
|
+
* and `removeLocalModel` in interactive-mode.ts, which had the identical bug independently.
|
|
30
|
+
*/
|
|
31
|
+
export declare function matchesInstalledLocalModel(ref: string, installedName: string): boolean;
|
|
19
32
|
//# sourceMappingURL=model-ref.d.ts.map
|