@caupulican/pi-adaptative 0.81.38 → 0.81.40
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 +131 -0
- package/README.md +2 -0
- package/dist/bundled-resources/extensions/tmux-agent-manager/README.md +18 -1
- package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts +133 -0
- package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts.map +1 -0
- package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js +198 -0
- package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js.map +1 -0
- package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.ts +311 -0
- package/dist/bundled-resources/extensions/tmux-agent-manager/index.d.ts +31 -2
- package/dist/bundled-resources/extensions/tmux-agent-manager/index.d.ts.map +1 -1
- package/dist/bundled-resources/extensions/tmux-agent-manager/index.js +823 -79
- package/dist/bundled-resources/extensions/tmux-agent-manager/index.js.map +1 -1
- package/dist/bundled-resources/extensions/tmux-agent-manager/index.ts +1043 -86
- package/dist/bundled-resources/runtimes/pi-shell-engine/commands/__init__.py +43 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/commands/fs.py +270 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/commands/search.py +252 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/commands/strings.py +399 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/commands/text.py +575 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/context.py +52 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/errors.py +49 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/exec.py +734 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/expand.py +238 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/main.py +132 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/nodes.py +116 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/parser.py +287 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/proc.py +137 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/state.py +100 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/tokens.py +579 -0
- package/dist/bundled-resources/skills/tool-call-repair/SKILL.md +19 -9
- package/dist/bundled-resources/skills/tool-call-repair/references/failure-grammar.md +22 -5
- package/dist/bundled-resources/skills/tool-call-repair/references/repair-catalogue.md +7 -7
- package/dist/bundled-resources/skills/tool-call-repair/references/text-protocol-grammar.md +28 -7
- package/dist/cli/args.d.ts +5 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +24 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/core/agent-directory-layout.d.ts +15 -0
- package/dist/core/agent-directory-layout.d.ts.map +1 -0
- package/dist/core/agent-directory-layout.js +72 -0
- package/dist/core/agent-directory-layout.js.map +1 -0
- package/dist/core/agent-paths.d.ts +66 -0
- package/dist/core/agent-paths.d.ts.map +1 -0
- package/dist/core/agent-paths.js +170 -0
- package/dist/core/agent-paths.js.map +1 -0
- package/dist/core/agent-session-runtime.d.ts +52 -8
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +397 -79
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +1 -0
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +4 -3
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +255 -103
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +754 -1173
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/autonomy/approval-gate.d.ts +3 -2
- package/dist/core/autonomy/approval-gate.d.ts.map +1 -1
- package/dist/core/autonomy/approval-gate.js +6 -28
- package/dist/core/autonomy/approval-gate.js.map +1 -1
- package/dist/core/autonomy/bounded-completion.d.ts +1 -1
- package/dist/core/autonomy/bounded-completion.d.ts.map +1 -1
- package/dist/core/autonomy/bounded-completion.js +1 -1
- package/dist/core/autonomy/bounded-completion.js.map +1 -1
- package/dist/core/autonomy/contracts.d.ts +26 -9
- package/dist/core/autonomy/contracts.d.ts.map +1 -1
- package/dist/core/autonomy/contracts.js.map +1 -1
- package/dist/core/autonomy/foreground-envelope.d.ts +8 -2
- package/dist/core/autonomy/foreground-envelope.d.ts.map +1 -1
- package/dist/core/autonomy/foreground-envelope.js +8 -25
- package/dist/core/autonomy/foreground-envelope.js.map +1 -1
- package/dist/core/autonomy/gates.d.ts.map +1 -1
- package/dist/core/autonomy/gates.js +8 -10
- package/dist/core/autonomy/gates.js.map +1 -1
- package/dist/core/autonomy/lane-private-paths.d.ts +2 -0
- package/dist/core/autonomy/lane-private-paths.d.ts.map +1 -0
- package/dist/core/autonomy/lane-private-paths.js +16 -0
- package/dist/core/autonomy/lane-private-paths.js.map +1 -0
- package/dist/core/autonomy/lane-tool-surface.d.ts +10 -0
- package/dist/core/autonomy/lane-tool-surface.d.ts.map +1 -1
- package/dist/core/autonomy/lane-tool-surface.js +46 -8
- package/dist/core/autonomy/lane-tool-surface.js.map +1 -1
- package/dist/core/autonomy/lane-tracker.d.ts +24 -1
- package/dist/core/autonomy/lane-tracker.d.ts.map +1 -1
- package/dist/core/autonomy/lane-tracker.js +43 -1
- package/dist/core/autonomy/lane-tracker.js.map +1 -1
- package/dist/core/autonomy/risk-assessment.d.ts +1 -2
- package/dist/core/autonomy/risk-assessment.d.ts.map +1 -1
- package/dist/core/autonomy/risk-assessment.js +1 -123
- package/dist/core/autonomy/risk-assessment.js.map +1 -1
- package/dist/core/autonomy/session-lane-record.d.ts +4 -4
- package/dist/core/autonomy/session-lane-record.d.ts.map +1 -1
- package/dist/core/autonomy/session-lane-record.js +16 -29
- package/dist/core/autonomy/session-lane-record.js.map +1 -1
- package/dist/core/autonomy/telemetry-events.d.ts +1 -1
- package/dist/core/autonomy/telemetry-events.d.ts.map +1 -1
- package/dist/core/autonomy/telemetry-events.js +1 -1
- package/dist/core/autonomy/telemetry-events.js.map +1 -1
- package/dist/core/autonomy-telemetry.d.ts +7 -7
- package/dist/core/autonomy-telemetry.d.ts.map +1 -1
- package/dist/core/autonomy-telemetry.js +9 -9
- package/dist/core/autonomy-telemetry.js.map +1 -1
- package/dist/core/background-lane-controller.d.ts +90 -156
- package/dist/core/background-lane-controller.d.ts.map +1 -1
- package/dist/core/background-lane-controller.js +192 -968
- package/dist/core/background-lane-controller.js.map +1 -1
- package/dist/core/bash-execution-controller.d.ts +4 -0
- package/dist/core/bash-execution-controller.d.ts.map +1 -1
- package/dist/core/bash-execution-controller.js +7 -1
- package/dist/core/bash-execution-controller.js.map +1 -1
- package/dist/core/capability-contract.d.ts +4 -0
- package/dist/core/capability-contract.d.ts.map +1 -0
- package/dist/core/capability-contract.js +28 -0
- package/dist/core/capability-contract.js.map +1 -0
- package/dist/core/compaction-controller.d.ts +90 -0
- package/dist/core/compaction-controller.d.ts.map +1 -0
- package/dist/core/compaction-controller.js +452 -0
- package/dist/core/compaction-controller.js.map +1 -0
- package/dist/core/compaction-support.d.ts +24 -13
- package/dist/core/compaction-support.d.ts.map +1 -1
- package/dist/core/compaction-support.js +43 -7
- package/dist/core/compaction-support.js.map +1 -1
- package/dist/core/context/context-artifacts.d.ts +6 -2
- package/dist/core/context/context-artifacts.d.ts.map +1 -1
- package/dist/core/context/context-artifacts.js +34 -2
- package/dist/core/context/context-artifacts.js.map +1 -1
- package/dist/core/context/context-audit.d.ts +33 -1
- package/dist/core/context/context-audit.d.ts.map +1 -1
- package/dist/core/context/context-audit.js +31 -5
- package/dist/core/context/context-audit.js.map +1 -1
- package/dist/core/context/context-store-retention.d.ts +8 -2
- package/dist/core/context/context-store-retention.d.ts.map +1 -1
- package/dist/core/context/context-store-retention.js +158 -35
- package/dist/core/context/context-store-retention.js.map +1 -1
- package/dist/core/context/okf-memory.d.ts.map +1 -1
- package/dist/core/context/okf-memory.js +9 -11
- package/dist/core/context/okf-memory.js.map +1 -1
- package/dist/core/context/sqlite-runtime-index.d.ts.map +1 -1
- package/dist/core/context/sqlite-runtime-index.js +6 -8
- package/dist/core/context/sqlite-runtime-index.js.map +1 -1
- package/dist/core/context-gc.d.ts +3 -0
- package/dist/core/context-gc.d.ts.map +1 -1
- package/dist/core/context-gc.js +26 -6
- package/dist/core/context-gc.js.map +1 -1
- package/dist/core/context-pipeline.d.ts +26 -4
- package/dist/core/context-pipeline.d.ts.map +1 -1
- package/dist/core/context-pipeline.js +146 -18
- package/dist/core/context-pipeline.js.map +1 -1
- package/dist/core/cost-guard.d.ts +19 -3
- package/dist/core/cost-guard.d.ts.map +1 -1
- package/dist/core/cost-guard.js +18 -3
- package/dist/core/cost-guard.js.map +1 -1
- package/dist/core/default-tool-surface.d.ts.map +1 -1
- package/dist/core/default-tool-surface.js +1 -0
- package/dist/core/default-tool-surface.js.map +1 -1
- package/dist/core/delegation/managed-lane-controller.d.ts +34 -0
- package/dist/core/delegation/managed-lane-controller.d.ts.map +1 -0
- package/dist/core/delegation/managed-lane-controller.js +217 -0
- package/dist/core/delegation/managed-lane-controller.js.map +1 -0
- package/dist/core/delegation/session-worker-claim.d.ts +44 -0
- package/dist/core/delegation/session-worker-claim.d.ts.map +1 -0
- package/dist/core/delegation/session-worker-claim.js +98 -0
- package/dist/core/delegation/session-worker-claim.js.map +1 -0
- package/dist/core/delegation/worker-actions.d.ts +7 -5
- package/dist/core/delegation/worker-actions.d.ts.map +1 -1
- package/dist/core/delegation/worker-actions.js +20 -4
- package/dist/core/delegation/worker-actions.js.map +1 -1
- package/dist/core/delegation/worker-claim.d.ts +56 -0
- package/dist/core/delegation/worker-claim.d.ts.map +1 -0
- package/dist/core/delegation/worker-claim.js +239 -0
- package/dist/core/delegation/worker-claim.js.map +1 -0
- package/dist/core/delegation/worker-delegation-controller.d.ts +110 -0
- package/dist/core/delegation/worker-delegation-controller.d.ts.map +1 -0
- package/dist/core/delegation/worker-delegation-controller.js +861 -0
- package/dist/core/delegation/worker-delegation-controller.js.map +1 -0
- package/dist/core/delegation/worker-delegation-request.d.ts +11 -0
- package/dist/core/delegation/worker-delegation-request.d.ts.map +1 -0
- package/dist/core/delegation/worker-delegation-request.js +2 -0
- package/dist/core/delegation/worker-delegation-request.js.map +1 -0
- package/dist/core/delegation/worker-dispatch-scheduler.d.ts +40 -0
- package/dist/core/delegation/worker-dispatch-scheduler.d.ts.map +1 -0
- package/dist/core/delegation/worker-dispatch-scheduler.js +93 -0
- package/dist/core/delegation/worker-dispatch-scheduler.js.map +1 -0
- package/dist/core/delegation/worker-execution-policy.d.ts +62 -0
- package/dist/core/delegation/worker-execution-policy.d.ts.map +1 -0
- package/dist/core/delegation/worker-execution-policy.js +160 -0
- package/dist/core/delegation/worker-execution-policy.js.map +1 -0
- package/dist/core/delegation/worker-lane-projection.d.ts +14 -0
- package/dist/core/delegation/worker-lane-projection.d.ts.map +1 -0
- package/dist/core/delegation/worker-lane-projection.js +100 -0
- package/dist/core/delegation/worker-lane-projection.js.map +1 -0
- package/dist/core/delegation/worker-lifecycle.d.ts +97 -0
- package/dist/core/delegation/worker-lifecycle.d.ts.map +1 -0
- package/dist/core/delegation/worker-lifecycle.js +339 -0
- package/dist/core/delegation/worker-lifecycle.js.map +1 -0
- package/dist/core/delegation/worker-notification-coordinator.d.ts +36 -0
- package/dist/core/delegation/worker-notification-coordinator.d.ts.map +1 -0
- package/dist/core/delegation/worker-notification-coordinator.js +90 -0
- package/dist/core/delegation/worker-notification-coordinator.js.map +1 -0
- package/dist/core/delegation/worker-profile-resolver.d.ts +55 -0
- package/dist/core/delegation/worker-profile-resolver.d.ts.map +1 -0
- package/dist/core/delegation/worker-profile-resolver.js +113 -0
- package/dist/core/delegation/worker-profile-resolver.js.map +1 -0
- package/dist/core/delegation/worker-runner.d.ts +25 -14
- package/dist/core/delegation/worker-runner.d.ts.map +1 -1
- package/dist/core/delegation/worker-runner.js +122 -53
- package/dist/core/delegation/worker-runner.js.map +1 -1
- package/dist/core/delegation/worker-task-label.d.ts +3 -0
- package/dist/core/delegation/worker-task-label.d.ts.map +1 -0
- package/dist/core/delegation/worker-task-label.js +11 -0
- package/dist/core/delegation/worker-task-label.js.map +1 -0
- package/dist/core/doctor.d.ts +8 -0
- package/dist/core/doctor.d.ts.map +1 -1
- package/dist/core/doctor.js +32 -1
- package/dist/core/doctor.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader.d.ts +5 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +68 -13
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +7 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/storage.d.ts +8 -0
- package/dist/core/extensions/storage.d.ts.map +1 -0
- package/dist/core/extensions/storage.js +28 -0
- package/dist/core/extensions/storage.js.map +1 -0
- package/dist/core/extensions/types.d.ts +101 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/failure-corpus.d.ts +1 -15
- package/dist/core/failure-corpus.d.ts.map +1 -1
- package/dist/core/failure-corpus.js +9 -37
- package/dist/core/failure-corpus.js.map +1 -1
- package/dist/core/foreground-recovery-controller.d.ts +52 -0
- package/dist/core/foreground-recovery-controller.d.ts.map +1 -0
- package/dist/core/foreground-recovery-controller.js +111 -0
- package/dist/core/foreground-recovery-controller.js.map +1 -0
- package/dist/core/gateways/channel-provider.d.ts +3 -0
- package/dist/core/gateways/channel-provider.d.ts.map +1 -1
- package/dist/core/gateways/channel-provider.js +31 -6
- package/dist/core/gateways/channel-provider.js.map +1 -1
- package/dist/core/goal-loop-controller.d.ts +17 -1
- package/dist/core/goal-loop-controller.d.ts.map +1 -1
- package/dist/core/goal-loop-controller.js +79 -11
- package/dist/core/goal-loop-controller.js.map +1 -1
- package/dist/core/goals/goal-acceptance.d.ts +11 -0
- package/dist/core/goals/goal-acceptance.d.ts.map +1 -0
- package/dist/core/goals/goal-acceptance.js +25 -0
- package/dist/core/goals/goal-acceptance.js.map +1 -0
- package/dist/core/goals/goal-auto-continue-controller.d.ts +27 -0
- package/dist/core/goals/goal-auto-continue-controller.d.ts.map +1 -0
- package/dist/core/goals/goal-auto-continue-controller.js +93 -0
- package/dist/core/goals/goal-auto-continue-controller.js.map +1 -0
- package/dist/core/goals/goal-continuation-controller.d.ts +48 -2
- package/dist/core/goals/goal-continuation-controller.d.ts.map +1 -1
- package/dist/core/goals/goal-continuation-controller.js +87 -0
- package/dist/core/goals/goal-continuation-controller.js.map +1 -1
- package/dist/core/goals/goal-continuation-defaults.d.ts +39 -0
- package/dist/core/goals/goal-continuation-defaults.d.ts.map +1 -1
- package/dist/core/goals/goal-continuation-defaults.js +42 -0
- package/dist/core/goals/goal-continuation-defaults.js.map +1 -1
- package/dist/core/goals/goal-continuation-prompt.d.ts +5 -1
- package/dist/core/goals/goal-continuation-prompt.d.ts.map +1 -1
- package/dist/core/goals/goal-continuation-prompt.js +56 -15
- package/dist/core/goals/goal-continuation-prompt.js.map +1 -1
- package/dist/core/goals/goal-lifecycle.d.ts +20 -0
- package/dist/core/goals/goal-lifecycle.d.ts.map +1 -0
- package/dist/core/goals/goal-lifecycle.js +17 -0
- package/dist/core/goals/goal-lifecycle.js.map +1 -0
- package/dist/core/goals/goal-runtime-snapshot.d.ts +105 -4
- package/dist/core/goals/goal-runtime-snapshot.d.ts.map +1 -1
- package/dist/core/goals/goal-runtime-snapshot.js +91 -6
- package/dist/core/goals/goal-runtime-snapshot.js.map +1 -1
- package/dist/core/goals/goal-state.d.ts +90 -1
- package/dist/core/goals/goal-state.d.ts.map +1 -1
- package/dist/core/goals/goal-state.js +78 -15
- package/dist/core/goals/goal-state.js.map +1 -1
- package/dist/core/goals/goal-tool-core.d.ts +58 -2
- package/dist/core/goals/goal-tool-core.d.ts.map +1 -1
- package/dist/core/goals/goal-tool-core.js +82 -6
- package/dist/core/goals/goal-tool-core.js.map +1 -1
- package/dist/core/goals/session-goal-state.d.ts +13 -6
- package/dist/core/goals/session-goal-state.d.ts.map +1 -1
- package/dist/core/goals/session-goal-state.js +20 -28
- package/dist/core/goals/session-goal-state.js.map +1 -1
- package/dist/core/human-input.d.ts +100 -0
- package/dist/core/human-input.d.ts.map +1 -0
- package/dist/core/human-input.js +362 -0
- package/dist/core/human-input.js.map +1 -0
- package/dist/core/index.d.ts +9 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +9 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/{telemetry.d.ts → install-telemetry.d.ts} +1 -1
- package/dist/core/install-telemetry.d.ts.map +1 -0
- package/dist/core/{telemetry.js → install-telemetry.js} +1 -1
- package/dist/core/install-telemetry.js.map +1 -0
- package/dist/core/keybindings.d.ts +27 -1
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +34 -8
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/learning/learning-audit.d.ts +2 -4
- package/dist/core/learning/learning-audit.d.ts.map +1 -1
- package/dist/core/learning/learning-audit.js +9 -29
- package/dist/core/learning/learning-audit.js.map +1 -1
- package/dist/core/learning/learning-gate.d.ts.map +1 -1
- package/dist/core/learning/learning-gate.js +1 -6
- package/dist/core/learning/learning-gate.js.map +1 -1
- package/dist/core/learning/observation-store.d.ts +12 -3
- package/dist/core/learning/observation-store.d.ts.map +1 -1
- package/dist/core/learning/observation-store.js +30 -15
- package/dist/core/learning/observation-store.js.map +1 -1
- package/dist/core/learning/session-learning-decision.d.ts +2 -4
- package/dist/core/learning/session-learning-decision.d.ts.map +1 -1
- package/dist/core/learning/session-learning-decision.js +9 -29
- package/dist/core/learning/session-learning-decision.js.map +1 -1
- package/dist/core/learning/skill-curator.d.ts +5 -1
- package/dist/core/learning/skill-curator.d.ts.map +1 -1
- package/dist/core/learning/skill-curator.js +21 -19
- package/dist/core/learning/skill-curator.js.map +1 -1
- package/dist/core/local-runtime-controller.d.ts +65 -3
- package/dist/core/local-runtime-controller.d.ts.map +1 -1
- package/dist/core/local-runtime-controller.js +186 -26
- package/dist/core/local-runtime-controller.js.map +1 -1
- package/dist/core/memory/providers/file-store.d.ts +1 -1
- package/dist/core/memory/providers/file-store.d.ts.map +1 -1
- package/dist/core/memory/providers/file-store.js +6 -6
- package/dist/core/memory/providers/file-store.js.map +1 -1
- package/dist/core/memory-controller.d.ts.map +1 -1
- package/dist/core/memory-controller.js +4 -4
- package/dist/core/memory-controller.js.map +1 -1
- package/dist/core/model-capability.d.ts +34 -0
- package/dist/core/model-capability.d.ts.map +1 -1
- package/dist/core/model-capability.js +43 -1
- package/dist/core/model-capability.js.map +1 -1
- package/dist/core/model-resolver.d.ts +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +6 -9
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/model-router/intent-classifier.d.ts +1 -4
- package/dist/core/model-router/intent-classifier.d.ts.map +1 -1
- package/dist/core/model-router/intent-classifier.js +1 -156
- package/dist/core/model-router/intent-classifier.js.map +1 -1
- package/dist/core/model-router/tool-escalation.d.ts +15 -0
- package/dist/core/model-router/tool-escalation.d.ts.map +1 -1
- package/dist/core/model-router/tool-escalation.js +23 -1
- package/dist/core/model-router/tool-escalation.js.map +1 -1
- package/dist/core/model-router-controller.d.ts +34 -7
- package/dist/core/model-router-controller.d.ts.map +1 -1
- package/dist/core/model-router-controller.js +95 -16
- package/dist/core/model-router-controller.js.map +1 -1
- package/dist/core/model-selection-controller.d.ts +4 -4
- package/dist/core/model-selection-controller.d.ts.map +1 -1
- package/dist/core/model-selection-controller.js.map +1 -1
- package/dist/core/model-tool-protocol.d.ts +23 -0
- package/dist/core/model-tool-protocol.d.ts.map +1 -0
- package/dist/core/model-tool-protocol.js +43 -0
- package/dist/core/model-tool-protocol.js.map +1 -0
- package/dist/core/models/adaptation-store.d.ts +10 -5
- package/dist/core/models/adaptation-store.d.ts.map +1 -1
- package/dist/core/models/adaptation-store.js +129 -81
- package/dist/core/models/adaptation-store.js.map +1 -1
- package/dist/core/models/default-model-suggestions.d.ts.map +1 -1
- package/dist/core/models/default-model-suggestions.js +17 -0
- package/dist/core/models/default-model-suggestions.js.map +1 -1
- package/dist/core/models/fitness-store.d.ts +4 -11
- package/dist/core/models/fitness-store.d.ts.map +1 -1
- package/dist/core/models/fitness-store.js +87 -51
- package/dist/core/models/fitness-store.js.map +1 -1
- package/dist/core/models/host-state-store.d.ts +34 -0
- package/dist/core/models/host-state-store.d.ts.map +1 -0
- package/dist/core/models/host-state-store.js +86 -0
- package/dist/core/models/host-state-store.js.map +1 -0
- package/dist/core/models/llamacpp-runtime.d.ts +180 -0
- package/dist/core/models/llamacpp-runtime.d.ts.map +1 -0
- package/dist/core/models/llamacpp-runtime.js +475 -0
- package/dist/core/models/llamacpp-runtime.js.map +1 -0
- package/dist/core/models/local-registration.d.ts +40 -0
- package/dist/core/models/local-registration.d.ts.map +1 -1
- package/dist/core/models/local-registration.js +94 -5
- package/dist/core/models/local-registration.js.map +1 -1
- package/dist/core/models/local-runtime.d.ts.map +1 -1
- package/dist/core/models/local-runtime.js +6 -5
- package/dist/core/models/local-runtime.js.map +1 -1
- package/dist/core/models/model-ref.d.ts +7 -0
- package/dist/core/models/model-ref.d.ts.map +1 -1
- package/dist/core/models/model-ref.js +26 -0
- package/dist/core/models/model-ref.js.map +1 -1
- package/dist/core/models/needle-runtime.d.ts +257 -0
- package/dist/core/models/needle-runtime.d.ts.map +1 -0
- package/dist/core/models/needle-runtime.js +519 -0
- package/dist/core/models/needle-runtime.js.map +1 -0
- package/dist/core/models/prism-llamacpp-lifecycle.d.ts +89 -0
- package/dist/core/models/prism-llamacpp-lifecycle.d.ts.map +1 -0
- package/dist/core/models/prism-llamacpp-lifecycle.js +121 -0
- package/dist/core/models/prism-llamacpp-lifecycle.js.map +1 -0
- package/dist/core/orchestration/agent-resume.d.ts +24 -0
- package/dist/core/orchestration/agent-resume.d.ts.map +1 -0
- package/dist/core/orchestration/agent-resume.js +90 -0
- package/dist/core/orchestration/agent-resume.js.map +1 -0
- package/dist/core/orchestration/capability-gateway.d.ts +61 -0
- package/dist/core/orchestration/capability-gateway.d.ts.map +1 -0
- package/dist/core/orchestration/capability-gateway.js +152 -0
- package/dist/core/orchestration/capability-gateway.js.map +1 -0
- package/dist/core/orchestration/contracts.d.ts +343 -0
- package/dist/core/orchestration/contracts.d.ts.map +1 -0
- package/dist/core/orchestration/contracts.js +135 -0
- package/dist/core/orchestration/contracts.js.map +1 -0
- package/dist/core/orchestration/delegation-ledger.d.ts +56 -0
- package/dist/core/orchestration/delegation-ledger.d.ts.map +1 -0
- package/dist/core/orchestration/delegation-ledger.js +197 -0
- package/dist/core/orchestration/delegation-ledger.js.map +1 -0
- package/dist/core/orchestration/event-store.d.ts +83 -0
- package/dist/core/orchestration/event-store.d.ts.map +1 -0
- package/dist/core/orchestration/event-store.js +560 -0
- package/dist/core/orchestration/event-store.js.map +1 -0
- package/dist/core/orchestration/lane-tool-manifests.d.ts +9 -0
- package/dist/core/orchestration/lane-tool-manifests.d.ts.map +1 -0
- package/dist/core/orchestration/lane-tool-manifests.js +37 -0
- package/dist/core/orchestration/lane-tool-manifests.js.map +1 -0
- package/dist/core/orchestration/model-binding.d.ts +15 -0
- package/dist/core/orchestration/model-binding.d.ts.map +1 -0
- package/dist/core/orchestration/model-binding.js +29 -0
- package/dist/core/orchestration/model-binding.js.map +1 -0
- package/dist/core/orchestration/policy-compiler.d.ts +49 -0
- package/dist/core/orchestration/policy-compiler.d.ts.map +1 -0
- package/dist/core/orchestration/policy-compiler.js +191 -0
- package/dist/core/orchestration/policy-compiler.js.map +1 -0
- package/dist/core/orchestration/policy-gate.d.ts +18 -0
- package/dist/core/orchestration/policy-gate.d.ts.map +1 -0
- package/dist/core/orchestration/policy-gate.js +24 -0
- package/dist/core/orchestration/policy-gate.js.map +1 -0
- package/dist/core/orchestration/profile-registry.d.ts +51 -0
- package/dist/core/orchestration/profile-registry.d.ts.map +1 -0
- package/dist/core/orchestration/profile-registry.js +393 -0
- package/dist/core/orchestration/profile-registry.js.map +1 -0
- package/dist/core/orchestration/profile-store.d.ts +31 -0
- package/dist/core/orchestration/profile-store.d.ts.map +1 -0
- package/dist/core/orchestration/profile-store.js +136 -0
- package/dist/core/orchestration/profile-store.js.map +1 -0
- package/dist/core/orchestration/risk-budget.d.ts +9 -0
- package/dist/core/orchestration/risk-budget.d.ts.map +1 -0
- package/dist/core/orchestration/risk-budget.js +48 -0
- package/dist/core/orchestration/risk-budget.js.map +1 -0
- package/dist/core/orchestration/task-runtime.d.ts +168 -0
- package/dist/core/orchestration/task-runtime.d.ts.map +1 -0
- package/dist/core/orchestration/task-runtime.js +1600 -0
- package/dist/core/orchestration/task-runtime.js.map +1 -0
- package/dist/core/orchestration/work-state-projection.d.ts +32 -0
- package/dist/core/orchestration/work-state-projection.d.ts.map +1 -0
- package/dist/core/orchestration/work-state-projection.js +116 -0
- package/dist/core/orchestration/work-state-projection.js.map +1 -0
- package/dist/core/orchestration/worker-execution-contract.d.ts +21 -0
- package/dist/core/orchestration/worker-execution-contract.d.ts.map +1 -0
- package/dist/core/orchestration/worker-execution-contract.js +179 -0
- package/dist/core/orchestration/worker-execution-contract.js.map +1 -0
- package/dist/core/orchestration/worker-result-adapter.d.ts +21 -0
- package/dist/core/orchestration/worker-result-adapter.d.ts.map +1 -0
- package/dist/core/orchestration/worker-result-adapter.js +109 -0
- package/dist/core/orchestration/worker-result-adapter.js.map +1 -0
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +11 -10
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/process-identity.d.ts +11 -0
- package/dist/core/process-identity.d.ts.map +1 -0
- package/dist/core/process-identity.js +26 -0
- package/dist/core/process-identity.js.map +1 -0
- package/dist/core/process-matrix/codes.d.ts +83 -0
- package/dist/core/process-matrix/codes.d.ts.map +1 -0
- package/dist/core/process-matrix/codes.js +15 -0
- package/dist/core/process-matrix/codes.js.map +1 -0
- package/dist/core/process-matrix/resume-launcher.d.ts +26 -0
- package/dist/core/process-matrix/resume-launcher.d.ts.map +1 -0
- package/dist/core/process-matrix/resume-launcher.js +62 -0
- package/dist/core/process-matrix/resume-launcher.js.map +1 -0
- package/dist/core/process-matrix/runtime.d.ts +78 -0
- package/dist/core/process-matrix/runtime.d.ts.map +1 -0
- package/dist/core/process-matrix/runtime.js +633 -0
- package/dist/core/process-matrix/runtime.js.map +1 -0
- package/dist/core/process-matrix/store.d.ts +25 -0
- package/dist/core/process-matrix/store.d.ts.map +1 -0
- package/dist/core/process-matrix/store.js +189 -0
- package/dist/core/process-matrix/store.js.map +1 -0
- package/dist/core/process-matrix/supervisor.d.ts +75 -0
- package/dist/core/process-matrix/supervisor.d.ts.map +1 -0
- package/dist/core/process-matrix/supervisor.js +161 -0
- package/dist/core/process-matrix/supervisor.js.map +1 -0
- package/dist/core/profile-registry.d.ts +7 -0
- package/dist/core/profile-registry.d.ts.map +1 -1
- package/dist/core/profile-registry.js +25 -7
- package/dist/core/profile-registry.js.map +1 -1
- package/dist/core/python-runtime.d.ts.map +1 -1
- package/dist/core/python-runtime.js +3 -3
- package/dist/core/python-runtime.js.map +1 -1
- package/dist/core/reflection-controller.d.ts +33 -9
- package/dist/core/reflection-controller.d.ts.map +1 -1
- package/dist/core/reflection-controller.js +217 -127
- package/dist/core/reflection-controller.js.map +1 -1
- package/dist/core/reload-blockers.d.ts +36 -0
- package/dist/core/reload-blockers.d.ts.map +1 -1
- package/dist/core/reload-blockers.js +50 -8
- package/dist/core/reload-blockers.js.map +1 -1
- package/dist/core/research/evidence-bundle.d.ts.map +1 -1
- package/dist/core/research/evidence-bundle.js +1 -6
- package/dist/core/research/evidence-bundle.js.map +1 -1
- package/dist/core/research/lane-model-resolver.d.ts +33 -0
- package/dist/core/research/lane-model-resolver.d.ts.map +1 -0
- package/dist/core/research/lane-model-resolver.js +65 -0
- package/dist/core/research/lane-model-resolver.js.map +1 -0
- package/dist/core/research/model-fitness-controller.d.ts +38 -0
- package/dist/core/research/model-fitness-controller.d.ts.map +1 -0
- package/dist/core/research/model-fitness-controller.js +106 -0
- package/dist/core/research/model-fitness-controller.js.map +1 -0
- package/dist/core/research/model-fitness.d.ts +1 -1
- package/dist/core/research/model-fitness.d.ts.map +1 -1
- package/dist/core/research/model-fitness.js +4 -4
- package/dist/core/research/model-fitness.js.map +1 -1
- package/dist/core/research/research-gate.d.ts.map +1 -1
- package/dist/core/research/research-gate.js +7 -7
- package/dist/core/research/research-gate.js.map +1 -1
- package/dist/core/research/research-lane-controller.d.ts +62 -0
- package/dist/core/research/research-lane-controller.d.ts.map +1 -0
- package/dist/core/research/research-lane-controller.js +292 -0
- package/dist/core/research/research-lane-controller.js.map +1 -0
- package/dist/core/research/session-evidence-bundle.d.ts +2 -4
- package/dist/core/research/session-evidence-bundle.d.ts.map +1 -1
- package/dist/core/research/session-evidence-bundle.js +10 -46
- package/dist/core/research/session-evidence-bundle.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +15 -9
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/risk-classifier.d.ts +6 -0
- package/dist/core/risk-classifier.d.ts.map +1 -0
- package/dist/core/risk-classifier.js +225 -0
- package/dist/core/risk-classifier.js.map +1 -0
- package/dist/core/runtime-builder.d.ts +76 -17
- package/dist/core/runtime-builder.d.ts.map +1 -1
- package/dist/core/runtime-builder.js +367 -124
- package/dist/core/runtime-builder.js.map +1 -1
- package/dist/core/scout-controller.d.ts +6 -0
- package/dist/core/scout-controller.d.ts.map +1 -1
- package/dist/core/scout-controller.js +66 -52
- package/dist/core/scout-controller.js.map +1 -1
- package/dist/core/sdk.d.ts +6 -3
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +64 -27
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-analytics.d.ts.map +1 -1
- package/dist/core/session-analytics.js +28 -1
- package/dist/core/session-analytics.js.map +1 -1
- package/dist/core/session-image-store.d.ts +33 -0
- package/dist/core/session-image-store.d.ts.map +1 -0
- package/dist/core/session-image-store.js +283 -0
- package/dist/core/session-image-store.js.map +1 -0
- package/dist/core/session-role.d.ts +33 -0
- package/dist/core/session-role.d.ts.map +1 -0
- package/dist/core/session-role.js +58 -0
- package/dist/core/session-role.js.map +1 -0
- package/dist/core/session-snapshot.d.ts +34 -0
- package/dist/core/session-snapshot.d.ts.map +1 -0
- package/dist/core/session-snapshot.js +68 -0
- package/dist/core/session-snapshot.js.map +1 -0
- package/dist/core/session-supervision-runtime.d.ts +31 -0
- package/dist/core/session-supervision-runtime.d.ts.map +1 -0
- package/dist/core/session-supervision-runtime.js +97 -0
- package/dist/core/session-supervision-runtime.js.map +1 -0
- package/dist/core/settings-manager.d.ts +51 -7
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +168 -82
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/system-prompt-builder.d.ts +12 -0
- package/dist/core/system-prompt-builder.d.ts.map +1 -1
- package/dist/core/system-prompt-builder.js +6 -0
- package/dist/core/system-prompt-builder.js.map +1 -1
- package/dist/core/system-prompt.d.ts +14 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +20 -3
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tasks/session-task-state.d.ts +13 -6
- package/dist/core/tasks/session-task-state.d.ts.map +1 -1
- package/dist/core/tasks/session-task-state.js +20 -22
- package/dist/core/tasks/session-task-state.js.map +1 -1
- package/dist/core/tasks/task-contract-monitor.d.ts +45 -0
- package/dist/core/tasks/task-contract-monitor.d.ts.map +1 -0
- package/dist/core/tasks/task-contract-monitor.js +56 -0
- package/dist/core/tasks/task-contract-monitor.js.map +1 -0
- package/dist/core/tasks/task-projection.d.ts +20 -0
- package/dist/core/tasks/task-projection.d.ts.map +1 -0
- package/dist/core/tasks/task-projection.js +47 -0
- package/dist/core/tasks/task-projection.js.map +1 -0
- package/dist/core/tasks/task-state.d.ts +12 -0
- package/dist/core/tasks/task-state.d.ts.map +1 -1
- package/dist/core/tasks/task-state.js +56 -12
- package/dist/core/tasks/task-state.js.map +1 -1
- package/dist/core/tool-capability-policy.d.ts +13 -0
- package/dist/core/tool-capability-policy.d.ts.map +1 -0
- package/dist/core/tool-capability-policy.js +85 -0
- package/dist/core/tool-capability-policy.js.map +1 -0
- package/dist/core/tool-gate-controller.d.ts.map +1 -1
- package/dist/core/tool-gate-controller.js +5 -0
- package/dist/core/tool-gate-controller.js.map +1 -1
- package/dist/core/tool-protocol-controller.d.ts +91 -0
- package/dist/core/tool-protocol-controller.d.ts.map +1 -0
- package/dist/core/tool-protocol-controller.js +512 -0
- package/dist/core/tool-protocol-controller.js.map +1 -0
- package/dist/core/tool-recovery-log-records.d.ts +6 -0
- package/dist/core/tool-recovery-log-records.d.ts.map +1 -1
- package/dist/core/tool-recovery-log-records.js +13 -31
- package/dist/core/tool-recovery-log-records.js.map +1 -1
- package/dist/core/tool-selection/promotion.d.ts +54 -0
- package/dist/core/tool-selection/promotion.d.ts.map +1 -0
- package/dist/core/tool-selection/promotion.js +81 -0
- package/dist/core/tool-selection/promotion.js.map +1 -0
- package/dist/core/tool-selection/tool-performance-store.d.ts +39 -6
- package/dist/core/tool-selection/tool-performance-store.d.ts.map +1 -1
- package/dist/core/tool-selection/tool-performance-store.js +153 -110
- package/dist/core/tool-selection/tool-performance-store.js.map +1 -1
- package/dist/core/tool-selection/tool-selection-controller.d.ts +45 -0
- package/dist/core/tool-selection/tool-selection-controller.d.ts.map +1 -1
- package/dist/core/tool-selection/tool-selection-controller.js +96 -0
- package/dist/core/tool-selection/tool-selection-controller.js.map +1 -1
- package/dist/core/tools/ask-question.d.ts +124 -0
- package/dist/core/tools/ask-question.d.ts.map +1 -0
- package/dist/core/tools/ask-question.js +693 -0
- package/dist/core/tools/ask-question.js.map +1 -0
- package/dist/core/tools/bash.d.ts +18 -0
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +95 -16
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/delegate-status.d.ts +44 -2
- package/dist/core/tools/delegate-status.d.ts.map +1 -1
- package/dist/core/tools/delegate-status.js +214 -19
- package/dist/core/tools/delegate-status.js.map +1 -1
- package/dist/core/tools/delegate.d.ts +15 -13
- package/dist/core/tools/delegate.d.ts.map +1 -1
- package/dist/core/tools/delegate.js +124 -22
- package/dist/core/tools/delegate.js.map +1 -1
- package/dist/core/tools/extensionify.d.ts.map +1 -1
- package/dist/core/tools/extensionify.js +1 -0
- package/dist/core/tools/extensionify.js.map +1 -1
- package/dist/core/tools/goal.d.ts +94 -3
- package/dist/core/tools/goal.d.ts.map +1 -1
- package/dist/core/tools/goal.js +165 -15
- package/dist/core/tools/goal.js.map +1 -1
- package/dist/core/tools/model-fitness.d.ts +7 -0
- package/dist/core/tools/model-fitness.d.ts.map +1 -1
- package/dist/core/tools/model-fitness.js +4 -4
- package/dist/core/tools/model-fitness.js.map +1 -1
- package/dist/core/tools/orchestration-panel.d.ts +43 -0
- package/dist/core/tools/orchestration-panel.d.ts.map +1 -0
- package/dist/core/tools/orchestration-panel.js +168 -0
- package/dist/core/tools/orchestration-panel.js.map +1 -0
- package/dist/core/tools/run-process.d.ts +26 -0
- package/dist/core/tools/run-process.d.ts.map +1 -0
- package/dist/core/tools/run-process.js +138 -0
- package/dist/core/tools/run-process.js.map +1 -0
- package/dist/core/tools/shell-contract-router.d.ts +6 -1
- package/dist/core/tools/shell-contract-router.d.ts.map +1 -1
- package/dist/core/tools/shell-contract-router.js +23 -2
- package/dist/core/tools/shell-contract-router.js.map +1 -1
- package/dist/core/tools/shell-session.d.ts +89 -0
- package/dist/core/tools/shell-session.d.ts.map +1 -0
- package/dist/core/tools/shell-session.js +432 -0
- package/dist/core/tools/shell-session.js.map +1 -0
- package/dist/core/tools/task-steps.d.ts +6 -0
- package/dist/core/tools/task-steps.d.ts.map +1 -1
- package/dist/core/tools/task-steps.js +165 -8
- package/dist/core/tools/task-steps.js.map +1 -1
- package/dist/core/tools/tmux-dispatch.d.ts +84 -0
- package/dist/core/tools/tmux-dispatch.d.ts.map +1 -0
- package/dist/core/tools/tmux-dispatch.js +91 -0
- package/dist/core/tools/tmux-dispatch.js.map +1 -0
- package/dist/core/tools/windows-shell-engine.d.ts +42 -0
- package/dist/core/tools/windows-shell-engine.d.ts.map +1 -0
- package/dist/core/tools/windows-shell-engine.js +151 -0
- package/dist/core/tools/windows-shell-engine.js.map +1 -0
- package/dist/core/tools/windows-shell-state.d.ts +40 -0
- package/dist/core/tools/windows-shell-state.d.ts.map +1 -0
- package/dist/core/tools/windows-shell-state.js +59 -0
- package/dist/core/tools/windows-shell-state.js.map +1 -0
- package/dist/core/tools/worktree-sync.d.ts +24 -0
- package/dist/core/tools/worktree-sync.d.ts.map +1 -0
- package/dist/core/tools/worktree-sync.js +338 -0
- package/dist/core/tools/worktree-sync.js.map +1 -0
- package/dist/core/trust-manager.d.ts +4 -1
- package/dist/core/trust-manager.d.ts.map +1 -1
- package/dist/core/trust-manager.js +20 -2
- package/dist/core/trust-manager.js.map +1 -1
- package/dist/core/util/atomic-file.d.ts +55 -0
- package/dist/core/util/atomic-file.d.ts.map +1 -0
- package/dist/core/util/atomic-file.js +255 -0
- package/dist/core/util/atomic-file.js.map +1 -0
- package/dist/core/util/bounded-jsonl.d.ts +10 -0
- package/dist/core/util/bounded-jsonl.d.ts.map +1 -0
- package/dist/core/util/bounded-jsonl.js +75 -0
- package/dist/core/util/bounded-jsonl.js.map +1 -0
- package/dist/core/util/minimatch-cache.d.ts +33 -0
- package/dist/core/util/minimatch-cache.d.ts.map +1 -0
- package/dist/core/util/minimatch-cache.js +0 -0
- package/dist/core/util/minimatch-cache.js.map +1 -0
- package/dist/core/util/value-guards.d.ts +5 -0
- package/dist/core/util/value-guards.d.ts.map +1 -0
- package/dist/core/util/value-guards.js +12 -0
- package/dist/core/util/value-guards.js.map +1 -0
- package/dist/core/worktree-sync/codes.d.ts +227 -0
- package/dist/core/worktree-sync/codes.d.ts.map +1 -0
- package/dist/core/worktree-sync/codes.js +14 -0
- package/dist/core/worktree-sync/codes.js.map +1 -0
- package/dist/core/worktree-sync/git-engine.d.ts +156 -0
- package/dist/core/worktree-sync/git-engine.d.ts.map +1 -0
- package/dist/core/worktree-sync/git-engine.js +1191 -0
- package/dist/core/worktree-sync/git-engine.js.map +1 -0
- package/dist/core/worktree-sync/lane-gate.d.ts +75 -0
- package/dist/core/worktree-sync/lane-gate.d.ts.map +1 -0
- package/dist/core/worktree-sync/lane-gate.js +360 -0
- package/dist/core/worktree-sync/lane-gate.js.map +1 -0
- package/dist/core/worktree-sync/runtime.d.ts +47 -0
- package/dist/core/worktree-sync/runtime.d.ts.map +1 -0
- package/dist/core/worktree-sync/runtime.js +96 -0
- package/dist/core/worktree-sync/runtime.js.map +1 -0
- package/dist/core/worktree-sync/store.d.ts +69 -0
- package/dist/core/worktree-sync/store.d.ts.map +1 -0
- package/dist/core/worktree-sync/store.js +252 -0
- package/dist/core/worktree-sync/store.js.map +1 -0
- package/dist/core/worktree-sync/watcher.d.ts +29 -0
- package/dist/core/worktree-sync/watcher.d.ts.map +1 -0
- package/dist/core/worktree-sync/watcher.js +93 -0
- package/dist/core/worktree-sync/watcher.js.map +1 -0
- package/dist/index.d.ts +13 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -2
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +179 -1
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts +7 -0
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +197 -1
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/auto-learn-controller.d.ts +16 -1
- package/dist/modes/interactive/auto-learn-controller.d.ts.map +1 -1
- package/dist/modes/interactive/auto-learn-controller.js +50 -8
- package/dist/modes/interactive/auto-learn-controller.js.map +1 -1
- package/dist/modes/interactive/clipboard-input.d.ts +7 -1
- package/dist/modes/interactive/clipboard-input.d.ts.map +1 -1
- package/dist/modes/interactive/clipboard-input.js +44 -6
- package/dist/modes/interactive/clipboard-input.js.map +1 -1
- package/dist/modes/interactive/components/profile-resource-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/profile-resource-editor.js +23 -1
- package/dist/modes/interactive/components/profile-resource-editor.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +2 -2
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/config-backup.d.ts.map +1 -1
- package/dist/modes/interactive/config-backup.js +5 -4
- package/dist/modes/interactive/config-backup.js.map +1 -1
- package/dist/modes/interactive/extension-ui-host.d.ts +14 -0
- package/dist/modes/interactive/extension-ui-host.d.ts.map +1 -1
- package/dist/modes/interactive/extension-ui-host.js +76 -15
- package/dist/modes/interactive/extension-ui-host.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +4 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +67 -1
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/key-handlers.d.ts.map +1 -1
- package/dist/modes/interactive/key-handlers.js +1 -1
- package/dist/modes/interactive/key-handlers.js.map +1 -1
- package/dist/modes/interactive/local-model-commands.d.ts +43 -0
- package/dist/modes/interactive/local-model-commands.d.ts.map +1 -1
- package/dist/modes/interactive/local-model-commands.js +290 -3
- package/dist/modes/interactive/local-model-commands.js.map +1 -1
- package/dist/modes/interactive/profile-menu-controller.d.ts.map +1 -1
- package/dist/modes/interactive/profile-menu-controller.js +7 -7
- package/dist/modes/interactive/profile-menu-controller.js.map +1 -1
- package/dist/modes/interactive/report-commands.d.ts.map +1 -1
- package/dist/modes/interactive/report-commands.js +21 -0
- package/dist/modes/interactive/report-commands.js.map +1 -1
- package/dist/modes/interactive/session-flow-commands.d.ts +17 -2
- package/dist/modes/interactive/session-flow-commands.d.ts.map +1 -1
- package/dist/modes/interactive/session-flow-commands.js +74 -21
- package/dist/modes/interactive/session-flow-commands.js.map +1 -1
- package/dist/modes/interactive/session-io-commands.d.ts.map +1 -1
- package/dist/modes/interactive/session-io-commands.js +16 -6
- package/dist/modes/interactive/session-io-commands.js.map +1 -1
- package/dist/modes/interactive/session-replacement-errors.d.ts +7 -0
- package/dist/modes/interactive/session-replacement-errors.d.ts.map +1 -0
- package/dist/modes/interactive/session-replacement-errors.js +15 -0
- package/dist/modes/interactive/session-replacement-errors.js.map +1 -0
- package/dist/modes/interactive/startup-checks.d.ts.map +1 -1
- package/dist/modes/interactive/startup-checks.js +1 -1
- package/dist/modes/interactive/startup-checks.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +82 -23
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +15 -0
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js +138 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/utils/clipboard-image.d.ts.map +1 -1
- package/dist/utils/clipboard-image.js +2 -13
- package/dist/utils/clipboard-image.js.map +1 -1
- package/dist/utils/clipboard-native.d.ts +1 -0
- package/dist/utils/clipboard-native.d.ts.map +1 -1
- package/dist/utils/clipboard-native.js.map +1 -1
- package/dist/utils/clipboard.d.ts +1 -0
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js +52 -1
- package/dist/utils/clipboard.js.map +1 -1
- package/dist/utils/fs-watch.d.ts +11 -0
- package/dist/utils/fs-watch.d.ts.map +1 -1
- package/dist/utils/fs-watch.js +20 -2
- package/dist/utils/fs-watch.js.map +1 -1
- package/dist/utils/highlight-js-languages.d.ts +4 -0
- package/dist/utils/highlight-js-languages.d.ts.map +1 -0
- package/dist/utils/highlight-js-languages.js +573 -0
- package/dist/utils/highlight-js-languages.js.map +1 -0
- package/dist/utils/platform.d.ts +3 -0
- package/dist/utils/platform.d.ts.map +1 -0
- package/dist/utils/platform.js +8 -0
- package/dist/utils/platform.js.map +1 -0
- package/dist/utils/shell.d.ts +7 -1
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/shell.js +21 -6
- package/dist/utils/shell.js.map +1 -1
- package/dist/utils/syntax-highlight.d.ts.map +1 -1
- package/dist/utils/syntax-highlight.js +53 -5
- package/dist/utils/syntax-highlight.js.map +1 -1
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +112 -1
- package/dist/utils/tools-manager.js.map +1 -1
- package/dist/utils/work-directory.d.ts +11 -0
- package/dist/utils/work-directory.d.ts.map +1 -1
- package/dist/utils/work-directory.js +30 -9
- package/dist/utils/work-directory.js.map +1 -1
- package/docs/UI_POLISH_ORCHESTRATION.md +44 -0
- package/docs/UI_QUALITY_ORCHESTRATION.md +30 -0
- package/docs/docs.json +4 -0
- package/docs/extensions.md +62 -2
- package/docs/harness-architecture.md +156 -0
- package/docs/keybindings.md +11 -1
- package/docs/process-matrix.md +153 -0
- package/docs/rpc.md +45 -2
- package/docs/sessions.md +15 -0
- package/docs/settings.md +128 -11
- package/docs/task-steps.md +8 -0
- package/docs/telemetry.md +19 -0
- package/docs/tmux-agent-manager.md +92 -2
- package/docs/ui-reference/README.md +9 -0
- package/docs/ui-reference/orchestration-after.txt +7 -0
- package/docs/ui-reference/orchestration-before.txt +7 -0
- package/docs/ui-reference/orchestration-reference.txt +6 -0
- package/docs/usage.md +14 -2
- package/docs/windows.md +52 -3
- package/docs/work-directory.md +42 -2
- package/docs/worktree-sync.md +250 -0
- 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/question.ts +34 -245
- package/examples/extensions/questionnaire.ts +41 -407
- 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/npm-shrinkwrap.json +12 -12
- package/package.json +10 -4
- package/dist/core/delegation/session-worker-result.d.ts +0 -16
- package/dist/core/delegation/session-worker-result.d.ts.map +0 -1
- package/dist/core/delegation/session-worker-result.js +0 -53
- package/dist/core/delegation/session-worker-result.js.map +0 -1
- package/dist/core/delegation/worker-result.d.ts +0 -15
- package/dist/core/delegation/worker-result.d.ts.map +0 -1
- package/dist/core/delegation/worker-result.js +0 -161
- package/dist/core/delegation/worker-result.js.map +0 -1
- package/dist/core/telemetry.d.ts.map +0 -1
- package/dist/core/telemetry.js.map +0 -1
- package/docs/integration-sweep-builder-blueprint-2026-07-09.md +0 -365
- package/docs/integration-sweep-resume-2026-07-09.md +0 -407
|
@@ -57,4 +57,38 @@ export declare const MODEL_CAPABILITY_LEAN_MAX_CONTINUE_WALL_CLOCK_MINUTES = 5;
|
|
|
57
57
|
export declare function scaleContinuationBudgetsForCapability(profile: ModelCapabilityProfile, budgets: ContinuationBudgets): ContinuationBudgets;
|
|
58
58
|
/** Apply the profile's allow/block lists to a requested tool-name list, preserving order. */
|
|
59
59
|
export declare function filterToolNamesForCapability(toolNames: readonly string[], profile: ModelCapabilityProfile): string[];
|
|
60
|
+
/**
|
|
61
|
+
* Lane-worker eligibility: a session bound to a worktree-sync lane (`--worktree-lane` /
|
|
62
|
+
* `PI_WORKTREE_LANE`, see worktree-sync/runtime.ts) is expected to drive the FULL multi-step
|
|
63
|
+
* lane-gate/recovery surface -- sync, conflict recovery, land -- unattended. A sub-full capability
|
|
64
|
+
* class or a model with no working native tool-call path cannot reliably drive that surface. This
|
|
65
|
+
* rides the SAME capability system every other adaptation in this file rides (class + context
|
|
66
|
+
* window + the `/toolprobe` verdict) -- no parallel mechanism, no new env var, no new registry field.
|
|
67
|
+
*/
|
|
68
|
+
export type LaneWorkerRefusalReason = "capability_class_below_full" | "context_window_unknown" | "tool_calling_unadvertised" | "tool_calling_demoted";
|
|
69
|
+
export interface LaneWorkerRefusal {
|
|
70
|
+
reason: LaneWorkerRefusalReason;
|
|
71
|
+
capabilityClass: ModelCapabilityClass;
|
|
72
|
+
contextWindow?: number;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Decide whether the model described by `args` may drive a worktree-sync lane worker. First
|
|
76
|
+
* failure wins, in order: capability class below full; an unknown/undeclared context window (the
|
|
77
|
+
* classifier's own registry-derived SSOT -- see `deriveModelCapabilityProfile`; a full class can
|
|
78
|
+
* still carry an undefined window via the `unknown_context_window_defaults` fallback); no
|
|
79
|
+
* ADVERTISED native tool-call path (`Model.textToolCallProtocol` unset/false -- set true means
|
|
80
|
+
* phone-only); or a GRADED `/toolprobe` demotion to "text-protocol"/"none". An UNPROBED model (no
|
|
81
|
+
* verdict on record yet) is eligible on its advertised support alone -- unprobed is never treated
|
|
82
|
+
* as demoted. `undefined` means eligible.
|
|
83
|
+
*/
|
|
84
|
+
export declare function evaluateLaneWorkerRefusal(args: {
|
|
85
|
+
capabilityClass: ModelCapabilityClass;
|
|
86
|
+
contextWindow: number | undefined;
|
|
87
|
+
toolCallingAdvertised: boolean;
|
|
88
|
+
toolCallingDemoted: boolean;
|
|
89
|
+
}): LaneWorkerRefusal | undefined;
|
|
90
|
+
/** Stable, greppable prefix for {@link formatLaneWorkerRefusal}'s output. */
|
|
91
|
+
export declare const LANE_WORKER_REFUSAL_PREFIX = "worktree-sync lane-worker refusal:";
|
|
92
|
+
/** Format a refusal into one deterministic, greppable line naming the lane, class, window, and reason. */
|
|
93
|
+
export declare function formatLaneWorkerRefusal(refusal: LaneWorkerRefusal, laneKey?: string): string;
|
|
60
94
|
//# sourceMappingURL=model-capability.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-capability.d.ts","sourceRoot":"","sources":["../../src/core/model-capability.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;AAExE,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,KAAK,GAAG,oBAAoB,CAAC;AAExE,MAAM,WAAW,sBAAsB;IACtC,KAAK,EAAE,oBAAoB,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,0FAA0F;IAC1F,sBAAsB,EAAE,OAAO,CAAC;IAChC,4EAA4E;IAC5E,mBAAmB,EAAE,MAAM,CAAC;CAC5B;AAED,8DAA8D;AAC9D,eAAO,MAAM,iCAAiC,QAAS,CAAC;AACxD,oFAAoF;AACpF,eAAO,MAAM,iCAAiC,QAAS,CAAC;AACxD,+EAA+E;AAC/E,eAAO,MAAM,oCAAoC,OAAQ,CAAC;AAE1D,eAAO,MAAM,mCAAmC,EAAE,SAAS,MAAM,EAAkC,CAAC;AACpG,eAAO,MAAM,sCAAsC,EAAE,SAAS,MAAM,EASnE,CAAC;AACF,eAAO,MAAM,mCAAmC,EAAE,SAAS,MAAM,EAAO,CAAC;AAEzE,eAAO,MAAM,8BAA8B,OAAO,CAAC;AA0CnD,wBAAgB,4BAA4B,CAAC,IAAI,EAAE;IAClD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,mBAAmB,CAAC;CAC3B,GAAG,sBAAsB,CA2BzB;AAED,uFAAuF;AACvF,MAAM,WAAW,mBAAmB;IACnC,uDAAuD;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB,8EAA8E;IAC9E,mBAAmB,EAAE,MAAM,CAAC;CAC5B;AAED,6FAA6F;AAC7F,eAAO,MAAM,wCAAwC,IAAI,CAAC;AAC1D,eAAO,MAAM,qDAAqD,IAAI,CAAC;AAEvE;;;;;;;GAOG;AACH,wBAAgB,qCAAqC,CACpD,OAAO,EAAE,sBAAsB,EAC/B,OAAO,EAAE,mBAAmB,GAC1B,mBAAmB,CAMrB;AAED,6FAA6F;AAC7F,wBAAgB,4BAA4B,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,EAAE,sBAAsB,GAAG,MAAM,EAAE,CAWpH","sourcesContent":["/**\n * Model capability auto-detection: derive what the harness may load onto a model FROM the model's\n * own metadata (`Model.contextWindow`), so small open models (4k/8k/16k windows, sub-1B params)\n * can still hold a usable chat instead of drowning in tool schemas and background-lane prompts.\n *\n * Derivation is metadata-first; defaults apply only when the metadata is missing (unknown/zero\n * window keeps today's full behavior rather than guessing). Detection can be disabled or forced\n * per class via the `modelCapability.mode` setting.\n */\n\nexport type ModelCapabilityClass = \"full\" | \"lean\" | \"minimal\" | \"chat\";\n\nexport type ModelCapabilityMode = \"auto\" | \"off\" | ModelCapabilityClass;\n\nexport interface ModelCapabilityProfile {\n\tclass: ModelCapabilityClass;\n\tcontextWindow?: number;\n\treasonCode: string;\n\t/** Allow-list; undefined = no allow-list restriction. */\n\tallowedToolNames?: readonly string[];\n\t/** Block-list applied after the allow-list; undefined = nothing blocked. */\n\tblockedToolNames?: readonly string[];\n\t/** Whether idle background lanes (goal auto-continue, research) may run on this model. */\n\tbackgroundLanesEnabled: boolean;\n\t/** Output-token cap for lane isolated completions, scaled to the window. */\n\tlaneMaxOutputTokens: number;\n}\n\n/** Windows at or above this keep the full harness surface. */\nexport const MODEL_CAPABILITY_FULL_MIN_CONTEXT = 32_768;\n/** Windows at or above this keep core tools but shed background-autonomy extras. */\nexport const MODEL_CAPABILITY_LEAN_MIN_CONTEXT = 16_384;\n/** Windows at or above this get the minimal coding set; below is chat-only. */\nexport const MODEL_CAPABILITY_MINIMAL_MIN_CONTEXT = 8_192;\n\nexport const MODEL_CAPABILITY_LEAN_BLOCKED_TOOLS: readonly string[] = [\"delegate\", \"context_audit\"];\nexport const MODEL_CAPABILITY_MINIMAL_ALLOWED_TOOLS: readonly string[] = [\n\t\"read\",\n\t\"bash\",\n\t\"python\",\n\t\"powershell\",\n\t\"edit\",\n\t\"write\",\n\t// The executor tool: minimal-class models ARE the daily-ops executors, and its schema is tiny.\n\t\"run_toolkit_script\",\n];\nexport const MODEL_CAPABILITY_CHAT_ALLOWED_TOOLS: readonly string[] = [];\n\nexport const DEFAULT_LANE_MAX_OUTPUT_TOKENS = 2048;\nconst MIN_LANE_MAX_OUTPUT_TOKENS = 256;\n\nfunction laneOutputTokensForWindow(contextWindow: number | undefined): number {\n\tif (contextWindow === undefined || contextWindow <= 0) return DEFAULT_LANE_MAX_OUTPUT_TOKENS;\n\t// A lane completion may use at most an eighth of the window for output, floored so tiny\n\t// windows still produce something parseable.\n\treturn Math.min(DEFAULT_LANE_MAX_OUTPUT_TOKENS, Math.max(MIN_LANE_MAX_OUTPUT_TOKENS, Math.floor(contextWindow / 8)));\n}\n\nfunction profileForClass(\n\tcapabilityClass: ModelCapabilityClass,\n\treasonCode: string,\n\tcontextWindow: number | undefined,\n): ModelCapabilityProfile {\n\tconst base = {\n\t\tclass: capabilityClass,\n\t\treasonCode,\n\t\tbackgroundLanesEnabled: true,\n\t\tlaneMaxOutputTokens: laneOutputTokensForWindow(contextWindow),\n\t\t...(contextWindow !== undefined && contextWindow > 0 ? { contextWindow } : {}),\n\t};\n\tswitch (capabilityClass) {\n\t\tcase \"full\":\n\t\t\treturn base;\n\t\tcase \"lean\":\n\t\t\treturn { ...base, blockedToolNames: MODEL_CAPABILITY_LEAN_BLOCKED_TOOLS };\n\t\tcase \"minimal\":\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\tallowedToolNames: MODEL_CAPABILITY_MINIMAL_ALLOWED_TOOLS,\n\t\t\t\tbackgroundLanesEnabled: false,\n\t\t\t};\n\t\tcase \"chat\":\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\tallowedToolNames: MODEL_CAPABILITY_CHAT_ALLOWED_TOOLS,\n\t\t\t\tbackgroundLanesEnabled: false,\n\t\t\t};\n\t}\n}\n\nexport function deriveModelCapabilityProfile(args: {\n\tcontextWindow?: number;\n\tmode?: ModelCapabilityMode;\n}): ModelCapabilityProfile {\n\tconst mode = args.mode ?? \"auto\";\n\tconst contextWindow =\n\t\targs.contextWindow !== undefined && Number.isFinite(args.contextWindow) && args.contextWindow > 0\n\t\t\t? args.contextWindow\n\t\t\t: undefined;\n\tif (mode === \"off\") {\n\t\treturn profileForClass(\"full\", \"detection_disabled\", contextWindow);\n\t}\n\tif (mode !== \"auto\") {\n\t\treturn profileForClass(mode, \"forced_by_setting\", contextWindow);\n\t}\n\n\tif (contextWindow === undefined) {\n\t\t// Metadata missing: defaults, never guesses.\n\t\treturn profileForClass(\"full\", \"unknown_context_window_defaults\", undefined);\n\t}\n\tif (contextWindow >= MODEL_CAPABILITY_FULL_MIN_CONTEXT) {\n\t\treturn profileForClass(\"full\", \"large_context_window\", contextWindow);\n\t}\n\tif (contextWindow >= MODEL_CAPABILITY_LEAN_MIN_CONTEXT) {\n\t\treturn profileForClass(\"lean\", \"lean_context_window\", contextWindow);\n\t}\n\tif (contextWindow >= MODEL_CAPABILITY_MINIMAL_MIN_CONTEXT) {\n\t\treturn profileForClass(\"minimal\", \"minimal_context_window\", contextWindow);\n\t}\n\treturn profileForClass(\"chat\", \"chat_only_context_window\", contextWindow);\n}\n\n/** Goal-continuation (autosteer) budgets, scaled to the session's capability class. */\nexport interface ContinuationBudgets {\n\t/** Maximum continuation prompts per idle goal loop. */\n\tmaxTurns: number;\n\t/** Wall-clock budget in minutes; 0 means \"disabled\" (upstream convention). */\n\tmaxWallClockMinutes: number;\n}\n\n/** Lean-class continuation caps: a 16-32k window cannot afford the full autosteer budget. */\nexport const MODEL_CAPABILITY_LEAN_MAX_CONTINUE_TURNS = 2;\nexport const MODEL_CAPABILITY_LEAN_MAX_CONTINUE_WALL_CLOCK_MINUTES = 5;\n\n/**\n * Scale goal-continuation budgets to the model's capability class. Lean-window models (16-32k) keep\n * autonomy but at a reduced budget; every other class passes the configured budget through unchanged\n * (full stays full; minimal/chat never reach here — their background lanes are disabled upstream).\n *\n * Both dimensions are a straight `min(configured, cap)`: a disabled wall-clock budget (0) stays\n * disabled because `min(0, cap) === 0`, so the cap only ever tightens an already-positive budget.\n */\nexport function scaleContinuationBudgetsForCapability(\n\tprofile: ModelCapabilityProfile,\n\tbudgets: ContinuationBudgets,\n): ContinuationBudgets {\n\tif (profile.class !== \"lean\") return budgets;\n\treturn {\n\t\tmaxTurns: Math.min(budgets.maxTurns, MODEL_CAPABILITY_LEAN_MAX_CONTINUE_TURNS),\n\t\tmaxWallClockMinutes: Math.min(budgets.maxWallClockMinutes, MODEL_CAPABILITY_LEAN_MAX_CONTINUE_WALL_CLOCK_MINUTES),\n\t};\n}\n\n/** Apply the profile's allow/block lists to a requested tool-name list, preserving order. */\nexport function filterToolNamesForCapability(toolNames: readonly string[], profile: ModelCapabilityProfile): string[] {\n\tlet filtered = [...toolNames];\n\tif (profile.allowedToolNames !== undefined) {\n\t\tconst allowed = new Set(profile.allowedToolNames);\n\t\tfiltered = filtered.filter((name) => allowed.has(name));\n\t}\n\tif (profile.blockedToolNames !== undefined) {\n\t\tconst blocked = new Set(profile.blockedToolNames);\n\t\tfiltered = filtered.filter((name) => !blocked.has(name));\n\t}\n\treturn filtered;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"model-capability.d.ts","sourceRoot":"","sources":["../../src/core/model-capability.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;AAExE,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,KAAK,GAAG,oBAAoB,CAAC;AAExE,MAAM,WAAW,sBAAsB;IACtC,KAAK,EAAE,oBAAoB,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,0FAA0F;IAC1F,sBAAsB,EAAE,OAAO,CAAC;IAChC,4EAA4E;IAC5E,mBAAmB,EAAE,MAAM,CAAC;CAC5B;AAED,8DAA8D;AAC9D,eAAO,MAAM,iCAAiC,QAAS,CAAC;AACxD,oFAAoF;AACpF,eAAO,MAAM,iCAAiC,QAAS,CAAC;AACxD,+EAA+E;AAC/E,eAAO,MAAM,oCAAoC,OAAQ,CAAC;AAE1D,eAAO,MAAM,mCAAmC,EAAE,SAAS,MAAM,EAWhE,CAAC;AACF,eAAO,MAAM,sCAAsC,EAAE,SAAS,MAAM,EAUnE,CAAC;AACF,eAAO,MAAM,mCAAmC,EAAE,SAAS,MAAM,EAAO,CAAC;AAEzE,eAAO,MAAM,8BAA8B,OAAO,CAAC;AA0CnD,wBAAgB,4BAA4B,CAAC,IAAI,EAAE;IAClD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,mBAAmB,CAAC;CAC3B,GAAG,sBAAsB,CA2BzB;AAED,uFAAuF;AACvF,MAAM,WAAW,mBAAmB;IACnC,uDAAuD;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB,8EAA8E;IAC9E,mBAAmB,EAAE,MAAM,CAAC;CAC5B;AAED,6FAA6F;AAC7F,eAAO,MAAM,wCAAwC,IAAI,CAAC;AAC1D,eAAO,MAAM,qDAAqD,IAAI,CAAC;AAEvE;;;;;;;GAOG;AACH,wBAAgB,qCAAqC,CACpD,OAAO,EAAE,sBAAsB,EAC/B,OAAO,EAAE,mBAAmB,GAC1B,mBAAmB,CAMrB;AAED,6FAA6F;AAC7F,wBAAgB,4BAA4B,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,EAAE,sBAAsB,GAAG,MAAM,EAAE,CAWpH;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,uBAAuB,GAChC,6BAA6B,GAC7B,wBAAwB,GACxB,2BAA2B,GAC3B,sBAAsB,CAAC;AAE1B,MAAM,WAAW,iBAAiB;IACjC,MAAM,EAAE,uBAAuB,CAAC;IAChC,eAAe,EAAE,oBAAoB,CAAC;IACtC,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE;IAC/C,eAAe,EAAE,oBAAoB,CAAC;IACtC,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,qBAAqB,EAAE,OAAO,CAAC;IAC/B,kBAAkB,EAAE,OAAO,CAAC;CAC5B,GAAG,iBAAiB,GAAG,SAAS,CAOhC;AAED,6EAA6E;AAC7E,eAAO,MAAM,0BAA0B,uCAAuC,CAAC;AAE/E,0GAA0G;AAC1G,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,iBAAiB,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAI5F","sourcesContent":["/**\n * Model capability auto-detection: derive what the harness may load onto a model FROM the model's\n * own metadata (`Model.contextWindow`), so small open models (4k/8k/16k windows, sub-1B params)\n * can still hold a usable chat instead of drowning in tool schemas and background-lane prompts.\n *\n * Derivation is metadata-first; defaults apply only when the metadata is missing (unknown/zero\n * window keeps today's full behavior rather than guessing). Detection can be disabled or forced\n * per class via the `modelCapability.mode` setting.\n */\n\nexport type ModelCapabilityClass = \"full\" | \"lean\" | \"minimal\" | \"chat\";\n\nexport type ModelCapabilityMode = \"auto\" | \"off\" | ModelCapabilityClass;\n\nexport interface ModelCapabilityProfile {\n\tclass: ModelCapabilityClass;\n\tcontextWindow?: number;\n\treasonCode: string;\n\t/** Allow-list; undefined = no allow-list restriction. */\n\tallowedToolNames?: readonly string[];\n\t/** Block-list applied after the allow-list; undefined = nothing blocked. */\n\tblockedToolNames?: readonly string[];\n\t/** Whether idle background lanes (goal auto-continue, research) may run on this model. */\n\tbackgroundLanesEnabled: boolean;\n\t/** Output-token cap for lane isolated completions, scaled to the window. */\n\tlaneMaxOutputTokens: number;\n}\n\n/** Windows at or above this keep the full harness surface. */\nexport const MODEL_CAPABILITY_FULL_MIN_CONTEXT = 32_768;\n/** Windows at or above this keep core tools but shed background-autonomy extras. */\nexport const MODEL_CAPABILITY_LEAN_MIN_CONTEXT = 16_384;\n/** Windows at or above this get the minimal coding set; below is chat-only. */\nexport const MODEL_CAPABILITY_MINIMAL_MIN_CONTEXT = 8_192;\n\nexport const MODEL_CAPABILITY_LEAN_BLOCKED_TOOLS: readonly string[] = [\n\t\"delegate\",\n\t\"context_audit\",\n\t\"goal\",\n\t\"worktree_sync\",\n\t\"improvement_loop\",\n\t\"extensionify\",\n\t\"skillify\",\n\t\"model_fitness\",\n\t\"context_scout\",\n\t\"tmux_agent_manager\",\n];\nexport const MODEL_CAPABILITY_MINIMAL_ALLOWED_TOOLS: readonly string[] = [\n\t\"read\",\n\t\"bash\",\n\t\"python\",\n\t\"powershell\",\n\t\"edit\",\n\t\"write\",\n\t\"ask_question\",\n\t// The executor tool: minimal-class models ARE the daily-ops executors, and its schema is tiny.\n\t\"run_toolkit_script\",\n];\nexport const MODEL_CAPABILITY_CHAT_ALLOWED_TOOLS: readonly string[] = [];\n\nexport const DEFAULT_LANE_MAX_OUTPUT_TOKENS = 2048;\nconst MIN_LANE_MAX_OUTPUT_TOKENS = 256;\n\nfunction laneOutputTokensForWindow(contextWindow: number | undefined): number {\n\tif (contextWindow === undefined || contextWindow <= 0) return DEFAULT_LANE_MAX_OUTPUT_TOKENS;\n\t// A lane completion may use at most an eighth of the window for output, floored so tiny\n\t// windows still produce something parseable.\n\treturn Math.min(DEFAULT_LANE_MAX_OUTPUT_TOKENS, Math.max(MIN_LANE_MAX_OUTPUT_TOKENS, Math.floor(contextWindow / 8)));\n}\n\nfunction profileForClass(\n\tcapabilityClass: ModelCapabilityClass,\n\treasonCode: string,\n\tcontextWindow: number | undefined,\n): ModelCapabilityProfile {\n\tconst base = {\n\t\tclass: capabilityClass,\n\t\treasonCode,\n\t\tbackgroundLanesEnabled: true,\n\t\tlaneMaxOutputTokens: laneOutputTokensForWindow(contextWindow),\n\t\t...(contextWindow !== undefined && contextWindow > 0 ? { contextWindow } : {}),\n\t};\n\tswitch (capabilityClass) {\n\t\tcase \"full\":\n\t\t\treturn base;\n\t\tcase \"lean\":\n\t\t\treturn { ...base, blockedToolNames: MODEL_CAPABILITY_LEAN_BLOCKED_TOOLS };\n\t\tcase \"minimal\":\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\tallowedToolNames: MODEL_CAPABILITY_MINIMAL_ALLOWED_TOOLS,\n\t\t\t\tbackgroundLanesEnabled: false,\n\t\t\t};\n\t\tcase \"chat\":\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\tallowedToolNames: MODEL_CAPABILITY_CHAT_ALLOWED_TOOLS,\n\t\t\t\tbackgroundLanesEnabled: false,\n\t\t\t};\n\t}\n}\n\nexport function deriveModelCapabilityProfile(args: {\n\tcontextWindow?: number;\n\tmode?: ModelCapabilityMode;\n}): ModelCapabilityProfile {\n\tconst mode = args.mode ?? \"auto\";\n\tconst contextWindow =\n\t\targs.contextWindow !== undefined && Number.isFinite(args.contextWindow) && args.contextWindow > 0\n\t\t\t? args.contextWindow\n\t\t\t: undefined;\n\tif (mode === \"off\") {\n\t\treturn profileForClass(\"full\", \"detection_disabled\", contextWindow);\n\t}\n\tif (mode !== \"auto\") {\n\t\treturn profileForClass(mode, \"forced_by_setting\", contextWindow);\n\t}\n\n\tif (contextWindow === undefined) {\n\t\t// Metadata missing: defaults, never guesses.\n\t\treturn profileForClass(\"full\", \"unknown_context_window_defaults\", undefined);\n\t}\n\tif (contextWindow >= MODEL_CAPABILITY_FULL_MIN_CONTEXT) {\n\t\treturn profileForClass(\"full\", \"large_context_window\", contextWindow);\n\t}\n\tif (contextWindow >= MODEL_CAPABILITY_LEAN_MIN_CONTEXT) {\n\t\treturn profileForClass(\"lean\", \"lean_context_window\", contextWindow);\n\t}\n\tif (contextWindow >= MODEL_CAPABILITY_MINIMAL_MIN_CONTEXT) {\n\t\treturn profileForClass(\"minimal\", \"minimal_context_window\", contextWindow);\n\t}\n\treturn profileForClass(\"chat\", \"chat_only_context_window\", contextWindow);\n}\n\n/** Goal-continuation (autosteer) budgets, scaled to the session's capability class. */\nexport interface ContinuationBudgets {\n\t/** Maximum continuation prompts per idle goal loop. */\n\tmaxTurns: number;\n\t/** Wall-clock budget in minutes; 0 means \"disabled\" (upstream convention). */\n\tmaxWallClockMinutes: number;\n}\n\n/** Lean-class continuation caps: a 16-32k window cannot afford the full autosteer budget. */\nexport const MODEL_CAPABILITY_LEAN_MAX_CONTINUE_TURNS = 2;\nexport const MODEL_CAPABILITY_LEAN_MAX_CONTINUE_WALL_CLOCK_MINUTES = 5;\n\n/**\n * Scale goal-continuation budgets to the model's capability class. Lean-window models (16-32k) keep\n * autonomy but at a reduced budget; every other class passes the configured budget through unchanged\n * (full stays full; minimal/chat never reach here — their background lanes are disabled upstream).\n *\n * Both dimensions are a straight `min(configured, cap)`: a disabled wall-clock budget (0) stays\n * disabled because `min(0, cap) === 0`, so the cap only ever tightens an already-positive budget.\n */\nexport function scaleContinuationBudgetsForCapability(\n\tprofile: ModelCapabilityProfile,\n\tbudgets: ContinuationBudgets,\n): ContinuationBudgets {\n\tif (profile.class !== \"lean\") return budgets;\n\treturn {\n\t\tmaxTurns: Math.min(budgets.maxTurns, MODEL_CAPABILITY_LEAN_MAX_CONTINUE_TURNS),\n\t\tmaxWallClockMinutes: Math.min(budgets.maxWallClockMinutes, MODEL_CAPABILITY_LEAN_MAX_CONTINUE_WALL_CLOCK_MINUTES),\n\t};\n}\n\n/** Apply the profile's allow/block lists to a requested tool-name list, preserving order. */\nexport function filterToolNamesForCapability(toolNames: readonly string[], profile: ModelCapabilityProfile): string[] {\n\tlet filtered = [...toolNames];\n\tif (profile.allowedToolNames !== undefined) {\n\t\tconst allowed = new Set(profile.allowedToolNames);\n\t\tfiltered = filtered.filter((name) => allowed.has(name));\n\t}\n\tif (profile.blockedToolNames !== undefined) {\n\t\tconst blocked = new Set(profile.blockedToolNames);\n\t\tfiltered = filtered.filter((name) => !blocked.has(name));\n\t}\n\treturn filtered;\n}\n\n/**\n * Lane-worker eligibility: a session bound to a worktree-sync lane (`--worktree-lane` /\n * `PI_WORKTREE_LANE`, see worktree-sync/runtime.ts) is expected to drive the FULL multi-step\n * lane-gate/recovery surface -- sync, conflict recovery, land -- unattended. A sub-full capability\n * class or a model with no working native tool-call path cannot reliably drive that surface. This\n * rides the SAME capability system every other adaptation in this file rides (class + context\n * window + the `/toolprobe` verdict) -- no parallel mechanism, no new env var, no new registry field.\n */\nexport type LaneWorkerRefusalReason =\n\t| \"capability_class_below_full\"\n\t| \"context_window_unknown\"\n\t| \"tool_calling_unadvertised\"\n\t| \"tool_calling_demoted\";\n\nexport interface LaneWorkerRefusal {\n\treason: LaneWorkerRefusalReason;\n\tcapabilityClass: ModelCapabilityClass;\n\tcontextWindow?: number;\n}\n\n/**\n * Decide whether the model described by `args` may drive a worktree-sync lane worker. First\n * failure wins, in order: capability class below full; an unknown/undeclared context window (the\n * classifier's own registry-derived SSOT -- see `deriveModelCapabilityProfile`; a full class can\n * still carry an undefined window via the `unknown_context_window_defaults` fallback); no\n * ADVERTISED native tool-call path (`Model.textToolCallProtocol` unset/false -- set true means\n * phone-only); or a GRADED `/toolprobe` demotion to \"text-protocol\"/\"none\". An UNPROBED model (no\n * verdict on record yet) is eligible on its advertised support alone -- unprobed is never treated\n * as demoted. `undefined` means eligible.\n */\nexport function evaluateLaneWorkerRefusal(args: {\n\tcapabilityClass: ModelCapabilityClass;\n\tcontextWindow: number | undefined;\n\ttoolCallingAdvertised: boolean;\n\ttoolCallingDemoted: boolean;\n}): LaneWorkerRefusal | undefined {\n\tconst { capabilityClass, contextWindow, toolCallingAdvertised, toolCallingDemoted } = args;\n\tif (capabilityClass !== \"full\") return { reason: \"capability_class_below_full\", capabilityClass, contextWindow };\n\tif (contextWindow === undefined) return { reason: \"context_window_unknown\", capabilityClass, contextWindow };\n\tif (!toolCallingAdvertised) return { reason: \"tool_calling_unadvertised\", capabilityClass, contextWindow };\n\tif (toolCallingDemoted) return { reason: \"tool_calling_demoted\", capabilityClass, contextWindow };\n\treturn undefined;\n}\n\n/** Stable, greppable prefix for {@link formatLaneWorkerRefusal}'s output. */\nexport const LANE_WORKER_REFUSAL_PREFIX = \"worktree-sync lane-worker refusal:\";\n\n/** Format a refusal into one deterministic, greppable line naming the lane, class, window, and reason. */\nexport function formatLaneWorkerRefusal(refusal: LaneWorkerRefusal, laneKey?: string): string {\n\tconst laneSuffix = laneKey !== undefined ? ` lane=${laneKey}` : \"\";\n\tconst windowText = refusal.contextWindow !== undefined ? String(refusal.contextWindow) : \"unknown\";\n\treturn `${LANE_WORKER_REFUSAL_PREFIX}${laneSuffix} class=${refusal.capabilityClass} contextWindow=${windowText} reason=${refusal.reason}`;\n}\n"]}
|
|
@@ -13,7 +13,18 @@ export const MODEL_CAPABILITY_FULL_MIN_CONTEXT = 32_768;
|
|
|
13
13
|
export const MODEL_CAPABILITY_LEAN_MIN_CONTEXT = 16_384;
|
|
14
14
|
/** Windows at or above this get the minimal coding set; below is chat-only. */
|
|
15
15
|
export const MODEL_CAPABILITY_MINIMAL_MIN_CONTEXT = 8_192;
|
|
16
|
-
export const MODEL_CAPABILITY_LEAN_BLOCKED_TOOLS = [
|
|
16
|
+
export const MODEL_CAPABILITY_LEAN_BLOCKED_TOOLS = [
|
|
17
|
+
"delegate",
|
|
18
|
+
"context_audit",
|
|
19
|
+
"goal",
|
|
20
|
+
"worktree_sync",
|
|
21
|
+
"improvement_loop",
|
|
22
|
+
"extensionify",
|
|
23
|
+
"skillify",
|
|
24
|
+
"model_fitness",
|
|
25
|
+
"context_scout",
|
|
26
|
+
"tmux_agent_manager",
|
|
27
|
+
];
|
|
17
28
|
export const MODEL_CAPABILITY_MINIMAL_ALLOWED_TOOLS = [
|
|
18
29
|
"read",
|
|
19
30
|
"bash",
|
|
@@ -21,6 +32,7 @@ export const MODEL_CAPABILITY_MINIMAL_ALLOWED_TOOLS = [
|
|
|
21
32
|
"powershell",
|
|
22
33
|
"edit",
|
|
23
34
|
"write",
|
|
35
|
+
"ask_question",
|
|
24
36
|
// The executor tool: minimal-class models ARE the daily-ops executors, and its schema is tiny.
|
|
25
37
|
"run_toolkit_script",
|
|
26
38
|
];
|
|
@@ -119,4 +131,34 @@ export function filterToolNamesForCapability(toolNames, profile) {
|
|
|
119
131
|
}
|
|
120
132
|
return filtered;
|
|
121
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* Decide whether the model described by `args` may drive a worktree-sync lane worker. First
|
|
136
|
+
* failure wins, in order: capability class below full; an unknown/undeclared context window (the
|
|
137
|
+
* classifier's own registry-derived SSOT -- see `deriveModelCapabilityProfile`; a full class can
|
|
138
|
+
* still carry an undefined window via the `unknown_context_window_defaults` fallback); no
|
|
139
|
+
* ADVERTISED native tool-call path (`Model.textToolCallProtocol` unset/false -- set true means
|
|
140
|
+
* phone-only); or a GRADED `/toolprobe` demotion to "text-protocol"/"none". An UNPROBED model (no
|
|
141
|
+
* verdict on record yet) is eligible on its advertised support alone -- unprobed is never treated
|
|
142
|
+
* as demoted. `undefined` means eligible.
|
|
143
|
+
*/
|
|
144
|
+
export function evaluateLaneWorkerRefusal(args) {
|
|
145
|
+
const { capabilityClass, contextWindow, toolCallingAdvertised, toolCallingDemoted } = args;
|
|
146
|
+
if (capabilityClass !== "full")
|
|
147
|
+
return { reason: "capability_class_below_full", capabilityClass, contextWindow };
|
|
148
|
+
if (contextWindow === undefined)
|
|
149
|
+
return { reason: "context_window_unknown", capabilityClass, contextWindow };
|
|
150
|
+
if (!toolCallingAdvertised)
|
|
151
|
+
return { reason: "tool_calling_unadvertised", capabilityClass, contextWindow };
|
|
152
|
+
if (toolCallingDemoted)
|
|
153
|
+
return { reason: "tool_calling_demoted", capabilityClass, contextWindow };
|
|
154
|
+
return undefined;
|
|
155
|
+
}
|
|
156
|
+
/** Stable, greppable prefix for {@link formatLaneWorkerRefusal}'s output. */
|
|
157
|
+
export const LANE_WORKER_REFUSAL_PREFIX = "worktree-sync lane-worker refusal:";
|
|
158
|
+
/** Format a refusal into one deterministic, greppable line naming the lane, class, window, and reason. */
|
|
159
|
+
export function formatLaneWorkerRefusal(refusal, laneKey) {
|
|
160
|
+
const laneSuffix = laneKey !== undefined ? ` lane=${laneKey}` : "";
|
|
161
|
+
const windowText = refusal.contextWindow !== undefined ? String(refusal.contextWindow) : "unknown";
|
|
162
|
+
return `${LANE_WORKER_REFUSAL_PREFIX}${laneSuffix} class=${refusal.capabilityClass} contextWindow=${windowText} reason=${refusal.reason}`;
|
|
163
|
+
}
|
|
122
164
|
//# sourceMappingURL=model-capability.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-capability.js","sourceRoot":"","sources":["../../src/core/model-capability.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAoBH,8DAA8D;AAC9D,MAAM,CAAC,MAAM,iCAAiC,GAAG,MAAM,CAAC;AACxD,oFAAoF;AACpF,MAAM,CAAC,MAAM,iCAAiC,GAAG,MAAM,CAAC;AACxD,+EAA+E;AAC/E,MAAM,CAAC,MAAM,oCAAoC,GAAG,KAAK,CAAC;AAE1D,MAAM,CAAC,MAAM,mCAAmC,GAAsB,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC;AACpG,MAAM,CAAC,MAAM,sCAAsC,GAAsB;IACxE,MAAM;IACN,MAAM;IACN,QAAQ;IACR,YAAY;IACZ,MAAM;IACN,OAAO;IACP,+FAA+F;IAC/F,oBAAoB;CACpB,CAAC;AACF,MAAM,CAAC,MAAM,mCAAmC,GAAsB,EAAE,CAAC;AAEzE,MAAM,CAAC,MAAM,8BAA8B,GAAG,IAAI,CAAC;AACnD,MAAM,0BAA0B,GAAG,GAAG,CAAC;AAEvC,SAAS,yBAAyB,CAAC,aAAiC,EAAU;IAC7E,IAAI,aAAa,KAAK,SAAS,IAAI,aAAa,IAAI,CAAC;QAAE,OAAO,8BAA8B,CAAC;IAC7F,wFAAwF;IACxF,6CAA6C;IAC7C,OAAO,IAAI,CAAC,GAAG,CAAC,8BAA8B,EAAE,IAAI,CAAC,GAAG,CAAC,0BAA0B,EAAE,IAAI,CAAC,KAAK,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAAA,CACrH;AAED,SAAS,eAAe,CACvB,eAAqC,EACrC,UAAkB,EAClB,aAAiC,EACR;IACzB,MAAM,IAAI,GAAG;QACZ,KAAK,EAAE,eAAe;QACtB,UAAU;QACV,sBAAsB,EAAE,IAAI;QAC5B,mBAAmB,EAAE,yBAAyB,CAAC,aAAa,CAAC;QAC7D,GAAG,CAAC,aAAa,KAAK,SAAS,IAAI,aAAa,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC9E,CAAC;IACF,QAAQ,eAAe,EAAE,CAAC;QACzB,KAAK,MAAM;YACV,OAAO,IAAI,CAAC;QACb,KAAK,MAAM;YACV,OAAO,EAAE,GAAG,IAAI,EAAE,gBAAgB,EAAE,mCAAmC,EAAE,CAAC;QAC3E,KAAK,SAAS;YACb,OAAO;gBACN,GAAG,IAAI;gBACP,gBAAgB,EAAE,sCAAsC;gBACxD,sBAAsB,EAAE,KAAK;aAC7B,CAAC;QACH,KAAK,MAAM;YACV,OAAO;gBACN,GAAG,IAAI;gBACP,gBAAgB,EAAE,mCAAmC;gBACrD,sBAAsB,EAAE,KAAK;aAC7B,CAAC;IACJ,CAAC;AAAA,CACD;AAED,MAAM,UAAU,4BAA4B,CAAC,IAG5C,EAA0B;IAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,MAAM,CAAC;IACjC,MAAM,aAAa,GAClB,IAAI,CAAC,aAAa,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,IAAI,CAAC,aAAa,GAAG,CAAC;QAChG,CAAC,CAAC,IAAI,CAAC,aAAa;QACpB,CAAC,CAAC,SAAS,CAAC;IACd,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;QACpB,OAAO,eAAe,CAAC,MAAM,EAAE,oBAAoB,EAAE,aAAa,CAAC,CAAC;IACrE,CAAC;IACD,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QACrB,OAAO,eAAe,CAAC,IAAI,EAAE,mBAAmB,EAAE,aAAa,CAAC,CAAC;IAClE,CAAC;IAED,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;QACjC,6CAA6C;QAC7C,OAAO,eAAe,CAAC,MAAM,EAAE,iCAAiC,EAAE,SAAS,CAAC,CAAC;IAC9E,CAAC;IACD,IAAI,aAAa,IAAI,iCAAiC,EAAE,CAAC;QACxD,OAAO,eAAe,CAAC,MAAM,EAAE,sBAAsB,EAAE,aAAa,CAAC,CAAC;IACvE,CAAC;IACD,IAAI,aAAa,IAAI,iCAAiC,EAAE,CAAC;QACxD,OAAO,eAAe,CAAC,MAAM,EAAE,qBAAqB,EAAE,aAAa,CAAC,CAAC;IACtE,CAAC;IACD,IAAI,aAAa,IAAI,oCAAoC,EAAE,CAAC;QAC3D,OAAO,eAAe,CAAC,SAAS,EAAE,wBAAwB,EAAE,aAAa,CAAC,CAAC;IAC5E,CAAC;IACD,OAAO,eAAe,CAAC,MAAM,EAAE,0BAA0B,EAAE,aAAa,CAAC,CAAC;AAAA,CAC1E;AAUD,6FAA6F;AAC7F,MAAM,CAAC,MAAM,wCAAwC,GAAG,CAAC,CAAC;AAC1D,MAAM,CAAC,MAAM,qDAAqD,GAAG,CAAC,CAAC;AAEvE;;;;;;;GAOG;AACH,MAAM,UAAU,qCAAqC,CACpD,OAA+B,EAC/B,OAA4B,EACN;IACtB,IAAI,OAAO,CAAC,KAAK,KAAK,MAAM;QAAE,OAAO,OAAO,CAAC;IAC7C,OAAO;QACN,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,wCAAwC,CAAC;QAC9E,mBAAmB,EAAE,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,mBAAmB,EAAE,qDAAqD,CAAC;KACjH,CAAC;AAAA,CACF;AAED,6FAA6F;AAC7F,MAAM,UAAU,4BAA4B,CAAC,SAA4B,EAAE,OAA+B,EAAY;IACrH,IAAI,QAAQ,GAAG,CAAC,GAAG,SAAS,CAAC,CAAC;IAC9B,IAAI,OAAO,CAAC,gBAAgB,KAAK,SAAS,EAAE,CAAC;QAC5C,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QAClD,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IACzD,CAAC;IACD,IAAI,OAAO,CAAC,gBAAgB,KAAK,SAAS,EAAE,CAAC;QAC5C,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QAClD,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,QAAQ,CAAC;AAAA,CAChB","sourcesContent":["/**\n * Model capability auto-detection: derive what the harness may load onto a model FROM the model's\n * own metadata (`Model.contextWindow`), so small open models (4k/8k/16k windows, sub-1B params)\n * can still hold a usable chat instead of drowning in tool schemas and background-lane prompts.\n *\n * Derivation is metadata-first; defaults apply only when the metadata is missing (unknown/zero\n * window keeps today's full behavior rather than guessing). Detection can be disabled or forced\n * per class via the `modelCapability.mode` setting.\n */\n\nexport type ModelCapabilityClass = \"full\" | \"lean\" | \"minimal\" | \"chat\";\n\nexport type ModelCapabilityMode = \"auto\" | \"off\" | ModelCapabilityClass;\n\nexport interface ModelCapabilityProfile {\n\tclass: ModelCapabilityClass;\n\tcontextWindow?: number;\n\treasonCode: string;\n\t/** Allow-list; undefined = no allow-list restriction. */\n\tallowedToolNames?: readonly string[];\n\t/** Block-list applied after the allow-list; undefined = nothing blocked. */\n\tblockedToolNames?: readonly string[];\n\t/** Whether idle background lanes (goal auto-continue, research) may run on this model. */\n\tbackgroundLanesEnabled: boolean;\n\t/** Output-token cap for lane isolated completions, scaled to the window. */\n\tlaneMaxOutputTokens: number;\n}\n\n/** Windows at or above this keep the full harness surface. */\nexport const MODEL_CAPABILITY_FULL_MIN_CONTEXT = 32_768;\n/** Windows at or above this keep core tools but shed background-autonomy extras. */\nexport const MODEL_CAPABILITY_LEAN_MIN_CONTEXT = 16_384;\n/** Windows at or above this get the minimal coding set; below is chat-only. */\nexport const MODEL_CAPABILITY_MINIMAL_MIN_CONTEXT = 8_192;\n\nexport const MODEL_CAPABILITY_LEAN_BLOCKED_TOOLS: readonly string[] = [\"delegate\", \"context_audit\"];\nexport const MODEL_CAPABILITY_MINIMAL_ALLOWED_TOOLS: readonly string[] = [\n\t\"read\",\n\t\"bash\",\n\t\"python\",\n\t\"powershell\",\n\t\"edit\",\n\t\"write\",\n\t// The executor tool: minimal-class models ARE the daily-ops executors, and its schema is tiny.\n\t\"run_toolkit_script\",\n];\nexport const MODEL_CAPABILITY_CHAT_ALLOWED_TOOLS: readonly string[] = [];\n\nexport const DEFAULT_LANE_MAX_OUTPUT_TOKENS = 2048;\nconst MIN_LANE_MAX_OUTPUT_TOKENS = 256;\n\nfunction laneOutputTokensForWindow(contextWindow: number | undefined): number {\n\tif (contextWindow === undefined || contextWindow <= 0) return DEFAULT_LANE_MAX_OUTPUT_TOKENS;\n\t// A lane completion may use at most an eighth of the window for output, floored so tiny\n\t// windows still produce something parseable.\n\treturn Math.min(DEFAULT_LANE_MAX_OUTPUT_TOKENS, Math.max(MIN_LANE_MAX_OUTPUT_TOKENS, Math.floor(contextWindow / 8)));\n}\n\nfunction profileForClass(\n\tcapabilityClass: ModelCapabilityClass,\n\treasonCode: string,\n\tcontextWindow: number | undefined,\n): ModelCapabilityProfile {\n\tconst base = {\n\t\tclass: capabilityClass,\n\t\treasonCode,\n\t\tbackgroundLanesEnabled: true,\n\t\tlaneMaxOutputTokens: laneOutputTokensForWindow(contextWindow),\n\t\t...(contextWindow !== undefined && contextWindow > 0 ? { contextWindow } : {}),\n\t};\n\tswitch (capabilityClass) {\n\t\tcase \"full\":\n\t\t\treturn base;\n\t\tcase \"lean\":\n\t\t\treturn { ...base, blockedToolNames: MODEL_CAPABILITY_LEAN_BLOCKED_TOOLS };\n\t\tcase \"minimal\":\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\tallowedToolNames: MODEL_CAPABILITY_MINIMAL_ALLOWED_TOOLS,\n\t\t\t\tbackgroundLanesEnabled: false,\n\t\t\t};\n\t\tcase \"chat\":\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\tallowedToolNames: MODEL_CAPABILITY_CHAT_ALLOWED_TOOLS,\n\t\t\t\tbackgroundLanesEnabled: false,\n\t\t\t};\n\t}\n}\n\nexport function deriveModelCapabilityProfile(args: {\n\tcontextWindow?: number;\n\tmode?: ModelCapabilityMode;\n}): ModelCapabilityProfile {\n\tconst mode = args.mode ?? \"auto\";\n\tconst contextWindow =\n\t\targs.contextWindow !== undefined && Number.isFinite(args.contextWindow) && args.contextWindow > 0\n\t\t\t? args.contextWindow\n\t\t\t: undefined;\n\tif (mode === \"off\") {\n\t\treturn profileForClass(\"full\", \"detection_disabled\", contextWindow);\n\t}\n\tif (mode !== \"auto\") {\n\t\treturn profileForClass(mode, \"forced_by_setting\", contextWindow);\n\t}\n\n\tif (contextWindow === undefined) {\n\t\t// Metadata missing: defaults, never guesses.\n\t\treturn profileForClass(\"full\", \"unknown_context_window_defaults\", undefined);\n\t}\n\tif (contextWindow >= MODEL_CAPABILITY_FULL_MIN_CONTEXT) {\n\t\treturn profileForClass(\"full\", \"large_context_window\", contextWindow);\n\t}\n\tif (contextWindow >= MODEL_CAPABILITY_LEAN_MIN_CONTEXT) {\n\t\treturn profileForClass(\"lean\", \"lean_context_window\", contextWindow);\n\t}\n\tif (contextWindow >= MODEL_CAPABILITY_MINIMAL_MIN_CONTEXT) {\n\t\treturn profileForClass(\"minimal\", \"minimal_context_window\", contextWindow);\n\t}\n\treturn profileForClass(\"chat\", \"chat_only_context_window\", contextWindow);\n}\n\n/** Goal-continuation (autosteer) budgets, scaled to the session's capability class. */\nexport interface ContinuationBudgets {\n\t/** Maximum continuation prompts per idle goal loop. */\n\tmaxTurns: number;\n\t/** Wall-clock budget in minutes; 0 means \"disabled\" (upstream convention). */\n\tmaxWallClockMinutes: number;\n}\n\n/** Lean-class continuation caps: a 16-32k window cannot afford the full autosteer budget. */\nexport const MODEL_CAPABILITY_LEAN_MAX_CONTINUE_TURNS = 2;\nexport const MODEL_CAPABILITY_LEAN_MAX_CONTINUE_WALL_CLOCK_MINUTES = 5;\n\n/**\n * Scale goal-continuation budgets to the model's capability class. Lean-window models (16-32k) keep\n * autonomy but at a reduced budget; every other class passes the configured budget through unchanged\n * (full stays full; minimal/chat never reach here — their background lanes are disabled upstream).\n *\n * Both dimensions are a straight `min(configured, cap)`: a disabled wall-clock budget (0) stays\n * disabled because `min(0, cap) === 0`, so the cap only ever tightens an already-positive budget.\n */\nexport function scaleContinuationBudgetsForCapability(\n\tprofile: ModelCapabilityProfile,\n\tbudgets: ContinuationBudgets,\n): ContinuationBudgets {\n\tif (profile.class !== \"lean\") return budgets;\n\treturn {\n\t\tmaxTurns: Math.min(budgets.maxTurns, MODEL_CAPABILITY_LEAN_MAX_CONTINUE_TURNS),\n\t\tmaxWallClockMinutes: Math.min(budgets.maxWallClockMinutes, MODEL_CAPABILITY_LEAN_MAX_CONTINUE_WALL_CLOCK_MINUTES),\n\t};\n}\n\n/** Apply the profile's allow/block lists to a requested tool-name list, preserving order. */\nexport function filterToolNamesForCapability(toolNames: readonly string[], profile: ModelCapabilityProfile): string[] {\n\tlet filtered = [...toolNames];\n\tif (profile.allowedToolNames !== undefined) {\n\t\tconst allowed = new Set(profile.allowedToolNames);\n\t\tfiltered = filtered.filter((name) => allowed.has(name));\n\t}\n\tif (profile.blockedToolNames !== undefined) {\n\t\tconst blocked = new Set(profile.blockedToolNames);\n\t\tfiltered = filtered.filter((name) => !blocked.has(name));\n\t}\n\treturn filtered;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"model-capability.js","sourceRoot":"","sources":["../../src/core/model-capability.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Model capability auto-detection: derive what the harness may load onto a model FROM the model's\n * own metadata (`Model.contextWindow`), so small open models (4k/8k/16k windows, sub-1B params)\n * can still hold a usable chat instead of drowning in tool schemas and background-lane prompts.\n *\n * Derivation is metadata-first; defaults apply only when the metadata is missing (unknown/zero\n * window keeps today's full behavior rather than guessing). Detection can be disabled or forced\n * per class via the `modelCapability.mode` setting.\n */\n\nexport type ModelCapabilityClass = \"full\" | \"lean\" | \"minimal\" | \"chat\";\n\nexport type ModelCapabilityMode = \"auto\" | \"off\" | ModelCapabilityClass;\n\nexport interface ModelCapabilityProfile {\n\tclass: ModelCapabilityClass;\n\tcontextWindow?: number;\n\treasonCode: string;\n\t/** Allow-list; undefined = no allow-list restriction. */\n\tallowedToolNames?: readonly string[];\n\t/** Block-list applied after the allow-list; undefined = nothing blocked. */\n\tblockedToolNames?: readonly string[];\n\t/** Whether idle background lanes (goal auto-continue, research) may run on this model. */\n\tbackgroundLanesEnabled: boolean;\n\t/** Output-token cap for lane isolated completions, scaled to the window. */\n\tlaneMaxOutputTokens: number;\n}\n\n/** Windows at or above this keep the full harness surface. */\nexport const MODEL_CAPABILITY_FULL_MIN_CONTEXT = 32_768;\n/** Windows at or above this keep core tools but shed background-autonomy extras. */\nexport const MODEL_CAPABILITY_LEAN_MIN_CONTEXT = 16_384;\n/** Windows at or above this get the minimal coding set; below is chat-only. */\nexport const MODEL_CAPABILITY_MINIMAL_MIN_CONTEXT = 8_192;\n\nexport const MODEL_CAPABILITY_LEAN_BLOCKED_TOOLS: readonly string[] = [\n\t\"delegate\",\n\t\"context_audit\",\n\t\"goal\",\n\t\"worktree_sync\",\n\t\"improvement_loop\",\n\t\"extensionify\",\n\t\"skillify\",\n\t\"model_fitness\",\n\t\"context_scout\",\n\t\"tmux_agent_manager\",\n];\nexport const MODEL_CAPABILITY_MINIMAL_ALLOWED_TOOLS: readonly string[] = [\n\t\"read\",\n\t\"bash\",\n\t\"python\",\n\t\"powershell\",\n\t\"edit\",\n\t\"write\",\n\t\"ask_question\",\n\t// The executor tool: minimal-class models ARE the daily-ops executors, and its schema is tiny.\n\t\"run_toolkit_script\",\n];\nexport const MODEL_CAPABILITY_CHAT_ALLOWED_TOOLS: readonly string[] = [];\n\nexport const DEFAULT_LANE_MAX_OUTPUT_TOKENS = 2048;\nconst MIN_LANE_MAX_OUTPUT_TOKENS = 256;\n\nfunction laneOutputTokensForWindow(contextWindow: number | undefined): number {\n\tif (contextWindow === undefined || contextWindow <= 0) return DEFAULT_LANE_MAX_OUTPUT_TOKENS;\n\t// A lane completion may use at most an eighth of the window for output, floored so tiny\n\t// windows still produce something parseable.\n\treturn Math.min(DEFAULT_LANE_MAX_OUTPUT_TOKENS, Math.max(MIN_LANE_MAX_OUTPUT_TOKENS, Math.floor(contextWindow / 8)));\n}\n\nfunction profileForClass(\n\tcapabilityClass: ModelCapabilityClass,\n\treasonCode: string,\n\tcontextWindow: number | undefined,\n): ModelCapabilityProfile {\n\tconst base = {\n\t\tclass: capabilityClass,\n\t\treasonCode,\n\t\tbackgroundLanesEnabled: true,\n\t\tlaneMaxOutputTokens: laneOutputTokensForWindow(contextWindow),\n\t\t...(contextWindow !== undefined && contextWindow > 0 ? { contextWindow } : {}),\n\t};\n\tswitch (capabilityClass) {\n\t\tcase \"full\":\n\t\t\treturn base;\n\t\tcase \"lean\":\n\t\t\treturn { ...base, blockedToolNames: MODEL_CAPABILITY_LEAN_BLOCKED_TOOLS };\n\t\tcase \"minimal\":\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\tallowedToolNames: MODEL_CAPABILITY_MINIMAL_ALLOWED_TOOLS,\n\t\t\t\tbackgroundLanesEnabled: false,\n\t\t\t};\n\t\tcase \"chat\":\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\tallowedToolNames: MODEL_CAPABILITY_CHAT_ALLOWED_TOOLS,\n\t\t\t\tbackgroundLanesEnabled: false,\n\t\t\t};\n\t}\n}\n\nexport function deriveModelCapabilityProfile(args: {\n\tcontextWindow?: number;\n\tmode?: ModelCapabilityMode;\n}): ModelCapabilityProfile {\n\tconst mode = args.mode ?? \"auto\";\n\tconst contextWindow =\n\t\targs.contextWindow !== undefined && Number.isFinite(args.contextWindow) && args.contextWindow > 0\n\t\t\t? args.contextWindow\n\t\t\t: undefined;\n\tif (mode === \"off\") {\n\t\treturn profileForClass(\"full\", \"detection_disabled\", contextWindow);\n\t}\n\tif (mode !== \"auto\") {\n\t\treturn profileForClass(mode, \"forced_by_setting\", contextWindow);\n\t}\n\n\tif (contextWindow === undefined) {\n\t\t// Metadata missing: defaults, never guesses.\n\t\treturn profileForClass(\"full\", \"unknown_context_window_defaults\", undefined);\n\t}\n\tif (contextWindow >= MODEL_CAPABILITY_FULL_MIN_CONTEXT) {\n\t\treturn profileForClass(\"full\", \"large_context_window\", contextWindow);\n\t}\n\tif (contextWindow >= MODEL_CAPABILITY_LEAN_MIN_CONTEXT) {\n\t\treturn profileForClass(\"lean\", \"lean_context_window\", contextWindow);\n\t}\n\tif (contextWindow >= MODEL_CAPABILITY_MINIMAL_MIN_CONTEXT) {\n\t\treturn profileForClass(\"minimal\", \"minimal_context_window\", contextWindow);\n\t}\n\treturn profileForClass(\"chat\", \"chat_only_context_window\", contextWindow);\n}\n\n/** Goal-continuation (autosteer) budgets, scaled to the session's capability class. */\nexport interface ContinuationBudgets {\n\t/** Maximum continuation prompts per idle goal loop. */\n\tmaxTurns: number;\n\t/** Wall-clock budget in minutes; 0 means \"disabled\" (upstream convention). */\n\tmaxWallClockMinutes: number;\n}\n\n/** Lean-class continuation caps: a 16-32k window cannot afford the full autosteer budget. */\nexport const MODEL_CAPABILITY_LEAN_MAX_CONTINUE_TURNS = 2;\nexport const MODEL_CAPABILITY_LEAN_MAX_CONTINUE_WALL_CLOCK_MINUTES = 5;\n\n/**\n * Scale goal-continuation budgets to the model's capability class. Lean-window models (16-32k) keep\n * autonomy but at a reduced budget; every other class passes the configured budget through unchanged\n * (full stays full; minimal/chat never reach here — their background lanes are disabled upstream).\n *\n * Both dimensions are a straight `min(configured, cap)`: a disabled wall-clock budget (0) stays\n * disabled because `min(0, cap) === 0`, so the cap only ever tightens an already-positive budget.\n */\nexport function scaleContinuationBudgetsForCapability(\n\tprofile: ModelCapabilityProfile,\n\tbudgets: ContinuationBudgets,\n): ContinuationBudgets {\n\tif (profile.class !== \"lean\") return budgets;\n\treturn {\n\t\tmaxTurns: Math.min(budgets.maxTurns, MODEL_CAPABILITY_LEAN_MAX_CONTINUE_TURNS),\n\t\tmaxWallClockMinutes: Math.min(budgets.maxWallClockMinutes, MODEL_CAPABILITY_LEAN_MAX_CONTINUE_WALL_CLOCK_MINUTES),\n\t};\n}\n\n/** Apply the profile's allow/block lists to a requested tool-name list, preserving order. */\nexport function filterToolNamesForCapability(toolNames: readonly string[], profile: ModelCapabilityProfile): string[] {\n\tlet filtered = [...toolNames];\n\tif (profile.allowedToolNames !== undefined) {\n\t\tconst allowed = new Set(profile.allowedToolNames);\n\t\tfiltered = filtered.filter((name) => allowed.has(name));\n\t}\n\tif (profile.blockedToolNames !== undefined) {\n\t\tconst blocked = new Set(profile.blockedToolNames);\n\t\tfiltered = filtered.filter((name) => !blocked.has(name));\n\t}\n\treturn filtered;\n}\n\n/**\n * Lane-worker eligibility: a session bound to a worktree-sync lane (`--worktree-lane` /\n * `PI_WORKTREE_LANE`, see worktree-sync/runtime.ts) is expected to drive the FULL multi-step\n * lane-gate/recovery surface -- sync, conflict recovery, land -- unattended. A sub-full capability\n * class or a model with no working native tool-call path cannot reliably drive that surface. This\n * rides the SAME capability system every other adaptation in this file rides (class + context\n * window + the `/toolprobe` verdict) -- no parallel mechanism, no new env var, no new registry field.\n */\nexport type LaneWorkerRefusalReason =\n\t| \"capability_class_below_full\"\n\t| \"context_window_unknown\"\n\t| \"tool_calling_unadvertised\"\n\t| \"tool_calling_demoted\";\n\nexport interface LaneWorkerRefusal {\n\treason: LaneWorkerRefusalReason;\n\tcapabilityClass: ModelCapabilityClass;\n\tcontextWindow?: number;\n}\n\n/**\n * Decide whether the model described by `args` may drive a worktree-sync lane worker. First\n * failure wins, in order: capability class below full; an unknown/undeclared context window (the\n * classifier's own registry-derived SSOT -- see `deriveModelCapabilityProfile`; a full class can\n * still carry an undefined window via the `unknown_context_window_defaults` fallback); no\n * ADVERTISED native tool-call path (`Model.textToolCallProtocol` unset/false -- set true means\n * phone-only); or a GRADED `/toolprobe` demotion to \"text-protocol\"/\"none\". An UNPROBED model (no\n * verdict on record yet) is eligible on its advertised support alone -- unprobed is never treated\n * as demoted. `undefined` means eligible.\n */\nexport function evaluateLaneWorkerRefusal(args: {\n\tcapabilityClass: ModelCapabilityClass;\n\tcontextWindow: number | undefined;\n\ttoolCallingAdvertised: boolean;\n\ttoolCallingDemoted: boolean;\n}): LaneWorkerRefusal | undefined {\n\tconst { capabilityClass, contextWindow, toolCallingAdvertised, toolCallingDemoted } = args;\n\tif (capabilityClass !== \"full\") return { reason: \"capability_class_below_full\", capabilityClass, contextWindow };\n\tif (contextWindow === undefined) return { reason: \"context_window_unknown\", capabilityClass, contextWindow };\n\tif (!toolCallingAdvertised) return { reason: \"tool_calling_unadvertised\", capabilityClass, contextWindow };\n\tif (toolCallingDemoted) return { reason: \"tool_calling_demoted\", capabilityClass, contextWindow };\n\treturn undefined;\n}\n\n/** Stable, greppable prefix for {@link formatLaneWorkerRefusal}'s output. */\nexport const LANE_WORKER_REFUSAL_PREFIX = \"worktree-sync lane-worker refusal:\";\n\n/** Format a refusal into one deterministic, greppable line naming the lane, class, window, and reason. */\nexport function formatLaneWorkerRefusal(refusal: LaneWorkerRefusal, laneKey?: string): string {\n\tconst laneSuffix = laneKey !== undefined ? ` lane=${laneKey}` : \"\";\n\tconst windowText = refusal.contextWindow !== undefined ? String(refusal.contextWindow) : \"unknown\";\n\treturn `${LANE_WORKER_REFUSAL_PREFIX}${laneSuffix} class=${refusal.capabilityClass} contextWindow=${windowText} reason=${refusal.reason}`;\n}\n"]}
|
|
@@ -115,7 +115,7 @@ export declare function restoreModelFromSession(savedProvider: string, savedMode
|
|
|
115
115
|
fallbackMessage: string | undefined;
|
|
116
116
|
}>;
|
|
117
117
|
export interface ResolvedProfileModelSettings {
|
|
118
|
-
model?: Model<
|
|
118
|
+
model?: Model<Api>;
|
|
119
119
|
thinkingLevel?: ThinkingLevel;
|
|
120
120
|
warning?: string;
|
|
121
121
|
error?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-resolver.d.ts","sourceRoot":"","sources":["../../src/core/model-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Model resolution, scoping, and initial selection\n */\n\nimport type { ThinkingLevel } from \"@caupulican/pi-agent-core\";\nimport { type Api, type KnownProvider, type Model, modelsAreEqual } from \"@caupulican/pi-ai\";\nimport chalk from \"chalk\";\nimport { minimatch } from \"minimatch\";\nimport { isValidThinkingLevel } from \"../cli/args.ts\";\nimport { DEFAULT_THINKING_LEVEL } from \"./defaults.ts\";\nimport type { ModelRegistry } from \"./model-registry.ts\";\nimport type { ProfileRegistry } from \"./profile-registry.ts\";\n\n/** Default model IDs for each known provider */\nexport const defaultModelPerProvider: Record<KnownProvider, string> = {\n\t\"amazon-bedrock\": \"us.anthropic.claude-opus-4-6-v1\",\n\tanthropic: \"claude-opus-4-8\",\n\topenai: \"gpt-5.4\",\n\tfugu: \"fugu\",\n\t\"azure-openai-responses\": \"gpt-5.4\",\n\t\"openai-codex\": \"gpt-5.6-sol\",\n\tdeepseek: \"deepseek-v4-pro\",\n\tgoogle: \"gemini-3.1-pro-preview\",\n\t\"google-vertex\": \"gemini-3.1-pro-preview\",\n\t\"github-copilot\": \"gpt-5.4\",\n\topenrouter: \"moonshotai/kimi-k2.6\",\n\t\"vercel-ai-gateway\": \"zai/glm-5.1\",\n\txai: \"grok-4.20-0309-reasoning\",\n\tgroq: \"openai/gpt-oss-120b\",\n\tcerebras: \"zai-glm-4.7\",\n\tzai: \"glm-5.1\",\n\tmistral: \"devstral-medium-latest\",\n\tminimax: \"MiniMax-M2.7\",\n\t\"minimax-cn\": \"MiniMax-M2.7\",\n\tmoonshotai: \"kimi-k2.6\",\n\t\"moonshotai-cn\": \"kimi-k2.6\",\n\thuggingface: \"moonshotai/Kimi-K2.6\",\n\tfireworks: \"accounts/fireworks/models/kimi-k2p6\",\n\ttogether: \"moonshotai/Kimi-K2.6\",\n\topencode: \"kimi-k2.6\",\n\t\"opencode-go\": \"kimi-k2.6\",\n\t\"kimi-coding\": \"kimi-for-coding\",\n\t\"llama-cpp\": \"local\",\n\t\"cloudflare-workers-ai\": \"@cf/moonshotai/kimi-k2.6\",\n\t\"cloudflare-ai-gateway\": \"workers-ai/@cf/moonshotai/kimi-k2.6\",\n\txiaomi: \"mimo-v2.5-pro\",\n\t\"xiaomi-token-plan-cn\": \"mimo-v2.5-pro\",\n\t\"xiaomi-token-plan-ams\": \"mimo-v2.5-pro\",\n\t\"xiaomi-token-plan-sgp\": \"mimo-v2.5-pro\",\n};\n\nexport interface ScopedModel {\n\tmodel: Model<Api>;\n\t/** Thinking level if explicitly specified in pattern (e.g., \"model:high\"), undefined otherwise */\n\tthinkingLevel?: ThinkingLevel;\n}\n\n/** User-friendly aliases for CLI provider names. Keep canonical provider IDs authoritative. */\nexport const cliProviderAliases: Record<string, string> = {\n\tchatgpt: \"openai-codex\",\n\tcodex: \"openai-codex\",\n\t\"openai-codex-subscription\": \"openai-codex\",\n\t\"openai-subscription\": \"openai-codex\",\n\tclaude: \"anthropic\",\n\t\"claude-pro\": \"anthropic\",\n\t\"claude-max\": \"anthropic\",\n};\n\nfunction buildProviderLookup(availableModels: Model<Api>[]): Map<string, string> {\n\tconst providerMap = new Map<string, string>();\n\tfor (const model of availableModels) {\n\t\tproviderMap.set(model.provider.toLowerCase(), model.provider);\n\t}\n\tfor (const [alias, canonical] of Object.entries(cliProviderAliases)) {\n\t\tconst normalizedAlias = alias.toLowerCase();\n\t\tif (providerMap.has(normalizedAlias)) continue;\n\t\tconst resolvedCanonical = providerMap.get(canonical.toLowerCase());\n\t\tif (resolvedCanonical) {\n\t\t\tproviderMap.set(normalizedAlias, resolvedCanonical);\n\t\t}\n\t}\n\treturn providerMap;\n}\n\n/**\n * Helper to check if a model ID looks like an alias (no date suffix)\n * Dates are typically in format: -20241022 or -20250929\n */\nfunction isAlias(id: string): boolean {\n\t// Check if ID ends with -latest\n\tif (id.endsWith(\"-latest\")) return true;\n\n\t// Check if ID ends with a date pattern (-YYYYMMDD)\n\tconst datePattern = /-\\d{8}$/;\n\treturn !datePattern.test(id);\n}\n\n/**\n * Find an exact model reference match.\n * Supports either a bare model id or a canonical provider/modelId reference.\n * When matching by bare id, ambiguous matches across providers are rejected.\n */\nexport function findExactModelReferenceMatch(\n\tmodelReference: string,\n\tavailableModels: Model<Api>[],\n): Model<Api> | undefined {\n\tconst trimmedReference = modelReference.trim();\n\tif (!trimmedReference) {\n\t\treturn undefined;\n\t}\n\n\tconst normalizedReference = trimmedReference.toLowerCase();\n\n\tconst canonicalMatches = availableModels.filter(\n\t\t(model) => `${model.provider}/${model.id}`.toLowerCase() === normalizedReference,\n\t);\n\tif (canonicalMatches.length === 1) {\n\t\treturn canonicalMatches[0];\n\t}\n\tif (canonicalMatches.length > 1) {\n\t\treturn undefined;\n\t}\n\n\tconst slashIndex = trimmedReference.indexOf(\"/\");\n\tif (slashIndex !== -1) {\n\t\tconst provider = trimmedReference.substring(0, slashIndex).trim();\n\t\tconst modelId = trimmedReference.substring(slashIndex + 1).trim();\n\t\tif (provider && modelId) {\n\t\t\tconst providerMatches = availableModels.filter(\n\t\t\t\t(model) =>\n\t\t\t\t\tmodel.provider.toLowerCase() === provider.toLowerCase() &&\n\t\t\t\t\tmodel.id.toLowerCase() === modelId.toLowerCase(),\n\t\t\t);\n\t\t\tif (providerMatches.length === 1) {\n\t\t\t\treturn providerMatches[0];\n\t\t\t}\n\t\t\tif (providerMatches.length > 1) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst idMatches = availableModels.filter((model) => model.id.toLowerCase() === normalizedReference);\n\treturn idMatches.length === 1 ? idMatches[0] : undefined;\n}\n\n/**\n * Try to match a pattern to a model from the available models list.\n * Returns the matched model or undefined if no match found.\n */\nfunction tryMatchModel(modelPattern: string, availableModels: Model<Api>[]): Model<Api> | undefined {\n\tconst exactMatch = findExactModelReferenceMatch(modelPattern, availableModels);\n\tif (exactMatch) {\n\t\treturn exactMatch;\n\t}\n\n\t// No exact match - fall back to partial matching\n\tconst matches = availableModels.filter(\n\t\t(m) =>\n\t\t\tm.id.toLowerCase().includes(modelPattern.toLowerCase()) ||\n\t\t\tm.name?.toLowerCase().includes(modelPattern.toLowerCase()),\n\t);\n\n\tif (matches.length === 0) {\n\t\treturn undefined;\n\t}\n\n\t// Separate into aliases and dated versions\n\tconst aliases = matches.filter((m) => isAlias(m.id));\n\tconst datedVersions = matches.filter((m) => !isAlias(m.id));\n\n\tif (aliases.length > 0) {\n\t\t// Prefer alias - if multiple aliases, pick the one that sorts highest\n\t\taliases.sort((a, b) => b.id.localeCompare(a.id));\n\t\treturn aliases[0];\n\t} else {\n\t\t// No alias found, pick latest dated version\n\t\tdatedVersions.sort((a, b) => b.id.localeCompare(a.id));\n\t\treturn datedVersions[0];\n\t}\n}\n\nexport interface ParsedModelResult {\n\tmodel: Model<Api> | undefined;\n\t/** Thinking level if explicitly specified in pattern, undefined otherwise */\n\tthinkingLevel?: ThinkingLevel;\n\twarning: string | undefined;\n}\n\nfunction buildFallbackModel(provider: string, modelId: string, availableModels: Model<Api>[]): Model<Api> | undefined {\n\tconst providerModels = availableModels.filter((m) => m.provider === provider);\n\tif (providerModels.length === 0) return undefined;\n\n\tconst defaultId = defaultModelPerProvider[provider as KnownProvider];\n\tconst baseModel = defaultId\n\t\t? (providerModels.find((m) => m.id === defaultId) ?? providerModels[0])\n\t\t: providerModels[0];\n\n\treturn {\n\t\t...baseModel,\n\t\tid: modelId,\n\t\tname: modelId,\n\t};\n}\n\n/**\n * Parse a pattern to extract model and thinking level.\n * Handles models with colons in their IDs (e.g., OpenRouter's :exacto suffix).\n *\n * Algorithm:\n * 1. Try to match full pattern as a model\n * 2. If found, return it with \"off\" thinking level\n * 3. If not found and has colons, split on last colon:\n * - If suffix is valid thinking level, use it and recurse on prefix\n * - If suffix is invalid, warn and recurse on prefix with \"off\"\n *\n * @internal Exported for testing\n */\nexport function parseModelPattern(\n\tpattern: string,\n\tavailableModels: Model<Api>[],\n\toptions?: { allowInvalidThinkingLevelFallback?: boolean },\n): ParsedModelResult {\n\t// Try exact match first\n\tconst exactMatch = tryMatchModel(pattern, availableModels);\n\tif (exactMatch) {\n\t\treturn { model: exactMatch, thinkingLevel: undefined, warning: undefined };\n\t}\n\n\t// No match - try splitting on last colon if present\n\tconst lastColonIndex = pattern.lastIndexOf(\":\");\n\tif (lastColonIndex === -1) {\n\t\t// No colons, pattern simply doesn't match any model\n\t\treturn { model: undefined, thinkingLevel: undefined, warning: undefined };\n\t}\n\n\tconst prefix = pattern.substring(0, lastColonIndex);\n\tconst suffix = pattern.substring(lastColonIndex + 1);\n\n\tif (isValidThinkingLevel(suffix)) {\n\t\t// Valid thinking level - recurse on prefix and use this level\n\t\tconst result = parseModelPattern(prefix, availableModels, options);\n\t\tif (result.model) {\n\t\t\t// Only use this thinking level if no warning from inner recursion\n\t\t\treturn {\n\t\t\t\tmodel: result.model,\n\t\t\t\tthinkingLevel: result.warning ? undefined : suffix,\n\t\t\t\twarning: result.warning,\n\t\t\t};\n\t\t}\n\t\treturn result;\n\t} else {\n\t\t// Invalid suffix\n\t\tconst allowFallback = options?.allowInvalidThinkingLevelFallback ?? true;\n\t\tif (!allowFallback) {\n\t\t\t// In strict mode (CLI --model parsing), treat it as part of the model id and fail.\n\t\t\t// This avoids accidentally resolving to a different model.\n\t\t\treturn { model: undefined, thinkingLevel: undefined, warning: undefined };\n\t\t}\n\n\t\t// Scope mode: recurse on prefix and warn\n\t\tconst result = parseModelPattern(prefix, availableModels, options);\n\t\tif (result.model) {\n\t\t\treturn {\n\t\t\t\tmodel: result.model,\n\t\t\t\tthinkingLevel: undefined,\n\t\t\t\twarning: `Invalid thinking level \"${suffix}\" in pattern \"${pattern}\". Using default instead.`,\n\t\t\t};\n\t\t}\n\t\treturn result;\n\t}\n}\n\n/**\n * Resolve model patterns to actual Model objects with optional thinking levels\n * Format: \"pattern:level\" where :level is optional\n * For each pattern, finds all matching models and picks the best version:\n * 1. Prefer alias (e.g., claude-sonnet-4-5) over dated versions (claude-sonnet-4-5-20250929)\n * 2. If no alias, pick the latest dated version\n *\n * Supports models with colons in their IDs (e.g., OpenRouter's model:exacto).\n * The algorithm tries to match the full pattern first, then progressively\n * strips colon-suffixes to find a match.\n */\nexport async function resolveModelScope(patterns: string[], modelRegistry: ModelRegistry): Promise<ScopedModel[]> {\n\tconst availableModels = await modelRegistry.getAvailable();\n\tconst scopedModels: ScopedModel[] = [];\n\n\tfor (const pattern of patterns) {\n\t\t// Check if pattern contains glob characters\n\t\tif (pattern.includes(\"*\") || pattern.includes(\"?\") || pattern.includes(\"[\")) {\n\t\t\t// Extract optional thinking level suffix (e.g., \"provider/*:high\")\n\t\t\tconst colonIdx = pattern.lastIndexOf(\":\");\n\t\t\tlet globPattern = pattern;\n\t\t\tlet thinkingLevel: ThinkingLevel | undefined;\n\n\t\t\tif (colonIdx !== -1) {\n\t\t\t\tconst suffix = pattern.substring(colonIdx + 1);\n\t\t\t\tif (isValidThinkingLevel(suffix)) {\n\t\t\t\t\tthinkingLevel = suffix;\n\t\t\t\t\tglobPattern = pattern.substring(0, colonIdx);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Match against \"provider/modelId\" format OR just model ID\n\t\t\t// This allows \"*sonnet*\" to match without requiring \"anthropic/*sonnet*\"\n\t\t\tconst matchingModels = availableModels.filter((m) => {\n\t\t\t\tconst fullId = `${m.provider}/${m.id}`;\n\t\t\t\treturn minimatch(fullId, globPattern, { nocase: true }) || minimatch(m.id, globPattern, { nocase: true });\n\t\t\t});\n\n\t\t\tif (matchingModels.length === 0) {\n\t\t\t\tconsole.warn(chalk.yellow(`Warning: No models match pattern \"${pattern}\"`));\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tfor (const model of matchingModels) {\n\t\t\t\tif (!scopedModels.find((sm) => modelsAreEqual(sm.model, model))) {\n\t\t\t\t\tscopedModels.push({ model, thinkingLevel });\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst { model, thinkingLevel, warning } = parseModelPattern(pattern, availableModels);\n\n\t\tif (warning) {\n\t\t\tconsole.warn(chalk.yellow(`Warning: ${warning}`));\n\t\t}\n\n\t\tif (!model) {\n\t\t\tconsole.warn(chalk.yellow(`Warning: No models match pattern \"${pattern}\"`));\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Avoid duplicates\n\t\tif (!scopedModels.find((sm) => modelsAreEqual(sm.model, model))) {\n\t\t\tscopedModels.push({ model, thinkingLevel });\n\t\t}\n\t}\n\n\treturn scopedModels;\n}\n\nexport interface ResolveCliModelResult {\n\tmodel: Model<Api> | undefined;\n\tthinkingLevel?: ThinkingLevel;\n\twarning: string | undefined;\n\t/**\n\t * Error message suitable for CLI display.\n\t * When set, model will be undefined.\n\t */\n\terror: string | undefined;\n}\n\nfunction formatAmbiguousModelReferenceError(modelReference: string, matches: Model<Api>[]): string {\n\tconst candidates = matches.map((model) => `${model.provider}/${model.id}`).sort();\n\treturn `Model \"${modelReference}\" is ambiguous. Use one of: ${candidates.join(\", \")}.`;\n}\n\n/**\n * Resolve a single model from CLI flags.\n *\n * Supports:\n * - --provider <provider> --model <pattern>\n * - --model <provider>/<pattern>\n * - Fuzzy matching (same rules as model scoping: exact id, then partial id/name)\n *\n * Note: This does not apply the thinking level by itself, but it may *parse* and\n * return a thinking level from \"<pattern>:<thinking>\" so the caller can apply it.\n */\nexport function resolveCliModel(options: {\n\tcliProvider?: string;\n\tcliModel?: string;\n\tmodelRegistry: ModelRegistry;\n}): ResolveCliModelResult {\n\tconst { cliProvider, cliModel, modelRegistry } = options;\n\n\tif (!cliModel) {\n\t\treturn { model: undefined, warning: undefined, error: undefined };\n\t}\n\n\t// Important: use *all* models here, not just models with pre-configured auth.\n\t// This allows \"--api-key\" to be used for first-time setup.\n\tconst availableModels = modelRegistry.getAll();\n\tif (availableModels.length === 0) {\n\t\treturn {\n\t\t\tmodel: undefined,\n\t\t\twarning: undefined,\n\t\t\terror: \"No models available. Check your installation or add models to models.json.\",\n\t\t};\n\t}\n\n\t// Build canonical provider lookup (case-insensitive), including friendly aliases.\n\tconst providerMap = buildProviderLookup(availableModels);\n\n\tlet provider = cliProvider ? providerMap.get(cliProvider.toLowerCase()) : undefined;\n\tif (cliProvider && !provider) {\n\t\treturn {\n\t\t\tmodel: undefined,\n\t\t\twarning: undefined,\n\t\t\terror: `Unknown provider \"${cliProvider}\". Use --list-models to see available providers/models.`,\n\t\t};\n\t}\n\n\t// If no explicit --provider, try to interpret \"provider/model\" format first.\n\t// When the prefix before the first slash matches a known provider, prefer that\n\t// interpretation over matching models whose IDs literally contain slashes\n\t// (e.g. \"zai/glm-5\" should resolve to provider=zai, model=glm-5, not to a\n\t// vercel-ai-gateway model with id \"zai/glm-5\").\n\tlet pattern = cliModel;\n\tlet inferredProvider = false;\n\n\tif (!provider) {\n\t\tconst slashIndex = cliModel.indexOf(\"/\");\n\t\tif (slashIndex !== -1) {\n\t\t\tconst maybeProvider = cliModel.substring(0, slashIndex);\n\t\t\tconst canonical = providerMap.get(maybeProvider.toLowerCase());\n\t\t\tif (canonical) {\n\t\t\t\tprovider = canonical;\n\t\t\t\tpattern = cliModel.substring(slashIndex + 1);\n\t\t\t\tinferredProvider = true;\n\t\t\t}\n\t\t}\n\t}\n\n\t// If no provider was inferred from the slash, try exact matches without provider inference.\n\t// This handles models whose IDs naturally contain slashes (e.g. OpenRouter-style IDs).\n\tif (!provider) {\n\t\tconst lower = cliModel.toLowerCase();\n\t\tconst exactReferenceMatches = availableModels.filter((m) => `${m.provider}/${m.id}`.toLowerCase() === lower);\n\t\tif (exactReferenceMatches.length === 1) {\n\t\t\treturn { model: exactReferenceMatches[0], warning: undefined, thinkingLevel: undefined, error: undefined };\n\t\t}\n\t\tif (exactReferenceMatches.length > 1) {\n\t\t\treturn {\n\t\t\t\tmodel: undefined,\n\t\t\t\twarning: undefined,\n\t\t\t\tthinkingLevel: undefined,\n\t\t\t\terror: formatAmbiguousModelReferenceError(cliModel, exactReferenceMatches),\n\t\t\t};\n\t\t}\n\n\t\tconst idMatches = availableModels.filter((m) => m.id.toLowerCase() === lower);\n\t\tif (idMatches.length === 1) {\n\t\t\treturn { model: idMatches[0], warning: undefined, thinkingLevel: undefined, error: undefined };\n\t\t}\n\t\tif (idMatches.length > 1) {\n\t\t\tconst authenticatedMatches = modelRegistry\n\t\t\t\t.getAvailable()\n\t\t\t\t.filter((available) => idMatches.some((match) => modelsAreEqual(available, match)));\n\t\t\tif (authenticatedMatches.length === 1) {\n\t\t\t\treturn { model: authenticatedMatches[0], warning: undefined, thinkingLevel: undefined, error: undefined };\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tmodel: undefined,\n\t\t\t\twarning: undefined,\n\t\t\t\tthinkingLevel: undefined,\n\t\t\t\terror: formatAmbiguousModelReferenceError(cliModel, idMatches),\n\t\t\t};\n\t\t}\n\t}\n\n\tif (cliProvider && provider) {\n\t\t// If both were provided, tolerate --model <provider>/<pattern> by stripping\n\t\t// either the canonical provider prefix or the user-entered alias prefix.\n\t\tconst prefixes = Array.from(new Set([provider, cliProvider].filter((value) => value.length > 0)));\n\t\tfor (const candidatePrefix of prefixes) {\n\t\t\tconst prefix = `${candidatePrefix}/`;\n\t\t\tif (cliModel.toLowerCase().startsWith(prefix.toLowerCase())) {\n\t\t\t\tpattern = cliModel.substring(prefix.length);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst candidates = provider ? availableModels.filter((m) => m.provider === provider) : availableModels;\n\tconst { model, thinkingLevel, warning } = parseModelPattern(pattern, candidates, {\n\t\tallowInvalidThinkingLevelFallback: false,\n\t});\n\n\tif (model) {\n\t\treturn { model, thinkingLevel, warning, error: undefined };\n\t}\n\n\t// If we inferred a provider from the slash but found no match within that provider,\n\t// fall back to matching the full input as a raw model id across all models.\n\t// This handles OpenRouter-style IDs like \"openai/gpt-4o:extended\" where \"openai\"\n\t// looks like a provider but the full string is actually a model id on openrouter.\n\tif (inferredProvider) {\n\t\tconst lower = cliModel.toLowerCase();\n\t\tconst exact = availableModels.find(\n\t\t\t(m) => m.id.toLowerCase() === lower || `${m.provider}/${m.id}`.toLowerCase() === lower,\n\t\t);\n\t\tif (exact) {\n\t\t\treturn { model: exact, warning: undefined, thinkingLevel: undefined, error: undefined };\n\t\t}\n\t\t// Also try parseModelPattern on the full input against all models\n\t\tconst fallback = parseModelPattern(cliModel, availableModels, {\n\t\t\tallowInvalidThinkingLevelFallback: false,\n\t\t});\n\t\tif (fallback.model) {\n\t\t\treturn {\n\t\t\t\tmodel: fallback.model,\n\t\t\t\tthinkingLevel: fallback.thinkingLevel,\n\t\t\t\twarning: fallback.warning,\n\t\t\t\terror: undefined,\n\t\t\t};\n\t\t}\n\t}\n\n\tif (provider) {\n\t\tconst fallbackModel = buildFallbackModel(provider, pattern, availableModels);\n\t\tif (fallbackModel) {\n\t\t\tconst fallbackWarning = warning\n\t\t\t\t? `${warning} Model \"${pattern}\" not found for provider \"${provider}\". Using custom model id.`\n\t\t\t\t: `Model \"${pattern}\" not found for provider \"${provider}\". Using custom model id.`;\n\t\t\treturn { model: fallbackModel, thinkingLevel: undefined, warning: fallbackWarning, error: undefined };\n\t\t}\n\t}\n\n\tconst display = provider ? `${provider}/${pattern}` : cliModel;\n\treturn {\n\t\tmodel: undefined,\n\t\tthinkingLevel: undefined,\n\t\twarning,\n\t\terror: `Model \"${display}\" not found. Use --list-models to see available models.`,\n\t};\n}\n\nexport function resolveCliProviderDefault(options: {\n\tcliProvider?: string;\n\tmodelRegistry: ModelRegistry;\n}): ResolveCliModelResult {\n\tconst { cliProvider, modelRegistry } = options;\n\tif (!cliProvider) {\n\t\treturn { model: undefined, warning: undefined, thinkingLevel: undefined, error: undefined };\n\t}\n\n\t// Important: use *all* models here, not just models with pre-configured auth.\n\t// This allows \"--provider <name> --api-key <key>\" to work for first-time setup.\n\tconst availableModels = modelRegistry.getAll();\n\tif (availableModels.length === 0) {\n\t\treturn {\n\t\t\tmodel: undefined,\n\t\t\twarning: undefined,\n\t\t\tthinkingLevel: undefined,\n\t\t\terror: \"No models available. Check your installation or add models to models.json.\",\n\t\t};\n\t}\n\n\tconst providerMap = buildProviderLookup(availableModels);\n\tconst provider = providerMap.get(cliProvider.toLowerCase());\n\tif (!provider) {\n\t\treturn {\n\t\t\tmodel: undefined,\n\t\t\twarning: undefined,\n\t\t\tthinkingLevel: undefined,\n\t\t\terror: `Unknown provider \"${cliProvider}\". Use --list-models to see available providers/models.`,\n\t\t};\n\t}\n\n\tconst providerModels = availableModels.filter((model) => model.provider === provider);\n\tif (providerModels.length === 0) {\n\t\treturn {\n\t\t\tmodel: undefined,\n\t\t\twarning: undefined,\n\t\t\tthinkingLevel: undefined,\n\t\t\terror: `No models found for provider \"${provider}\". Use --list-models to see available providers/models.`,\n\t\t};\n\t}\n\n\tconst defaultId = defaultModelPerProvider[provider as KnownProvider];\n\tconst model =\n\t\t(defaultId ? providerModels.find((candidate) => candidate.id === defaultId) : undefined) ?? providerModels[0];\n\treturn { model, warning: undefined, thinkingLevel: undefined, error: undefined };\n}\n\nexport interface InitialModelResult {\n\tmodel: Model<Api> | undefined;\n\tthinkingLevel: ThinkingLevel;\n\tfallbackMessage: string | undefined;\n}\n\nfunction resolveInitialThinkingLevel(model: Model<Api>, explicitThinkingLevel?: ThinkingLevel): ThinkingLevel {\n\treturn explicitThinkingLevel ?? model.defaultThinkingLevel ?? DEFAULT_THINKING_LEVEL;\n}\n\n/**\n * Find the initial model to use based on priority:\n * 1. CLI args (provider + optional model)\n * 2. First model from scoped models (if not continuing/resuming)\n * 3. Restored from session (if continuing/resuming)\n * 4. Saved default from settings\n * 5. First available model with valid API key\n */\nexport async function findInitialModel(options: {\n\tcliProvider?: string;\n\tcliModel?: string;\n\tscopedModels: ScopedModel[];\n\tisContinuing: boolean;\n\tdefaultProvider?: string;\n\tdefaultModelId?: string;\n\tdefaultThinkingLevel?: ThinkingLevel;\n\tmodelRegistry: ModelRegistry;\n}): Promise<InitialModelResult> {\n\tconst {\n\t\tcliProvider,\n\t\tcliModel,\n\t\tscopedModels,\n\t\tisContinuing,\n\t\tdefaultProvider,\n\t\tdefaultModelId,\n\t\tdefaultThinkingLevel,\n\t\tmodelRegistry,\n\t} = options;\n\n\tlet model: Model<Api> | undefined;\n\n\t// 1. CLI args take priority\n\tif (cliProvider || cliModel) {\n\t\tconst resolved = cliModel\n\t\t\t? resolveCliModel({\n\t\t\t\t\tcliProvider,\n\t\t\t\t\tcliModel,\n\t\t\t\t\tmodelRegistry,\n\t\t\t\t})\n\t\t\t: resolveCliProviderDefault({ cliProvider, modelRegistry });\n\t\tif (resolved.error) {\n\t\t\tconsole.error(chalk.red(resolved.error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tif (resolved.model) {\n\t\t\treturn {\n\t\t\t\tmodel: resolved.model,\n\t\t\t\tthinkingLevel: resolveInitialThinkingLevel(resolved.model, resolved.thinkingLevel ?? defaultThinkingLevel),\n\t\t\t\tfallbackMessage: undefined,\n\t\t\t};\n\t\t}\n\t}\n\n\t// 2. Use first model from scoped models (skip if continuing/resuming)\n\tif (scopedModels.length > 0 && !isContinuing) {\n\t\treturn {\n\t\t\tmodel: scopedModels[0].model,\n\t\t\tthinkingLevel: resolveInitialThinkingLevel(\n\t\t\t\tscopedModels[0].model,\n\t\t\t\tscopedModels[0].thinkingLevel ?? defaultThinkingLevel,\n\t\t\t),\n\t\t\tfallbackMessage: undefined,\n\t\t};\n\t}\n\n\t// 3. Try saved default from settings\n\tif (defaultProvider && defaultModelId) {\n\t\tconst found = modelRegistry.find(defaultProvider, defaultModelId);\n\t\tif (found) {\n\t\t\tmodel = found;\n\t\t\treturn {\n\t\t\t\tmodel,\n\t\t\t\tthinkingLevel: resolveInitialThinkingLevel(model, defaultThinkingLevel),\n\t\t\t\tfallbackMessage: undefined,\n\t\t\t};\n\t\t}\n\t}\n\n\t// 4. Try first available model with valid API key\n\tconst availableModels = await modelRegistry.getAvailable();\n\n\tif (availableModels.length > 0) {\n\t\t// Try to find a default model from known providers\n\t\tfor (const provider of Object.keys(defaultModelPerProvider) as KnownProvider[]) {\n\t\t\tconst defaultId = defaultModelPerProvider[provider];\n\t\t\tconst match = availableModels.find((m) => m.provider === provider && m.id === defaultId);\n\t\t\tif (match) {\n\t\t\t\treturn {\n\t\t\t\t\tmodel: match,\n\t\t\t\t\tthinkingLevel: resolveInitialThinkingLevel(match, defaultThinkingLevel),\n\t\t\t\t\tfallbackMessage: undefined,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\t// If no default found, use first available\n\t\treturn {\n\t\t\tmodel: availableModels[0],\n\t\t\tthinkingLevel: resolveInitialThinkingLevel(availableModels[0], defaultThinkingLevel),\n\t\t\tfallbackMessage: undefined,\n\t\t};\n\t}\n\n\t// 5. No model found\n\treturn {\n\t\tmodel: undefined,\n\t\tthinkingLevel: defaultThinkingLevel ?? DEFAULT_THINKING_LEVEL,\n\t\tfallbackMessage: undefined,\n\t};\n}\n\n/**\n * Restore model from session, with fallback to available models\n */\nexport async function restoreModelFromSession(\n\tsavedProvider: string,\n\tsavedModelId: string,\n\tcurrentModel: Model<Api> | undefined,\n\tshouldPrintMessages: boolean,\n\tmodelRegistry: ModelRegistry,\n): Promise<{ model: Model<Api> | undefined; fallbackMessage: string | undefined }> {\n\tconst restoredModel = modelRegistry.find(savedProvider, savedModelId);\n\n\t// Check if restored model exists and still has auth configured\n\tconst hasConfiguredAuth = restoredModel ? modelRegistry.hasConfiguredAuth(restoredModel) : false;\n\n\tif (restoredModel && hasConfiguredAuth) {\n\t\tif (shouldPrintMessages) {\n\t\t\tconsole.log(chalk.dim(`Restored model: ${savedProvider}/${savedModelId}`));\n\t\t}\n\t\treturn { model: restoredModel, fallbackMessage: undefined };\n\t}\n\n\t// Model not found or no API key - fall back\n\tconst reason = !restoredModel ? \"model no longer exists\" : \"no auth configured\";\n\n\tif (shouldPrintMessages) {\n\t\tconsole.error(chalk.yellow(`Warning: Could not restore model ${savedProvider}/${savedModelId} (${reason}).`));\n\t}\n\n\t// If we already have a model, use it as fallback\n\tif (currentModel) {\n\t\tif (shouldPrintMessages) {\n\t\t\tconsole.log(chalk.dim(`Falling back to: ${currentModel.provider}/${currentModel.id}`));\n\t\t}\n\t\treturn {\n\t\t\tmodel: currentModel,\n\t\t\tfallbackMessage: `Could not restore model ${savedProvider}/${savedModelId} (${reason}). Using ${currentModel.provider}/${currentModel.id}.`,\n\t\t};\n\t}\n\n\t// Try to find any available model\n\tconst availableModels = await modelRegistry.getAvailable();\n\n\tif (availableModels.length > 0) {\n\t\t// Try to find a default model from known providers\n\t\tlet fallbackModel: Model<Api> | undefined;\n\t\tfor (const provider of Object.keys(defaultModelPerProvider) as KnownProvider[]) {\n\t\t\tconst defaultId = defaultModelPerProvider[provider];\n\t\t\tconst match = availableModels.find((m) => m.provider === provider && m.id === defaultId);\n\t\t\tif (match) {\n\t\t\t\tfallbackModel = match;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// If no default found, use first available\n\t\tif (!fallbackModel) {\n\t\t\tfallbackModel = availableModels[0];\n\t\t}\n\n\t\tif (shouldPrintMessages) {\n\t\t\tconsole.log(chalk.dim(`Falling back to: ${fallbackModel.provider}/${fallbackModel.id}`));\n\t\t}\n\n\t\treturn {\n\t\t\tmodel: fallbackModel,\n\t\t\tfallbackMessage: `Could not restore model ${savedProvider}/${savedModelId} (${reason}). Using ${fallbackModel.provider}/${fallbackModel.id}.`,\n\t\t};\n\t}\n\n\t// No models available\n\treturn { model: undefined, fallbackMessage: undefined };\n}\n\nexport interface ResolvedProfileModelSettings {\n\tmodel?: Model<any>;\n\tthinkingLevel?: ThinkingLevel;\n\twarning?: string;\n\terror?: string;\n}\n\nexport function resolveProfileModelSettings(options: {\n\tactiveProfileNames: string[];\n\tregistry: ProfileRegistry;\n\tmodelRegistry: ModelRegistry;\n\tcwd: string;\n}): ResolvedProfileModelSettings {\n\tconst { activeProfileNames, registry, modelRegistry, cwd } = options;\n\tlet modelString: string | undefined;\n\tlet thinking: ThinkingLevel | undefined;\n\n\tfor (const profileName of activeProfileNames) {\n\t\tconst profile =\n\t\t\tprofileName.startsWith(\"./\") || profileName.startsWith(\"../\")\n\t\t\t\t? registry.resolveProfileRef(profileName, cwd)\n\t\t\t\t: registry.getProfile(profileName);\n\t\tif (profile) {\n\t\t\tif (!modelString && profile.model) {\n\t\t\t\tmodelString = profile.model;\n\t\t\t}\n\t\t\tif (!thinking && profile.thinking) {\n\t\t\t\tthinking = profile.thinking;\n\t\t\t}\n\t\t\tif (modelString && thinking) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (!modelString && !thinking) {\n\t\treturn {};\n\t}\n\n\tconst result: ResolvedProfileModelSettings = {};\n\tif (modelString) {\n\t\tconst resolved = resolveCliModel({ cliModel: modelString, modelRegistry });\n\t\tif (resolved.error) {\n\t\t\tresult.error = resolved.error;\n\t\t}\n\t\tif (resolved.warning) {\n\t\t\tresult.warning = resolved.warning;\n\t\t}\n\t\tif (resolved.model) {\n\t\t\tresult.model = resolved.model;\n\t\t}\n\t\tif (resolved.thinkingLevel && !thinking) {\n\t\t\tthinking = resolved.thinkingLevel;\n\t\t}\n\t}\n\n\tif (thinking) {\n\t\tresult.thinkingLevel = thinking;\n\t}\n\n\treturn result;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"model-resolver.d.ts","sourceRoot":"","sources":["../../src/core/model-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Model resolution, scoping, and initial selection\n */\n\nimport type { ThinkingLevel } from \"@caupulican/pi-agent-core\";\nimport { type Api, type KnownProvider, type Model, modelsAreEqual, resolveModelThinkingLevel } from \"@caupulican/pi-ai\";\nimport chalk from \"chalk\";\nimport { minimatch } from \"minimatch\";\nimport { isValidThinkingLevel } from \"../cli/args.ts\";\nimport { DEFAULT_THINKING_LEVEL } from \"./defaults.ts\";\nimport type { ModelRegistry } from \"./model-registry.ts\";\nimport type { ProfileRegistry } from \"./profile-registry.ts\";\n\n/** Default model IDs for each known provider */\nexport const defaultModelPerProvider: Record<KnownProvider, string> = {\n\t\"amazon-bedrock\": \"us.anthropic.claude-opus-4-6-v1\",\n\tanthropic: \"claude-opus-4-8\",\n\topenai: \"gpt-5.4\",\n\tfugu: \"fugu\",\n\t\"azure-openai-responses\": \"gpt-5.4\",\n\t\"openai-codex\": \"gpt-5.6-sol\",\n\tdeepseek: \"deepseek-v4-pro\",\n\tgoogle: \"gemini-3.1-pro-preview\",\n\t\"google-vertex\": \"gemini-3.1-pro-preview\",\n\t\"github-copilot\": \"gpt-5.4\",\n\topenrouter: \"moonshotai/kimi-k2.6\",\n\t\"vercel-ai-gateway\": \"zai/glm-5.1\",\n\txai: \"grok-4.20-0309-reasoning\",\n\tgroq: \"openai/gpt-oss-120b\",\n\tcerebras: \"zai-glm-4.7\",\n\tzai: \"glm-5.1\",\n\tmistral: \"devstral-medium-latest\",\n\tminimax: \"MiniMax-M2.7\",\n\t\"minimax-cn\": \"MiniMax-M2.7\",\n\tmoonshotai: \"kimi-k2.6\",\n\t\"moonshotai-cn\": \"kimi-k2.6\",\n\thuggingface: \"moonshotai/Kimi-K2.6\",\n\tfireworks: \"accounts/fireworks/models/kimi-k2p6\",\n\ttogether: \"moonshotai/Kimi-K2.6\",\n\topencode: \"kimi-k2.6\",\n\t\"opencode-go\": \"kimi-k2.6\",\n\t\"kimi-coding\": \"kimi-for-coding\",\n\t\"llama-cpp\": \"local\",\n\t\"cloudflare-workers-ai\": \"@cf/moonshotai/kimi-k2.6\",\n\t\"cloudflare-ai-gateway\": \"workers-ai/@cf/moonshotai/kimi-k2.6\",\n\txiaomi: \"mimo-v2.5-pro\",\n\t\"xiaomi-token-plan-cn\": \"mimo-v2.5-pro\",\n\t\"xiaomi-token-plan-ams\": \"mimo-v2.5-pro\",\n\t\"xiaomi-token-plan-sgp\": \"mimo-v2.5-pro\",\n};\n\nexport interface ScopedModel {\n\tmodel: Model<Api>;\n\t/** Thinking level if explicitly specified in pattern (e.g., \"model:high\"), undefined otherwise */\n\tthinkingLevel?: ThinkingLevel;\n}\n\n/** User-friendly aliases for CLI provider names. Keep canonical provider IDs authoritative. */\nexport const cliProviderAliases: Record<string, string> = {\n\tchatgpt: \"openai-codex\",\n\tcodex: \"openai-codex\",\n\t\"openai-codex-subscription\": \"openai-codex\",\n\t\"openai-subscription\": \"openai-codex\",\n\tclaude: \"anthropic\",\n\t\"claude-pro\": \"anthropic\",\n\t\"claude-max\": \"anthropic\",\n};\n\nfunction buildProviderLookup(availableModels: Model<Api>[]): Map<string, string> {\n\tconst providerMap = new Map<string, string>();\n\tfor (const model of availableModels) {\n\t\tproviderMap.set(model.provider.toLowerCase(), model.provider);\n\t}\n\tfor (const [alias, canonical] of Object.entries(cliProviderAliases)) {\n\t\tconst normalizedAlias = alias.toLowerCase();\n\t\tif (providerMap.has(normalizedAlias)) continue;\n\t\tconst resolvedCanonical = providerMap.get(canonical.toLowerCase());\n\t\tif (resolvedCanonical) {\n\t\t\tproviderMap.set(normalizedAlias, resolvedCanonical);\n\t\t}\n\t}\n\treturn providerMap;\n}\n\n/**\n * Helper to check if a model ID looks like an alias (no date suffix)\n * Dates are typically in format: -20241022 or -20250929\n */\nfunction isAlias(id: string): boolean {\n\t// Check if ID ends with -latest\n\tif (id.endsWith(\"-latest\")) return true;\n\n\t// Check if ID ends with a date pattern (-YYYYMMDD)\n\tconst datePattern = /-\\d{8}$/;\n\treturn !datePattern.test(id);\n}\n\n/**\n * Find an exact model reference match.\n * Supports either a bare model id or a canonical provider/modelId reference.\n * When matching by bare id, ambiguous matches across providers are rejected.\n */\nexport function findExactModelReferenceMatch(\n\tmodelReference: string,\n\tavailableModels: Model<Api>[],\n): Model<Api> | undefined {\n\tconst trimmedReference = modelReference.trim();\n\tif (!trimmedReference) {\n\t\treturn undefined;\n\t}\n\n\tconst normalizedReference = trimmedReference.toLowerCase();\n\n\tconst canonicalMatches = availableModels.filter(\n\t\t(model) => `${model.provider}/${model.id}`.toLowerCase() === normalizedReference,\n\t);\n\tif (canonicalMatches.length === 1) {\n\t\treturn canonicalMatches[0];\n\t}\n\tif (canonicalMatches.length > 1) {\n\t\treturn undefined;\n\t}\n\n\tconst slashIndex = trimmedReference.indexOf(\"/\");\n\tif (slashIndex !== -1) {\n\t\tconst provider = trimmedReference.substring(0, slashIndex).trim();\n\t\tconst modelId = trimmedReference.substring(slashIndex + 1).trim();\n\t\tif (provider && modelId) {\n\t\t\tconst providerMatches = availableModels.filter(\n\t\t\t\t(model) =>\n\t\t\t\t\tmodel.provider.toLowerCase() === provider.toLowerCase() &&\n\t\t\t\t\tmodel.id.toLowerCase() === modelId.toLowerCase(),\n\t\t\t);\n\t\t\tif (providerMatches.length === 1) {\n\t\t\t\treturn providerMatches[0];\n\t\t\t}\n\t\t\tif (providerMatches.length > 1) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst idMatches = availableModels.filter((model) => model.id.toLowerCase() === normalizedReference);\n\treturn idMatches.length === 1 ? idMatches[0] : undefined;\n}\n\n/**\n * Try to match a pattern to a model from the available models list.\n * Returns the matched model or undefined if no match found.\n */\nfunction tryMatchModel(modelPattern: string, availableModels: Model<Api>[]): Model<Api> | undefined {\n\tconst exactMatch = findExactModelReferenceMatch(modelPattern, availableModels);\n\tif (exactMatch) {\n\t\treturn exactMatch;\n\t}\n\n\t// No exact match - fall back to partial matching\n\tconst matches = availableModels.filter(\n\t\t(m) =>\n\t\t\tm.id.toLowerCase().includes(modelPattern.toLowerCase()) ||\n\t\t\tm.name?.toLowerCase().includes(modelPattern.toLowerCase()),\n\t);\n\n\tif (matches.length === 0) {\n\t\treturn undefined;\n\t}\n\n\t// Separate into aliases and dated versions\n\tconst aliases = matches.filter((m) => isAlias(m.id));\n\tconst datedVersions = matches.filter((m) => !isAlias(m.id));\n\n\tif (aliases.length > 0) {\n\t\t// Prefer alias - if multiple aliases, pick the one that sorts highest\n\t\taliases.sort((a, b) => b.id.localeCompare(a.id));\n\t\treturn aliases[0];\n\t} else {\n\t\t// No alias found, pick latest dated version\n\t\tdatedVersions.sort((a, b) => b.id.localeCompare(a.id));\n\t\treturn datedVersions[0];\n\t}\n}\n\nexport interface ParsedModelResult {\n\tmodel: Model<Api> | undefined;\n\t/** Thinking level if explicitly specified in pattern, undefined otherwise */\n\tthinkingLevel?: ThinkingLevel;\n\twarning: string | undefined;\n}\n\nfunction buildFallbackModel(provider: string, modelId: string, availableModels: Model<Api>[]): Model<Api> | undefined {\n\tconst providerModels = availableModels.filter((m) => m.provider === provider);\n\tif (providerModels.length === 0) return undefined;\n\n\tconst defaultId = defaultModelPerProvider[provider as KnownProvider];\n\tconst baseModel = defaultId\n\t\t? (providerModels.find((m) => m.id === defaultId) ?? providerModels[0])\n\t\t: providerModels[0];\n\n\treturn {\n\t\t...baseModel,\n\t\tid: modelId,\n\t\tname: modelId,\n\t};\n}\n\n/**\n * Parse a pattern to extract model and thinking level.\n * Handles models with colons in their IDs (e.g., OpenRouter's :exacto suffix).\n *\n * Algorithm:\n * 1. Try to match full pattern as a model\n * 2. If found, return it with \"off\" thinking level\n * 3. If not found and has colons, split on last colon:\n * - If suffix is valid thinking level, use it and recurse on prefix\n * - If suffix is invalid, warn and recurse on prefix with \"off\"\n *\n * @internal Exported for testing\n */\nexport function parseModelPattern(\n\tpattern: string,\n\tavailableModels: Model<Api>[],\n\toptions?: { allowInvalidThinkingLevelFallback?: boolean },\n): ParsedModelResult {\n\t// Try exact match first\n\tconst exactMatch = tryMatchModel(pattern, availableModels);\n\tif (exactMatch) {\n\t\treturn { model: exactMatch, thinkingLevel: undefined, warning: undefined };\n\t}\n\n\t// No match - try splitting on last colon if present\n\tconst lastColonIndex = pattern.lastIndexOf(\":\");\n\tif (lastColonIndex === -1) {\n\t\t// No colons, pattern simply doesn't match any model\n\t\treturn { model: undefined, thinkingLevel: undefined, warning: undefined };\n\t}\n\n\tconst prefix = pattern.substring(0, lastColonIndex);\n\tconst suffix = pattern.substring(lastColonIndex + 1);\n\n\tif (isValidThinkingLevel(suffix)) {\n\t\t// Valid thinking level - recurse on prefix and use this level\n\t\tconst result = parseModelPattern(prefix, availableModels, options);\n\t\tif (result.model) {\n\t\t\t// Only use this thinking level if no warning from inner recursion\n\t\t\treturn {\n\t\t\t\tmodel: result.model,\n\t\t\t\tthinkingLevel: result.warning ? undefined : suffix,\n\t\t\t\twarning: result.warning,\n\t\t\t};\n\t\t}\n\t\treturn result;\n\t} else {\n\t\t// Invalid suffix\n\t\tconst allowFallback = options?.allowInvalidThinkingLevelFallback ?? true;\n\t\tif (!allowFallback) {\n\t\t\t// In strict mode (CLI --model parsing), treat it as part of the model id and fail.\n\t\t\t// This avoids accidentally resolving to a different model.\n\t\t\treturn { model: undefined, thinkingLevel: undefined, warning: undefined };\n\t\t}\n\n\t\t// Scope mode: recurse on prefix and warn\n\t\tconst result = parseModelPattern(prefix, availableModels, options);\n\t\tif (result.model) {\n\t\t\treturn {\n\t\t\t\tmodel: result.model,\n\t\t\t\tthinkingLevel: undefined,\n\t\t\t\twarning: `Invalid thinking level \"${suffix}\" in pattern \"${pattern}\". Using default instead.`,\n\t\t\t};\n\t\t}\n\t\treturn result;\n\t}\n}\n\n/**\n * Resolve model patterns to actual Model objects with optional thinking levels\n * Format: \"pattern:level\" where :level is optional\n * For each pattern, finds all matching models and picks the best version:\n * 1. Prefer alias (e.g., claude-sonnet-4-5) over dated versions (claude-sonnet-4-5-20250929)\n * 2. If no alias, pick the latest dated version\n *\n * Supports models with colons in their IDs (e.g., OpenRouter's model:exacto).\n * The algorithm tries to match the full pattern first, then progressively\n * strips colon-suffixes to find a match.\n */\nexport async function resolveModelScope(patterns: string[], modelRegistry: ModelRegistry): Promise<ScopedModel[]> {\n\tconst availableModels = await modelRegistry.getAvailable();\n\tconst scopedModels: ScopedModel[] = [];\n\n\tfor (const pattern of patterns) {\n\t\t// Check if pattern contains glob characters\n\t\tif (pattern.includes(\"*\") || pattern.includes(\"?\") || pattern.includes(\"[\")) {\n\t\t\t// Extract optional thinking level suffix (e.g., \"provider/*:high\")\n\t\t\tconst colonIdx = pattern.lastIndexOf(\":\");\n\t\t\tlet globPattern = pattern;\n\t\t\tlet thinkingLevel: ThinkingLevel | undefined;\n\n\t\t\tif (colonIdx !== -1) {\n\t\t\t\tconst suffix = pattern.substring(colonIdx + 1);\n\t\t\t\tif (isValidThinkingLevel(suffix)) {\n\t\t\t\t\tthinkingLevel = suffix;\n\t\t\t\t\tglobPattern = pattern.substring(0, colonIdx);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Match against \"provider/modelId\" format OR just model ID\n\t\t\t// This allows \"*sonnet*\" to match without requiring \"anthropic/*sonnet*\"\n\t\t\tconst matchingModels = availableModels.filter((m) => {\n\t\t\t\tconst fullId = `${m.provider}/${m.id}`;\n\t\t\t\treturn minimatch(fullId, globPattern, { nocase: true }) || minimatch(m.id, globPattern, { nocase: true });\n\t\t\t});\n\n\t\t\tif (matchingModels.length === 0) {\n\t\t\t\tconsole.warn(chalk.yellow(`Warning: No models match pattern \"${pattern}\"`));\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tfor (const model of matchingModels) {\n\t\t\t\tif (!scopedModels.find((sm) => modelsAreEqual(sm.model, model))) {\n\t\t\t\t\tscopedModels.push({ model, thinkingLevel });\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst { model, thinkingLevel, warning } = parseModelPattern(pattern, availableModels);\n\n\t\tif (warning) {\n\t\t\tconsole.warn(chalk.yellow(`Warning: ${warning}`));\n\t\t}\n\n\t\tif (!model) {\n\t\t\tconsole.warn(chalk.yellow(`Warning: No models match pattern \"${pattern}\"`));\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Avoid duplicates\n\t\tif (!scopedModels.find((sm) => modelsAreEqual(sm.model, model))) {\n\t\t\tscopedModels.push({ model, thinkingLevel });\n\t\t}\n\t}\n\n\treturn scopedModels;\n}\n\nexport interface ResolveCliModelResult {\n\tmodel: Model<Api> | undefined;\n\tthinkingLevel?: ThinkingLevel;\n\twarning: string | undefined;\n\t/**\n\t * Error message suitable for CLI display.\n\t * When set, model will be undefined.\n\t */\n\terror: string | undefined;\n}\n\nfunction formatAmbiguousModelReferenceError(modelReference: string, matches: Model<Api>[]): string {\n\tconst candidates = matches.map((model) => `${model.provider}/${model.id}`).sort();\n\treturn `Model \"${modelReference}\" is ambiguous. Use one of: ${candidates.join(\", \")}.`;\n}\n\n/**\n * Resolve a single model from CLI flags.\n *\n * Supports:\n * - --provider <provider> --model <pattern>\n * - --model <provider>/<pattern>\n * - Fuzzy matching (same rules as model scoping: exact id, then partial id/name)\n *\n * Note: This does not apply the thinking level by itself, but it may *parse* and\n * return a thinking level from \"<pattern>:<thinking>\" so the caller can apply it.\n */\nexport function resolveCliModel(options: {\n\tcliProvider?: string;\n\tcliModel?: string;\n\tmodelRegistry: ModelRegistry;\n}): ResolveCliModelResult {\n\tconst { cliProvider, cliModel, modelRegistry } = options;\n\n\tif (!cliModel) {\n\t\treturn { model: undefined, warning: undefined, error: undefined };\n\t}\n\n\t// Important: use *all* models here, not just models with pre-configured auth.\n\t// This allows \"--api-key\" to be used for first-time setup.\n\tconst availableModels = modelRegistry.getAll();\n\tif (availableModels.length === 0) {\n\t\treturn {\n\t\t\tmodel: undefined,\n\t\t\twarning: undefined,\n\t\t\terror: \"No models available. Check your installation or add models to models.json.\",\n\t\t};\n\t}\n\n\t// Build canonical provider lookup (case-insensitive), including friendly aliases.\n\tconst providerMap = buildProviderLookup(availableModels);\n\n\tlet provider = cliProvider ? providerMap.get(cliProvider.toLowerCase()) : undefined;\n\tif (cliProvider && !provider) {\n\t\treturn {\n\t\t\tmodel: undefined,\n\t\t\twarning: undefined,\n\t\t\terror: `Unknown provider \"${cliProvider}\". Use --list-models to see available providers/models.`,\n\t\t};\n\t}\n\n\t// If no explicit --provider, try to interpret \"provider/model\" format first.\n\t// When the prefix before the first slash matches a known provider, prefer that\n\t// interpretation over matching models whose IDs literally contain slashes\n\t// (e.g. \"zai/glm-5\" should resolve to provider=zai, model=glm-5, not to a\n\t// vercel-ai-gateway model with id \"zai/glm-5\").\n\tlet pattern = cliModel;\n\tlet inferredProvider = false;\n\n\tif (!provider) {\n\t\tconst slashIndex = cliModel.indexOf(\"/\");\n\t\tif (slashIndex !== -1) {\n\t\t\tconst maybeProvider = cliModel.substring(0, slashIndex);\n\t\t\tconst canonical = providerMap.get(maybeProvider.toLowerCase());\n\t\t\tif (canonical) {\n\t\t\t\tprovider = canonical;\n\t\t\t\tpattern = cliModel.substring(slashIndex + 1);\n\t\t\t\tinferredProvider = true;\n\t\t\t}\n\t\t}\n\t}\n\n\t// If no provider was inferred from the slash, try exact matches without provider inference.\n\t// This handles models whose IDs naturally contain slashes (e.g. OpenRouter-style IDs).\n\tif (!provider) {\n\t\tconst lower = cliModel.toLowerCase();\n\t\tconst exactReferenceMatches = availableModels.filter((m) => `${m.provider}/${m.id}`.toLowerCase() === lower);\n\t\tif (exactReferenceMatches.length === 1) {\n\t\t\treturn { model: exactReferenceMatches[0], warning: undefined, thinkingLevel: undefined, error: undefined };\n\t\t}\n\t\tif (exactReferenceMatches.length > 1) {\n\t\t\treturn {\n\t\t\t\tmodel: undefined,\n\t\t\t\twarning: undefined,\n\t\t\t\tthinkingLevel: undefined,\n\t\t\t\terror: formatAmbiguousModelReferenceError(cliModel, exactReferenceMatches),\n\t\t\t};\n\t\t}\n\n\t\tconst idMatches = availableModels.filter((m) => m.id.toLowerCase() === lower);\n\t\tif (idMatches.length === 1) {\n\t\t\treturn { model: idMatches[0], warning: undefined, thinkingLevel: undefined, error: undefined };\n\t\t}\n\t\tif (idMatches.length > 1) {\n\t\t\tconst authenticatedMatches = modelRegistry\n\t\t\t\t.getAvailable()\n\t\t\t\t.filter((available) => idMatches.some((match) => modelsAreEqual(available, match)));\n\t\t\tif (authenticatedMatches.length === 1) {\n\t\t\t\treturn { model: authenticatedMatches[0], warning: undefined, thinkingLevel: undefined, error: undefined };\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tmodel: undefined,\n\t\t\t\twarning: undefined,\n\t\t\t\tthinkingLevel: undefined,\n\t\t\t\terror: formatAmbiguousModelReferenceError(cliModel, idMatches),\n\t\t\t};\n\t\t}\n\t}\n\n\tif (cliProvider && provider) {\n\t\t// If both were provided, tolerate --model <provider>/<pattern> by stripping\n\t\t// either the canonical provider prefix or the user-entered alias prefix.\n\t\tconst prefixes = Array.from(new Set([provider, cliProvider].filter((value) => value.length > 0)));\n\t\tfor (const candidatePrefix of prefixes) {\n\t\t\tconst prefix = `${candidatePrefix}/`;\n\t\t\tif (cliModel.toLowerCase().startsWith(prefix.toLowerCase())) {\n\t\t\t\tpattern = cliModel.substring(prefix.length);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst candidates = provider ? availableModels.filter((m) => m.provider === provider) : availableModels;\n\tconst { model, thinkingLevel, warning } = parseModelPattern(pattern, candidates, {\n\t\tallowInvalidThinkingLevelFallback: false,\n\t});\n\n\tif (model) {\n\t\treturn { model, thinkingLevel, warning, error: undefined };\n\t}\n\n\t// If we inferred a provider from the slash but found no match within that provider,\n\t// fall back to matching the full input as a raw model id across all models.\n\t// This handles OpenRouter-style IDs like \"openai/gpt-4o:extended\" where \"openai\"\n\t// looks like a provider but the full string is actually a model id on openrouter.\n\tif (inferredProvider) {\n\t\tconst lower = cliModel.toLowerCase();\n\t\tconst exact = availableModels.find(\n\t\t\t(m) => m.id.toLowerCase() === lower || `${m.provider}/${m.id}`.toLowerCase() === lower,\n\t\t);\n\t\tif (exact) {\n\t\t\treturn { model: exact, warning: undefined, thinkingLevel: undefined, error: undefined };\n\t\t}\n\t\t// Also try parseModelPattern on the full input against all models\n\t\tconst fallback = parseModelPattern(cliModel, availableModels, {\n\t\t\tallowInvalidThinkingLevelFallback: false,\n\t\t});\n\t\tif (fallback.model) {\n\t\t\treturn {\n\t\t\t\tmodel: fallback.model,\n\t\t\t\tthinkingLevel: fallback.thinkingLevel,\n\t\t\t\twarning: fallback.warning,\n\t\t\t\terror: undefined,\n\t\t\t};\n\t\t}\n\t}\n\n\tif (provider) {\n\t\tconst fallbackModel = buildFallbackModel(provider, pattern, availableModels);\n\t\tif (fallbackModel) {\n\t\t\tconst fallbackWarning = warning\n\t\t\t\t? `${warning} Model \"${pattern}\" not found for provider \"${provider}\". Using custom model id.`\n\t\t\t\t: `Model \"${pattern}\" not found for provider \"${provider}\". Using custom model id.`;\n\t\t\treturn { model: fallbackModel, thinkingLevel: undefined, warning: fallbackWarning, error: undefined };\n\t\t}\n\t}\n\n\tconst display = provider ? `${provider}/${pattern}` : cliModel;\n\treturn {\n\t\tmodel: undefined,\n\t\tthinkingLevel: undefined,\n\t\twarning,\n\t\terror: `Model \"${display}\" not found. Use --list-models to see available models.`,\n\t};\n}\n\nexport function resolveCliProviderDefault(options: {\n\tcliProvider?: string;\n\tmodelRegistry: ModelRegistry;\n}): ResolveCliModelResult {\n\tconst { cliProvider, modelRegistry } = options;\n\tif (!cliProvider) {\n\t\treturn { model: undefined, warning: undefined, thinkingLevel: undefined, error: undefined };\n\t}\n\n\t// Important: use *all* models here, not just models with pre-configured auth.\n\t// This allows \"--provider <name> --api-key <key>\" to work for first-time setup.\n\tconst availableModels = modelRegistry.getAll();\n\tif (availableModels.length === 0) {\n\t\treturn {\n\t\t\tmodel: undefined,\n\t\t\twarning: undefined,\n\t\t\tthinkingLevel: undefined,\n\t\t\terror: \"No models available. Check your installation or add models to models.json.\",\n\t\t};\n\t}\n\n\tconst providerMap = buildProviderLookup(availableModels);\n\tconst provider = providerMap.get(cliProvider.toLowerCase());\n\tif (!provider) {\n\t\treturn {\n\t\t\tmodel: undefined,\n\t\t\twarning: undefined,\n\t\t\tthinkingLevel: undefined,\n\t\t\terror: `Unknown provider \"${cliProvider}\". Use --list-models to see available providers/models.`,\n\t\t};\n\t}\n\n\tconst providerModels = availableModels.filter((model) => model.provider === provider);\n\tif (providerModels.length === 0) {\n\t\treturn {\n\t\t\tmodel: undefined,\n\t\t\twarning: undefined,\n\t\t\tthinkingLevel: undefined,\n\t\t\terror: `No models found for provider \"${provider}\". Use --list-models to see available providers/models.`,\n\t\t};\n\t}\n\n\tconst defaultId = defaultModelPerProvider[provider as KnownProvider];\n\tconst model =\n\t\t(defaultId ? providerModels.find((candidate) => candidate.id === defaultId) : undefined) ?? providerModels[0];\n\treturn { model, warning: undefined, thinkingLevel: undefined, error: undefined };\n}\n\nexport interface InitialModelResult {\n\tmodel: Model<Api> | undefined;\n\tthinkingLevel: ThinkingLevel;\n\tfallbackMessage: string | undefined;\n}\n\n/**\n * Find the initial model to use based on priority:\n * 1. CLI args (provider + optional model)\n * 2. First model from scoped models (if not continuing/resuming)\n * 3. Restored from session (if continuing/resuming)\n * 4. Saved default from settings\n * 5. First available model with valid API key\n */\nexport async function findInitialModel(options: {\n\tcliProvider?: string;\n\tcliModel?: string;\n\tscopedModels: ScopedModel[];\n\tisContinuing: boolean;\n\tdefaultProvider?: string;\n\tdefaultModelId?: string;\n\tdefaultThinkingLevel?: ThinkingLevel;\n\tmodelRegistry: ModelRegistry;\n}): Promise<InitialModelResult> {\n\tconst {\n\t\tcliProvider,\n\t\tcliModel,\n\t\tscopedModels,\n\t\tisContinuing,\n\t\tdefaultProvider,\n\t\tdefaultModelId,\n\t\tdefaultThinkingLevel,\n\t\tmodelRegistry,\n\t} = options;\n\n\tlet model: Model<Api> | undefined;\n\n\t// 1. CLI args take priority\n\tif (cliProvider || cliModel) {\n\t\tconst resolved = cliModel\n\t\t\t? resolveCliModel({\n\t\t\t\t\tcliProvider,\n\t\t\t\t\tcliModel,\n\t\t\t\t\tmodelRegistry,\n\t\t\t\t})\n\t\t\t: resolveCliProviderDefault({ cliProvider, modelRegistry });\n\t\tif (resolved.error) {\n\t\t\tconsole.error(chalk.red(resolved.error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tif (resolved.model) {\n\t\t\treturn {\n\t\t\t\tmodel: resolved.model,\n\t\t\t\tthinkingLevel: resolveModelThinkingLevel(\n\t\t\t\t\tresolved.model,\n\t\t\t\t\tresolved.thinkingLevel ?? defaultThinkingLevel,\n\t\t\t\t\tDEFAULT_THINKING_LEVEL,\n\t\t\t\t),\n\t\t\t\tfallbackMessage: undefined,\n\t\t\t};\n\t\t}\n\t}\n\n\t// 2. Use first model from scoped models (skip if continuing/resuming)\n\tif (scopedModels.length > 0 && !isContinuing) {\n\t\treturn {\n\t\t\tmodel: scopedModels[0].model,\n\t\t\tthinkingLevel: resolveModelThinkingLevel(\n\t\t\t\tscopedModels[0].model,\n\t\t\t\tscopedModels[0].thinkingLevel ?? defaultThinkingLevel,\n\t\t\t\tDEFAULT_THINKING_LEVEL,\n\t\t\t),\n\t\t\tfallbackMessage: undefined,\n\t\t};\n\t}\n\n\t// 3. Try saved default from settings\n\tif (defaultProvider && defaultModelId) {\n\t\tconst found = modelRegistry.find(defaultProvider, defaultModelId);\n\t\tif (found) {\n\t\t\tmodel = found;\n\t\t\treturn {\n\t\t\t\tmodel,\n\t\t\t\tthinkingLevel: resolveModelThinkingLevel(model, defaultThinkingLevel, DEFAULT_THINKING_LEVEL),\n\t\t\t\tfallbackMessage: undefined,\n\t\t\t};\n\t\t}\n\t}\n\n\t// 4. Try first available model with valid API key\n\tconst availableModels = await modelRegistry.getAvailable();\n\n\tif (availableModels.length > 0) {\n\t\t// Try to find a default model from known providers\n\t\tfor (const provider of Object.keys(defaultModelPerProvider) as KnownProvider[]) {\n\t\t\tconst defaultId = defaultModelPerProvider[provider];\n\t\t\tconst match = availableModels.find((m) => m.provider === provider && m.id === defaultId);\n\t\t\tif (match) {\n\t\t\t\treturn {\n\t\t\t\t\tmodel: match,\n\t\t\t\t\tthinkingLevel: resolveModelThinkingLevel(match, defaultThinkingLevel, DEFAULT_THINKING_LEVEL),\n\t\t\t\t\tfallbackMessage: undefined,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\t// If no default found, use first available\n\t\treturn {\n\t\t\tmodel: availableModels[0],\n\t\t\tthinkingLevel: resolveModelThinkingLevel(availableModels[0], defaultThinkingLevel, DEFAULT_THINKING_LEVEL),\n\t\t\tfallbackMessage: undefined,\n\t\t};\n\t}\n\n\t// 5. No model found\n\treturn {\n\t\tmodel: undefined,\n\t\tthinkingLevel: defaultThinkingLevel ?? DEFAULT_THINKING_LEVEL,\n\t\tfallbackMessage: undefined,\n\t};\n}\n\n/**\n * Restore model from session, with fallback to available models\n */\nexport async function restoreModelFromSession(\n\tsavedProvider: string,\n\tsavedModelId: string,\n\tcurrentModel: Model<Api> | undefined,\n\tshouldPrintMessages: boolean,\n\tmodelRegistry: ModelRegistry,\n): Promise<{ model: Model<Api> | undefined; fallbackMessage: string | undefined }> {\n\tconst restoredModel = modelRegistry.find(savedProvider, savedModelId);\n\n\t// Check if restored model exists and still has auth configured\n\tconst hasConfiguredAuth = restoredModel ? modelRegistry.hasConfiguredAuth(restoredModel) : false;\n\n\tif (restoredModel && hasConfiguredAuth) {\n\t\tif (shouldPrintMessages) {\n\t\t\tconsole.log(chalk.dim(`Restored model: ${savedProvider}/${savedModelId}`));\n\t\t}\n\t\treturn { model: restoredModel, fallbackMessage: undefined };\n\t}\n\n\t// Model not found or no API key - fall back\n\tconst reason = !restoredModel ? \"model no longer exists\" : \"no auth configured\";\n\n\tif (shouldPrintMessages) {\n\t\tconsole.error(chalk.yellow(`Warning: Could not restore model ${savedProvider}/${savedModelId} (${reason}).`));\n\t}\n\n\t// If we already have a model, use it as fallback\n\tif (currentModel) {\n\t\tif (shouldPrintMessages) {\n\t\t\tconsole.log(chalk.dim(`Falling back to: ${currentModel.provider}/${currentModel.id}`));\n\t\t}\n\t\treturn {\n\t\t\tmodel: currentModel,\n\t\t\tfallbackMessage: `Could not restore model ${savedProvider}/${savedModelId} (${reason}). Using ${currentModel.provider}/${currentModel.id}.`,\n\t\t};\n\t}\n\n\t// Try to find any available model\n\tconst availableModels = await modelRegistry.getAvailable();\n\n\tif (availableModels.length > 0) {\n\t\t// Try to find a default model from known providers\n\t\tlet fallbackModel: Model<Api> | undefined;\n\t\tfor (const provider of Object.keys(defaultModelPerProvider) as KnownProvider[]) {\n\t\t\tconst defaultId = defaultModelPerProvider[provider];\n\t\t\tconst match = availableModels.find((m) => m.provider === provider && m.id === defaultId);\n\t\t\tif (match) {\n\t\t\t\tfallbackModel = match;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// If no default found, use first available\n\t\tif (!fallbackModel) {\n\t\t\tfallbackModel = availableModels[0];\n\t\t}\n\n\t\tif (shouldPrintMessages) {\n\t\t\tconsole.log(chalk.dim(`Falling back to: ${fallbackModel.provider}/${fallbackModel.id}`));\n\t\t}\n\n\t\treturn {\n\t\t\tmodel: fallbackModel,\n\t\t\tfallbackMessage: `Could not restore model ${savedProvider}/${savedModelId} (${reason}). Using ${fallbackModel.provider}/${fallbackModel.id}.`,\n\t\t};\n\t}\n\n\t// No models available\n\treturn { model: undefined, fallbackMessage: undefined };\n}\n\nexport interface ResolvedProfileModelSettings {\n\tmodel?: Model<Api>;\n\tthinkingLevel?: ThinkingLevel;\n\twarning?: string;\n\terror?: string;\n}\n\nexport function resolveProfileModelSettings(options: {\n\tactiveProfileNames: string[];\n\tregistry: ProfileRegistry;\n\tmodelRegistry: ModelRegistry;\n\tcwd: string;\n}): ResolvedProfileModelSettings {\n\tconst { activeProfileNames, registry, modelRegistry, cwd } = options;\n\tlet modelString: string | undefined;\n\tlet thinking: ThinkingLevel | undefined;\n\n\tfor (const profileName of activeProfileNames) {\n\t\tconst profile =\n\t\t\tprofileName.startsWith(\"./\") || profileName.startsWith(\"../\")\n\t\t\t\t? registry.resolveProfileRef(profileName, cwd)\n\t\t\t\t: registry.getProfile(profileName);\n\t\tif (profile) {\n\t\t\tif (!modelString && profile.model) {\n\t\t\t\tmodelString = profile.model;\n\t\t\t}\n\t\t\tif (!thinking && profile.thinking) {\n\t\t\t\tthinking = profile.thinking;\n\t\t\t}\n\t\t\tif (modelString && thinking) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (!modelString && !thinking) {\n\t\treturn {};\n\t}\n\n\tconst result: ResolvedProfileModelSettings = {};\n\tif (modelString) {\n\t\tconst resolved = resolveCliModel({ cliModel: modelString, modelRegistry });\n\t\tif (resolved.error) {\n\t\t\tresult.error = resolved.error;\n\t\t}\n\t\tif (resolved.warning) {\n\t\t\tresult.warning = resolved.warning;\n\t\t}\n\t\tif (resolved.model) {\n\t\t\tresult.model = resolved.model;\n\t\t}\n\t\tif (resolved.thinkingLevel && !thinking) {\n\t\t\tthinking = resolved.thinkingLevel;\n\t\t}\n\t}\n\n\tif (thinking) {\n\t\tresult.thinkingLevel = thinking;\n\t}\n\n\treturn result;\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Model resolution, scoping, and initial selection
|
|
3
3
|
*/
|
|
4
|
-
import { modelsAreEqual } from "@caupulican/pi-ai";
|
|
4
|
+
import { modelsAreEqual, resolveModelThinkingLevel } from "@caupulican/pi-ai";
|
|
5
5
|
import chalk from "chalk";
|
|
6
6
|
import { minimatch } from "minimatch";
|
|
7
7
|
import { isValidThinkingLevel } from "../cli/args.js";
|
|
@@ -472,9 +472,6 @@ export function resolveCliProviderDefault(options) {
|
|
|
472
472
|
const model = (defaultId ? providerModels.find((candidate) => candidate.id === defaultId) : undefined) ?? providerModels[0];
|
|
473
473
|
return { model, warning: undefined, thinkingLevel: undefined, error: undefined };
|
|
474
474
|
}
|
|
475
|
-
function resolveInitialThinkingLevel(model, explicitThinkingLevel) {
|
|
476
|
-
return explicitThinkingLevel ?? model.defaultThinkingLevel ?? DEFAULT_THINKING_LEVEL;
|
|
477
|
-
}
|
|
478
475
|
/**
|
|
479
476
|
* Find the initial model to use based on priority:
|
|
480
477
|
* 1. CLI args (provider + optional model)
|
|
@@ -502,7 +499,7 @@ export async function findInitialModel(options) {
|
|
|
502
499
|
if (resolved.model) {
|
|
503
500
|
return {
|
|
504
501
|
model: resolved.model,
|
|
505
|
-
thinkingLevel:
|
|
502
|
+
thinkingLevel: resolveModelThinkingLevel(resolved.model, resolved.thinkingLevel ?? defaultThinkingLevel, DEFAULT_THINKING_LEVEL),
|
|
506
503
|
fallbackMessage: undefined,
|
|
507
504
|
};
|
|
508
505
|
}
|
|
@@ -511,7 +508,7 @@ export async function findInitialModel(options) {
|
|
|
511
508
|
if (scopedModels.length > 0 && !isContinuing) {
|
|
512
509
|
return {
|
|
513
510
|
model: scopedModels[0].model,
|
|
514
|
-
thinkingLevel:
|
|
511
|
+
thinkingLevel: resolveModelThinkingLevel(scopedModels[0].model, scopedModels[0].thinkingLevel ?? defaultThinkingLevel, DEFAULT_THINKING_LEVEL),
|
|
515
512
|
fallbackMessage: undefined,
|
|
516
513
|
};
|
|
517
514
|
}
|
|
@@ -522,7 +519,7 @@ export async function findInitialModel(options) {
|
|
|
522
519
|
model = found;
|
|
523
520
|
return {
|
|
524
521
|
model,
|
|
525
|
-
thinkingLevel:
|
|
522
|
+
thinkingLevel: resolveModelThinkingLevel(model, defaultThinkingLevel, DEFAULT_THINKING_LEVEL),
|
|
526
523
|
fallbackMessage: undefined,
|
|
527
524
|
};
|
|
528
525
|
}
|
|
@@ -537,7 +534,7 @@ export async function findInitialModel(options) {
|
|
|
537
534
|
if (match) {
|
|
538
535
|
return {
|
|
539
536
|
model: match,
|
|
540
|
-
thinkingLevel:
|
|
537
|
+
thinkingLevel: resolveModelThinkingLevel(match, defaultThinkingLevel, DEFAULT_THINKING_LEVEL),
|
|
541
538
|
fallbackMessage: undefined,
|
|
542
539
|
};
|
|
543
540
|
}
|
|
@@ -545,7 +542,7 @@ export async function findInitialModel(options) {
|
|
|
545
542
|
// If no default found, use first available
|
|
546
543
|
return {
|
|
547
544
|
model: availableModels[0],
|
|
548
|
-
thinkingLevel:
|
|
545
|
+
thinkingLevel: resolveModelThinkingLevel(availableModels[0], defaultThinkingLevel, DEFAULT_THINKING_LEVEL),
|
|
549
546
|
fallbackMessage: undefined,
|
|
550
547
|
};
|
|
551
548
|
}
|