@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,623 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model-router turn routing: the session's per-turn model-selection subsystem — the regex/executor
|
|
3
|
+
* route resolver, the optional bounded routing judge, the executor lane (Level-0 toolkit direct hit
|
|
4
|
+
* + speculative brain-refined retry), the per-tier thinking/tool-surface swap around a routed turn,
|
|
5
|
+
* the cheap-research-turn session buffer with mutating-tool escalation to an expensive retry, and
|
|
6
|
+
* the router status/diagnostics report.
|
|
7
|
+
*
|
|
8
|
+
* Extracted verbatim from agent-session.ts (god-file decomposition). Owns the transient per-turn
|
|
9
|
+
* route state — the active intent/route, the cheap-turn session buffer, the escalation-requested and
|
|
10
|
+
* retry-in-flight flags — and the sticky last-decision/last-skip-reason/last-intent used by the
|
|
11
|
+
* status report. Everything else it needs — the live agent + its state, the current model, the
|
|
12
|
+
* session/settings managers, the model registry, the agent dir, the reflection abort signal, the
|
|
13
|
+
* base system prompt, the isolated-completion primitive, spawned-usage accounting, the event/telemetry
|
|
14
|
+
* emitters, and the recently-extracted BackgroundLaneController (resolveLaneModel) / ContextPipeline
|
|
15
|
+
* (resolveCurationModelIfFit) collaborators — is reached through narrow deps accessors rather than the
|
|
16
|
+
* whole AgentSession.
|
|
17
|
+
*
|
|
18
|
+
* Drive-path boundary (deliberate): the actual agent.prompt()/continue() loop stays host-side in
|
|
19
|
+
* AgentSession._runAgentPrompt; this controller's parallel routed drive path ({@link runRoutedTurn})
|
|
20
|
+
* owns only the route decision/escalation/tier bookkeeping and delegates every agent turn back through
|
|
21
|
+
* {@link ModelRouterControllerDeps.runAgentPrompt}, so the drive-loop logic is never duplicated. The
|
|
22
|
+
* host keeps a one-line delegation at each call-in: the routing prep + routed-turn entry in
|
|
23
|
+
* _promptUnserialized, the beforeToolCall escalation branch ({@link maybeEscalateToolCall}), the
|
|
24
|
+
* message_end cheap-turn buffering ({@link captureSessionMessage}), the retry-event suppression
|
|
25
|
+
* ({@link isRetryInFlight}), and the public getModelRouterStatus / autonomy-telemetry reads.
|
|
26
|
+
*/
|
|
27
|
+
import { clampThinkingLevel, modelsAreEqual } from "@caupulican/pi-ai";
|
|
28
|
+
import { AUTONOMY_TELEMETRY_EVENT_TYPES } from "./autonomy/telemetry-events.js";
|
|
29
|
+
import { latestUserPromptText } from "./context-pipeline.js";
|
|
30
|
+
import { deriveModelCapabilityProfile, filterToolNamesForCapability } from "./model-capability.js";
|
|
31
|
+
import { resolveCliModel } from "./model-resolver.js";
|
|
32
|
+
import { collectModelRouterConfigDiagnostics } from "./model-router/config-diagnostics.js";
|
|
33
|
+
import { classifyExecutorTurn } from "./model-router/executor-route.js";
|
|
34
|
+
import { classifyModelRouterRoute } from "./model-router/intent-classifier.js";
|
|
35
|
+
import { ROUTE_JUDGE_MAX_OUTPUT_TOKENS, runRouteJudge } from "./model-router/route-judge.js";
|
|
36
|
+
import { bufferModelRouterSessionCustomMessage, bufferModelRouterSessionMessage, createModelRouterSessionBuffer, flushModelRouterSessionBuffer, } from "./model-router/session-buffer.js";
|
|
37
|
+
import { formatModelRouterStatus, getRecentModelRouterDecisions, MODEL_ROUTER_DECISION_CUSTOM_TYPE, } from "./model-router/status.js";
|
|
38
|
+
import { shouldEscalateModelRouterTool } from "./model-router/tool-escalation.js";
|
|
39
|
+
import { FitnessStore } from "./models/fitness-store.js";
|
|
40
|
+
import { buildReflexUserPrompt, parseReflexPlan, REFLEX_INTERPRETER_SYSTEM_PROMPT, } from "./toolkit/reflex-interpreter.js";
|
|
41
|
+
/** Canonical `provider/id` label for a routed/resolved model, as it appears in decisions and status. */
|
|
42
|
+
export function formatModelRouterModel(model) {
|
|
43
|
+
return `${model.provider}/${model.id}`;
|
|
44
|
+
}
|
|
45
|
+
function persistModelRouterDecision(sessionManager, decision) {
|
|
46
|
+
sessionManager.appendCustomEntry(MODEL_ROUTER_DECISION_CUSTOM_TYPE, decision);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Owns the model-router turn routing extracted from {@link AgentSession}. See the module header for the
|
|
50
|
+
* drive-path boundary that keeps the agent.prompt()/continue() loop host-side.
|
|
51
|
+
*/
|
|
52
|
+
export class ModelRouterController {
|
|
53
|
+
/** Active model-router intent for the current transient routed turn, if any. */
|
|
54
|
+
_activeModelRouterIntent;
|
|
55
|
+
_activeModelRouterRoute;
|
|
56
|
+
_modelRouterSessionBuffer;
|
|
57
|
+
_modelRouterEscalationRequested = false;
|
|
58
|
+
_isModelRouterRetry = false;
|
|
59
|
+
_lastModelRouterDecision;
|
|
60
|
+
_lastModelRouterSkipReason;
|
|
61
|
+
_lastModelRouterIntent;
|
|
62
|
+
deps;
|
|
63
|
+
constructor(deps) {
|
|
64
|
+
this.deps = deps;
|
|
65
|
+
}
|
|
66
|
+
/** True while the escalation retry turn is running, so the host can suppress its duplicate prompt events. */
|
|
67
|
+
isRetryInFlight() {
|
|
68
|
+
return this._isModelRouterRetry;
|
|
69
|
+
}
|
|
70
|
+
/** Latest completed route decision (sticky), for the autonomy telemetry snapshot. */
|
|
71
|
+
getLastDecision() {
|
|
72
|
+
return this._lastModelRouterDecision;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* beforeToolCall escalation gate: a cheap research turn that reaches for a mutating tool aborts the
|
|
76
|
+
* turn and requests a retry on the expensive model. Returns the block result the host hook forwards,
|
|
77
|
+
* or undefined when no escalation is required.
|
|
78
|
+
*/
|
|
79
|
+
maybeEscalateToolCall(toolName, args) {
|
|
80
|
+
if (this._activeModelRouterRoute &&
|
|
81
|
+
shouldEscalateModelRouterTool({
|
|
82
|
+
tier: this._activeModelRouterRoute.tier,
|
|
83
|
+
toolName,
|
|
84
|
+
args,
|
|
85
|
+
reasonCode: this._activeModelRouterRoute.reasonCode,
|
|
86
|
+
})) {
|
|
87
|
+
this._modelRouterEscalationRequested = true;
|
|
88
|
+
this.deps.getAgent().abort();
|
|
89
|
+
return {
|
|
90
|
+
block: true,
|
|
91
|
+
reason: "Model router escalation required: a cheap research turn attempted a mutating tool. Retry the turn on the configured expensive model.",
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* message_end hook: while a cheap routed turn is buffering, capture its messages into the session
|
|
98
|
+
* buffer instead of persisting them (they are flushed on success or discarded on escalation).
|
|
99
|
+
* Returns true when the message was buffered, so the host skips its own persistence.
|
|
100
|
+
*/
|
|
101
|
+
captureSessionMessage(message) {
|
|
102
|
+
const modelRouterBuffer = this._modelRouterSessionBuffer;
|
|
103
|
+
if (!modelRouterBuffer)
|
|
104
|
+
return false;
|
|
105
|
+
if (message.role === "custom") {
|
|
106
|
+
bufferModelRouterSessionCustomMessage(modelRouterBuffer, message);
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
if (message.role === "user" || message.role === "assistant" || message.role === "toolResult") {
|
|
110
|
+
bufferModelRouterSessionMessage(modelRouterBuffer, message);
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
_isModelAvailableAndAuthed(pattern) {
|
|
116
|
+
const resolved = resolveCliModel({ cliModel: pattern, modelRegistry: this.deps.getModelRegistry() });
|
|
117
|
+
if (!resolved.model)
|
|
118
|
+
return false;
|
|
119
|
+
return this.deps.getModelRegistry().hasConfiguredAuth(resolved.model);
|
|
120
|
+
}
|
|
121
|
+
_resolveExecutorRoute(prompt, executorPattern) {
|
|
122
|
+
if (!executorPattern)
|
|
123
|
+
return undefined;
|
|
124
|
+
try {
|
|
125
|
+
const verdict = classifyExecutorTurn(prompt, this.deps.getSettingsManager().getToolkitScripts());
|
|
126
|
+
if (!verdict.execute)
|
|
127
|
+
return undefined;
|
|
128
|
+
const resolved = resolveCliModel({ cliModel: executorPattern, modelRegistry: this.deps.getModelRegistry() });
|
|
129
|
+
if (!resolved.model || !this.deps.getModelRegistry().hasConfiguredAuth(resolved.model))
|
|
130
|
+
return undefined;
|
|
131
|
+
// Fitness gate: the executor must have PROVEN tool-calling on this host (same
|
|
132
|
+
// canonical-ref discipline as the curation gate).
|
|
133
|
+
const canonicalRef = `${resolved.model.provider}/${resolved.model.id}`;
|
|
134
|
+
const fitness = FitnessStore.forAgentDir(this.deps.getAgentDir())
|
|
135
|
+
.getForHost()
|
|
136
|
+
.find((entry) => entry.model === canonicalRef);
|
|
137
|
+
const toolCall = fitness?.report.toolCall;
|
|
138
|
+
if (!toolCall || toolCall.succeeded < Math.ceil(toolCall.total * (2 / 3)))
|
|
139
|
+
return undefined;
|
|
140
|
+
this._lastModelRouterIntent = "research";
|
|
141
|
+
return {
|
|
142
|
+
decision: {
|
|
143
|
+
tier: "cheap",
|
|
144
|
+
risk: "scoped-write",
|
|
145
|
+
confidence: 1,
|
|
146
|
+
reasonCode: "executor_direct",
|
|
147
|
+
reasons: [`Executor lane: Level-0 direct hit on toolkit script "${verdict.scriptName}"`],
|
|
148
|
+
},
|
|
149
|
+
model: resolved.model,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
return undefined;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/** True if a run_toolkit_script tool result since `fromIndex` actually EXECUTED (not error/ambiguous). */
|
|
157
|
+
_executorTurnExecutedScript(fromIndex) {
|
|
158
|
+
for (const message of this.deps.getAgent().state.messages.slice(fromIndex)) {
|
|
159
|
+
if (message.role !== "toolResult")
|
|
160
|
+
continue;
|
|
161
|
+
if (message.toolName !== "run_toolkit_script")
|
|
162
|
+
continue;
|
|
163
|
+
if (message.isError === true)
|
|
164
|
+
continue;
|
|
165
|
+
const outcome = message.details?.outcome;
|
|
166
|
+
if (outcome === "executed")
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
/** Ask the reflex brain to refine the last user request into an explicit toolkit instruction. */
|
|
172
|
+
async _buildExecutorRefinedPrompt(messages) {
|
|
173
|
+
try {
|
|
174
|
+
const model = this.deps.resolveCurationModelIfFit();
|
|
175
|
+
if (!model)
|
|
176
|
+
return undefined;
|
|
177
|
+
const list = Array.isArray(messages) ? messages : [messages];
|
|
178
|
+
const request = latestUserPromptText(list.filter((m) => true));
|
|
179
|
+
if (!request)
|
|
180
|
+
return undefined;
|
|
181
|
+
const scripts = this.deps.getSettingsManager().getToolkitScripts();
|
|
182
|
+
const completion = await this.deps.runIsolatedCompletion({
|
|
183
|
+
systemPrompt: REFLEX_INTERPRETER_SYSTEM_PROMPT,
|
|
184
|
+
messages: [
|
|
185
|
+
{
|
|
186
|
+
role: "user",
|
|
187
|
+
content: [{ type: "text", text: buildReflexUserPrompt(request, scripts) }],
|
|
188
|
+
timestamp: Date.now(),
|
|
189
|
+
},
|
|
190
|
+
],
|
|
191
|
+
model,
|
|
192
|
+
thinkingLevel: "off",
|
|
193
|
+
maxTokens: 256,
|
|
194
|
+
cacheRetention: "short",
|
|
195
|
+
});
|
|
196
|
+
if (completion.usage.cost.total > 0 || completion.usage.totalTokens > 0) {
|
|
197
|
+
this.deps.addSpawnedUsage(completion.usage, { label: "executor-brain-warmup" });
|
|
198
|
+
}
|
|
199
|
+
const plan = parseReflexPlan(completion.text);
|
|
200
|
+
if (!plan || plan.script === "none")
|
|
201
|
+
return undefined;
|
|
202
|
+
const argHint = plan.args.length > 0 ? ` with args ${JSON.stringify(plan.args)}` : "";
|
|
203
|
+
return `Run the toolkit script "${plan.script}"${argHint} using run_toolkit_script, then report its result exactly.`;
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
return undefined;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
_resolveModelRouterTurnRoute(prompt) {
|
|
210
|
+
const settings = this.deps.getSettingsManager().getModelRouterSettings();
|
|
211
|
+
if (!settings.enabled) {
|
|
212
|
+
this._lastModelRouterSkipReason = "disabled";
|
|
213
|
+
return undefined;
|
|
214
|
+
}
|
|
215
|
+
// G16 executor lane: a Level-0 DIRECT toolkit hit on a command-shaped prompt routes the
|
|
216
|
+
// whole turn to the configured local executor (tool-call-fitness-gated) instead of
|
|
217
|
+
// spending the frontier model on a one-tool reflex. Ambiguity never routes here — it
|
|
218
|
+
// stays with the big model and the reflex brain. Deterministic, so the judge is skipped.
|
|
219
|
+
const executorRoute = this._resolveExecutorRoute(prompt, settings.executorModel);
|
|
220
|
+
if (executorRoute)
|
|
221
|
+
return executorRoute;
|
|
222
|
+
const decision = classifyModelRouterRoute(prompt);
|
|
223
|
+
this._lastModelRouterIntent = decision.tier === "cheap" ? "research" : "modify";
|
|
224
|
+
// Learning tier must not be selected for normal user prompts
|
|
225
|
+
if (decision.tier === "learning") {
|
|
226
|
+
this._lastModelRouterSkipReason = "learning tier not supported for user prompts";
|
|
227
|
+
return undefined;
|
|
228
|
+
}
|
|
229
|
+
const modelPattern = settings[decision.tier === "cheap" ? "cheapModel" : decision.tier === "medium" ? "mediumModel" : "expensiveModel"];
|
|
230
|
+
const label = decision.tier === "cheap" ? "cheap model" : decision.tier === "medium" ? "medium model" : "expensive model";
|
|
231
|
+
if (decision.tier === "medium" && (!modelPattern || !this._isModelAvailableAndAuthed(modelPattern))) {
|
|
232
|
+
const expensivePattern = settings.expensiveModel;
|
|
233
|
+
if (expensivePattern && this._isModelAvailableAndAuthed(expensivePattern)) {
|
|
234
|
+
const resolvedExpensive = resolveCliModel({
|
|
235
|
+
cliModel: expensivePattern,
|
|
236
|
+
modelRegistry: this.deps.getModelRegistry(),
|
|
237
|
+
});
|
|
238
|
+
if (resolvedExpensive.model) {
|
|
239
|
+
decision.fallbackFrom = "medium";
|
|
240
|
+
decision.tier = "expensive";
|
|
241
|
+
decision.reasonCode = "medium_unavailable_fallback_expensive";
|
|
242
|
+
decision.reasons = [...decision.reasons, "Medium model is unavailable, falling back to expensive model"];
|
|
243
|
+
decision.model = formatModelRouterModel(resolvedExpensive.model);
|
|
244
|
+
this._lastModelRouterSkipReason = undefined;
|
|
245
|
+
return { decision, model: resolvedExpensive.model };
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
this._lastModelRouterSkipReason = "medium model and expensive fallback are unavailable";
|
|
249
|
+
return undefined;
|
|
250
|
+
}
|
|
251
|
+
if (!modelPattern) {
|
|
252
|
+
this._lastModelRouterSkipReason = `${label} unset`;
|
|
253
|
+
return undefined;
|
|
254
|
+
}
|
|
255
|
+
const resolved = resolveCliModel({ cliModel: modelPattern, modelRegistry: this.deps.getModelRegistry() });
|
|
256
|
+
if (!resolved.model) {
|
|
257
|
+
this._lastModelRouterSkipReason = `${label} unresolved: ${modelPattern}`;
|
|
258
|
+
return undefined;
|
|
259
|
+
}
|
|
260
|
+
const resolvedName = formatModelRouterModel(resolved.model);
|
|
261
|
+
if (!this.deps.getModelRegistry().hasConfiguredAuth(resolved.model)) {
|
|
262
|
+
this._lastModelRouterSkipReason = `${label} missing auth: ${resolvedName}`;
|
|
263
|
+
return undefined;
|
|
264
|
+
}
|
|
265
|
+
this._lastModelRouterSkipReason = undefined;
|
|
266
|
+
decision.model = resolvedName;
|
|
267
|
+
return { decision, model: resolved.model };
|
|
268
|
+
}
|
|
269
|
+
_resolveModelRouterModelForIntent(intent) {
|
|
270
|
+
const settings = this.deps.getSettingsManager().getModelRouterSettings();
|
|
271
|
+
const modelPattern = intent === "research" ? settings.cheapModel : settings.expensiveModel;
|
|
272
|
+
if (!modelPattern)
|
|
273
|
+
return undefined;
|
|
274
|
+
const resolved = resolveCliModel({ cliModel: modelPattern, modelRegistry: this.deps.getModelRegistry() });
|
|
275
|
+
if (!resolved.model)
|
|
276
|
+
return undefined;
|
|
277
|
+
if (!this.deps.getModelRegistry().hasConfiguredAuth(resolved.model))
|
|
278
|
+
return undefined;
|
|
279
|
+
return resolved.model;
|
|
280
|
+
}
|
|
281
|
+
resolveConfiguredTierModel(tier) {
|
|
282
|
+
const settings = this.deps.getSettingsManager().getModelRouterSettings();
|
|
283
|
+
const pattern = tier === "cheap" ? settings.cheapModel : tier === "medium" ? settings.mediumModel : settings.expensiveModel;
|
|
284
|
+
if (!pattern)
|
|
285
|
+
return undefined;
|
|
286
|
+
const resolved = resolveCliModel({ cliModel: pattern, modelRegistry: this.deps.getModelRegistry() });
|
|
287
|
+
if (!resolved.model)
|
|
288
|
+
return undefined;
|
|
289
|
+
if (!this.deps.getModelRegistry().hasConfiguredAuth(resolved.model))
|
|
290
|
+
return undefined;
|
|
291
|
+
return resolved.model;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Router resolution with the routing judge (auto-on with the router): the regex classifier's
|
|
295
|
+
* decision is the baseline; when a judge model resolves (judgeModel, else mediumModel), one
|
|
296
|
+
* bounded, tool-less completion may move the tier between cheap/medium/expensive — never to
|
|
297
|
+
* learning. Core rule encoded in the judge prompt: planning is never cheap unless genuinely
|
|
298
|
+
* trivial. Every fallback stays visible in the decision reasons, and judge spend reports
|
|
299
|
+
* through spawned-usage accounting.
|
|
300
|
+
*/
|
|
301
|
+
async resolveTurnRouteJudged(prompt, options) {
|
|
302
|
+
const baseline = this._resolveModelRouterTurnRoute(prompt);
|
|
303
|
+
if (!baseline)
|
|
304
|
+
return undefined;
|
|
305
|
+
if (options?.skipJudge)
|
|
306
|
+
return baseline;
|
|
307
|
+
// Deterministic executor routes need no judge (Level-0 already decided).
|
|
308
|
+
if (baseline.decision.reasonCode === "executor_direct")
|
|
309
|
+
return baseline;
|
|
310
|
+
const settings = this.deps.getSettingsManager().getModelRouterSettings();
|
|
311
|
+
if (!settings.judgeEnabled)
|
|
312
|
+
return baseline;
|
|
313
|
+
const judgePattern = settings.judgeModel ?? settings.mediumModel;
|
|
314
|
+
if (!judgePattern)
|
|
315
|
+
return baseline;
|
|
316
|
+
const judgeModel = this.deps.resolveLaneModel(judgePattern);
|
|
317
|
+
if (!judgeModel)
|
|
318
|
+
return baseline;
|
|
319
|
+
let spentUsage;
|
|
320
|
+
const judged = await runRouteJudge({
|
|
321
|
+
prompt,
|
|
322
|
+
baseline: baseline.decision,
|
|
323
|
+
signal: this.deps.getReflectionSignal(),
|
|
324
|
+
complete: async ({ systemPrompt, userPrompt, signal }) => {
|
|
325
|
+
const completion = await this.deps.runIsolatedCompletion({
|
|
326
|
+
systemPrompt,
|
|
327
|
+
messages: [{ role: "user", content: [{ type: "text", text: userPrompt }], timestamp: Date.now() }],
|
|
328
|
+
model: judgeModel,
|
|
329
|
+
// Per-tier thinking (R1): judgeThinking overrides the judge's own completion; unset
|
|
330
|
+
// keeps today's "off" (the judge is a cheap classification call by default).
|
|
331
|
+
thinkingLevel: settings.judgeThinking ?? "off",
|
|
332
|
+
maxTokens: ROUTE_JUDGE_MAX_OUTPUT_TOKENS,
|
|
333
|
+
signal,
|
|
334
|
+
// The judge system prompt is static — the provider can cache the prefix.
|
|
335
|
+
cacheRetention: "short",
|
|
336
|
+
});
|
|
337
|
+
spentUsage = completion.usage;
|
|
338
|
+
return {
|
|
339
|
+
text: completion.text,
|
|
340
|
+
costUsd: completion.usage.cost.total,
|
|
341
|
+
stopReason: String(completion.stopReason),
|
|
342
|
+
};
|
|
343
|
+
},
|
|
344
|
+
});
|
|
345
|
+
if (spentUsage && (spentUsage.cost.total > 0 || spentUsage.totalTokens > 0)) {
|
|
346
|
+
this.deps.addSpawnedUsage(spentUsage, { label: "router-judge" });
|
|
347
|
+
}
|
|
348
|
+
if (!judged.verdict || judged.decision.tier === baseline.decision.tier) {
|
|
349
|
+
// Same tier (or judge fell back): keep the baseline model, carry the annotated decision.
|
|
350
|
+
return { decision: judged.decision, model: baseline.model };
|
|
351
|
+
}
|
|
352
|
+
const judgedTier = judged.decision.tier;
|
|
353
|
+
if (judgedTier !== "cheap" && judgedTier !== "medium" && judgedTier !== "expensive") {
|
|
354
|
+
return { decision: baseline.decision, model: baseline.model };
|
|
355
|
+
}
|
|
356
|
+
const judgedModel = this.resolveConfiguredTierModel(judgedTier);
|
|
357
|
+
if (!judgedModel) {
|
|
358
|
+
return {
|
|
359
|
+
decision: {
|
|
360
|
+
...baseline.decision,
|
|
361
|
+
reasons: [
|
|
362
|
+
...baseline.decision.reasons,
|
|
363
|
+
`Route judge chose ${judgedTier} but no model resolves for that tier; baseline kept`,
|
|
364
|
+
],
|
|
365
|
+
},
|
|
366
|
+
model: baseline.model,
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
return { decision: { ...judged.decision, model: formatModelRouterModel(judgedModel) }, model: judgedModel };
|
|
370
|
+
}
|
|
371
|
+
// biome-ignore lint/correctness/noUnusedPrivateClassMembers: test seam
|
|
372
|
+
_resolveModelRouterTurnModel(prompt) {
|
|
373
|
+
const resolved = this._resolveModelRouterTurnRoute(prompt);
|
|
374
|
+
return resolved?.model;
|
|
375
|
+
}
|
|
376
|
+
getStatus(formatLabel) {
|
|
377
|
+
const recentDecisions = getRecentModelRouterDecisions(this.deps.getSessionManager().getEntries());
|
|
378
|
+
const lastDecision = this._lastModelRouterDecision ?? recentDecisions.at(-1);
|
|
379
|
+
const historicalDecisions = this._lastModelRouterDecision ? recentDecisions : recentDecisions.slice(0, -1);
|
|
380
|
+
const settings = this.deps.getSettingsManager().getModelRouterSettings();
|
|
381
|
+
const lines = [
|
|
382
|
+
formatModelRouterStatus(settings, lastDecision, formatLabel, historicalDecisions, this._lastModelRouterSkipReason, this._lastModelRouterIntent ?? lastDecision?.intent),
|
|
383
|
+
];
|
|
384
|
+
const diagnostics = collectModelRouterConfigDiagnostics(settings, this.deps.getModelRegistry());
|
|
385
|
+
if (diagnostics.length > 0) {
|
|
386
|
+
lines.push(formatLabel ? formatLabel("Config diagnostics:") : "Config diagnostics:");
|
|
387
|
+
for (const diagnostic of diagnostics) {
|
|
388
|
+
lines.push(`- ${diagnostic}`);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
return lines.join("\n");
|
|
392
|
+
}
|
|
393
|
+
async runRoutedTurn(messages, routedModel, routeDecision, persistDecision = true) {
|
|
394
|
+
if (!routedModel) {
|
|
395
|
+
await this.deps.runAgentPrompt(messages);
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
const agent = this.deps.getAgent();
|
|
399
|
+
const previousModel = agent.state.model;
|
|
400
|
+
const previousThinkingLevel = agent.state.thinkingLevel;
|
|
401
|
+
const previousTurnTools = agent.state.tools;
|
|
402
|
+
const previousSystemPrompt = agent.state.systemPrompt;
|
|
403
|
+
// G4 swap bookkeeping (Bug G): the exact references the swap below assigns, so the finally can
|
|
404
|
+
// restore ONLY what IT put there — never assigned when no swap happens (e.g. a full-class
|
|
405
|
+
// routed profile).
|
|
406
|
+
let swappedTools;
|
|
407
|
+
let swappedSystemPrompt;
|
|
408
|
+
const previousActiveModelRouterIntent = this._activeModelRouterIntent;
|
|
409
|
+
const previousActiveModelRouterRoute = this._activeModelRouterRoute;
|
|
410
|
+
const previousModelRouterSessionBuffer = this._modelRouterSessionBuffer;
|
|
411
|
+
const previousModelRouterEscalationRequested = this._modelRouterEscalationRequested;
|
|
412
|
+
const bufferRoutedTurn = routeDecision?.tier === "cheap";
|
|
413
|
+
const originalHistoryLength = agent.state.messages.length;
|
|
414
|
+
let retryModel;
|
|
415
|
+
let completedDecision = routeDecision
|
|
416
|
+
? {
|
|
417
|
+
route: routeDecision,
|
|
418
|
+
routedModel: formatModelRouterModel(routedModel),
|
|
419
|
+
outcome: "routed",
|
|
420
|
+
intent: routeDecision.tier === "cheap" ? "research" : "modify",
|
|
421
|
+
}
|
|
422
|
+
: undefined;
|
|
423
|
+
let thrownError;
|
|
424
|
+
if (routeDecision) {
|
|
425
|
+
this._lastModelRouterDecision = completedDecision;
|
|
426
|
+
}
|
|
427
|
+
this._activeModelRouterIntent = routeDecision
|
|
428
|
+
? routeDecision.tier === "cheap"
|
|
429
|
+
? "research"
|
|
430
|
+
: "modify"
|
|
431
|
+
: undefined;
|
|
432
|
+
this._activeModelRouterRoute = routeDecision;
|
|
433
|
+
if (bufferRoutedTurn) {
|
|
434
|
+
this._modelRouterSessionBuffer = createModelRouterSessionBuffer();
|
|
435
|
+
this._modelRouterEscalationRequested = false;
|
|
436
|
+
}
|
|
437
|
+
if (!modelsAreEqual(this.deps.getModel(), routedModel)) {
|
|
438
|
+
agent.state.model = routedModel;
|
|
439
|
+
// Per-tier thinking (R1): a configured tier/executor thinking level overrides the inherited
|
|
440
|
+
// session thinking for THIS routed turn only; unset falls back to exactly today's
|
|
441
|
+
// inherit-and-clamp behavior. Executor routes carry tier "cheap" too, so reasonCode is
|
|
442
|
+
// checked first — otherwise an executor turn would silently pick up cheapThinking instead.
|
|
443
|
+
// The judge's own completion has a separate knob (judgeThinking) applied at its call site.
|
|
444
|
+
const routerThinkingSettings = this.deps.getSettingsManager().getModelRouterSettings();
|
|
445
|
+
const configuredThinking = !routeDecision
|
|
446
|
+
? undefined
|
|
447
|
+
: routeDecision.reasonCode === "executor_direct"
|
|
448
|
+
? routerThinkingSettings.executorThinking
|
|
449
|
+
: routeDecision.tier === "cheap"
|
|
450
|
+
? routerThinkingSettings.cheapThinking
|
|
451
|
+
: routeDecision.tier === "medium"
|
|
452
|
+
? routerThinkingSettings.mediumThinking
|
|
453
|
+
: routeDecision.tier === "expensive"
|
|
454
|
+
? routerThinkingSettings.expensiveThinking
|
|
455
|
+
: undefined;
|
|
456
|
+
agent.state.thinkingLevel = clampThinkingLevel(routedModel, configuredThinking ?? previousThinkingLevel);
|
|
457
|
+
// G4: capability tool-filtering follows the ROUTED model for the turn. Without this a
|
|
458
|
+
// cheap/local routed model inherits the session model's full tool surface — schemas it
|
|
459
|
+
// pays for on every request and may not be able to drive at all.
|
|
460
|
+
const routedProfile = deriveModelCapabilityProfile({
|
|
461
|
+
contextWindow: routedModel.contextWindow,
|
|
462
|
+
mode: this.deps.getSettingsManager().getModelCapabilitySettings().mode,
|
|
463
|
+
});
|
|
464
|
+
if (routedProfile.class !== "full") {
|
|
465
|
+
const allowed = new Set(filterToolNamesForCapability(previousTurnTools.map((tool) => tool.name), routedProfile));
|
|
466
|
+
swappedTools = previousTurnTools.filter((tool) => allowed.has(tool.name));
|
|
467
|
+
agent.state.tools = swappedTools;
|
|
468
|
+
// G4: the system prompt follows the ROUTED model's filtered surface too — otherwise the
|
|
469
|
+
// cheap/local model is billed for (and told about) tool guidelines/snippets it can't call.
|
|
470
|
+
// Per-turn only; restored in the finally. A live extension override of the prompt is left
|
|
471
|
+
// alone (only shed when we're on the base prompt).
|
|
472
|
+
if (agent.state.systemPrompt === this.deps.getBaseSystemPrompt()) {
|
|
473
|
+
swappedSystemPrompt = this.deps.buildSystemPromptForToolNames(agent.state.tools.map((tool) => tool.name));
|
|
474
|
+
agent.state.systemPrompt = swappedSystemPrompt;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
try {
|
|
479
|
+
await this.deps.runAgentPrompt(messages);
|
|
480
|
+
// Speculative muscle-retry (G16 refinement): an executor-routed turn is a bet that the
|
|
481
|
+
// small model can run the toolkit command directly. If it ends WITHOUT a successful
|
|
482
|
+
// run_toolkit_script execution, retry ONCE on the same executor with the brain's
|
|
483
|
+
// refined instruction injected — the brain warms while the muscle tries, so the retry
|
|
484
|
+
// pays only when the muscle actually missed.
|
|
485
|
+
if (routeDecision?.reasonCode === "executor_direct" &&
|
|
486
|
+
!this._isModelRouterRetry &&
|
|
487
|
+
!this._executorTurnExecutedScript(originalHistoryLength)) {
|
|
488
|
+
const refined = await this._buildExecutorRefinedPrompt(messages);
|
|
489
|
+
if (refined) {
|
|
490
|
+
agent.state.messages.splice(originalHistoryLength);
|
|
491
|
+
await this.deps.runAgentPrompt([
|
|
492
|
+
{ role: "user", content: [{ type: "text", text: refined }], timestamp: Date.now() },
|
|
493
|
+
]);
|
|
494
|
+
completedDecision = {
|
|
495
|
+
route: {
|
|
496
|
+
...routeDecision,
|
|
497
|
+
reasonCode: "executor_speculative_retry",
|
|
498
|
+
reasons: [
|
|
499
|
+
...routeDecision.reasons,
|
|
500
|
+
"Executor missed on first try; retried with brain-refined instruction",
|
|
501
|
+
],
|
|
502
|
+
},
|
|
503
|
+
routedModel: formatModelRouterModel(routedModel),
|
|
504
|
+
outcome: "routed",
|
|
505
|
+
intent: "research",
|
|
506
|
+
};
|
|
507
|
+
this._lastModelRouterDecision = completedDecision;
|
|
508
|
+
}
|
|
509
|
+
else {
|
|
510
|
+
// The muscle missed AND the reflex brain could not refine the request into a toolkit
|
|
511
|
+
// instruction (no fit brain model, or no confident plan). There is deliberately NO
|
|
512
|
+
// frontier fallback here, so surface the miss instead of letting it stand silently —
|
|
513
|
+
// otherwise the routed turn just ends with an unrun command and no explanation.
|
|
514
|
+
this.deps.emit({
|
|
515
|
+
type: "warning",
|
|
516
|
+
message: "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).",
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
if (bufferRoutedTurn && this._modelRouterEscalationRequested) {
|
|
521
|
+
agent.state.messages.splice(originalHistoryLength);
|
|
522
|
+
retryModel = this._resolveModelRouterModelForIntent("modify") ?? previousModel;
|
|
523
|
+
completedDecision = {
|
|
524
|
+
route: routeDecision,
|
|
525
|
+
routedModel: formatModelRouterModel(routedModel),
|
|
526
|
+
outcome: "escalated",
|
|
527
|
+
retryModel: formatModelRouterModel(retryModel),
|
|
528
|
+
intent: routeDecision.tier === "cheap" ? "research" : "modify",
|
|
529
|
+
};
|
|
530
|
+
this._lastModelRouterDecision = completedDecision;
|
|
531
|
+
}
|
|
532
|
+
else if (bufferRoutedTurn && this._modelRouterSessionBuffer) {
|
|
533
|
+
flushModelRouterSessionBuffer(this._modelRouterSessionBuffer, (message) => {
|
|
534
|
+
this.deps.getSessionManager().appendMessage(message);
|
|
535
|
+
}, (customType, content, display, details) => {
|
|
536
|
+
this.deps.getSessionManager().appendCustomMessageEntry(customType, content, display, details);
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
catch (error) {
|
|
541
|
+
thrownError = error;
|
|
542
|
+
if (completedDecision) {
|
|
543
|
+
completedDecision = { ...completedDecision, outcome: "failed" };
|
|
544
|
+
this._lastModelRouterDecision = completedDecision;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
finally {
|
|
548
|
+
// Restore the pre-route model ONLY if the routed model is still in place: a command
|
|
549
|
+
// handler may have legitimately changed the session model mid-turn (setModel or a
|
|
550
|
+
// provider re-registration), and clobbering that would silently undo the change.
|
|
551
|
+
if (modelsAreEqual(agent.state.model, routedModel)) {
|
|
552
|
+
agent.state.model = previousModel;
|
|
553
|
+
agent.state.thinkingLevel = previousThinkingLevel;
|
|
554
|
+
// Symmetric restore (Bug G): undo tools/systemPrompt only if each is STILL the exact
|
|
555
|
+
// reference/string the G4 swap above assigned (never assigned at all when the routed
|
|
556
|
+
// profile was full-class — then there is nothing to restore either). An extension calling
|
|
557
|
+
// setActiveToolsByName mid-turn reassigns both to its own values without touching the
|
|
558
|
+
// model — the model guard above still passes, but that live change is legitimate and must
|
|
559
|
+
// survive rather than being silently reverted to the stale pre-turn snapshot.
|
|
560
|
+
if (swappedTools !== undefined && agent.state.tools === swappedTools) {
|
|
561
|
+
agent.state.tools = previousTurnTools;
|
|
562
|
+
}
|
|
563
|
+
if (swappedSystemPrompt !== undefined && agent.state.systemPrompt === swappedSystemPrompt) {
|
|
564
|
+
agent.state.systemPrompt = previousSystemPrompt;
|
|
565
|
+
}
|
|
566
|
+
// The registry may have changed mid-turn (command-time registerProvider): re-resolve
|
|
567
|
+
// the restored model so a provider override is not dropped with the routed model.
|
|
568
|
+
this.deps.refreshCurrentModelFromRegistry();
|
|
569
|
+
}
|
|
570
|
+
this._activeModelRouterIntent = previousActiveModelRouterIntent;
|
|
571
|
+
this._activeModelRouterRoute = previousActiveModelRouterRoute;
|
|
572
|
+
this._modelRouterSessionBuffer = previousModelRouterSessionBuffer;
|
|
573
|
+
this._modelRouterEscalationRequested = previousModelRouterEscalationRequested;
|
|
574
|
+
}
|
|
575
|
+
if (retryModel && !thrownError) {
|
|
576
|
+
const previousIsModelRouterRetry = this._isModelRouterRetry;
|
|
577
|
+
try {
|
|
578
|
+
this._isModelRouterRetry = true;
|
|
579
|
+
const retryDecision = {
|
|
580
|
+
tier: "expensive",
|
|
581
|
+
risk: "high-impact",
|
|
582
|
+
confidence: 1.0,
|
|
583
|
+
reasonCode: "cheap_mutating_tool_escalation",
|
|
584
|
+
reasons: ["Cheap research turn attempted a mutating tool and escalated"],
|
|
585
|
+
fallbackFrom: "cheap",
|
|
586
|
+
model: formatModelRouterModel(retryModel),
|
|
587
|
+
};
|
|
588
|
+
await this.runRoutedTurn(messages, retryModel, retryDecision, false);
|
|
589
|
+
this._lastModelRouterDecision = completedDecision;
|
|
590
|
+
}
|
|
591
|
+
catch (error) {
|
|
592
|
+
thrownError = error;
|
|
593
|
+
if (completedDecision) {
|
|
594
|
+
completedDecision = { ...completedDecision, outcome: "failed" };
|
|
595
|
+
this._lastModelRouterDecision = completedDecision;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
finally {
|
|
599
|
+
this._isModelRouterRetry = previousIsModelRouterRetry;
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
if (persistDecision && completedDecision) {
|
|
603
|
+
persistModelRouterDecision(this.deps.getSessionManager(), completedDecision);
|
|
604
|
+
// G3: one route event per user-facing routed turn (the escalation retry runs with
|
|
605
|
+
// persistDecision=false, so it does not double-emit). Codes/numbers only — no prompt text.
|
|
606
|
+
this.deps.emitAutonomyTelemetry({
|
|
607
|
+
type: AUTONOMY_TELEMETRY_EVENT_TYPES.routeDecision,
|
|
608
|
+
timestamp: new Date().toISOString(),
|
|
609
|
+
payload: {
|
|
610
|
+
tier: completedDecision.route.tier,
|
|
611
|
+
risk: completedDecision.route.risk,
|
|
612
|
+
reasonCode: completedDecision.route.reasonCode,
|
|
613
|
+
confidence: completedDecision.route.confidence,
|
|
614
|
+
outcome: completedDecision.outcome,
|
|
615
|
+
},
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
if (thrownError) {
|
|
619
|
+
throw thrownError;
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
//# sourceMappingURL=model-router-controller.js.map
|