@caupulican/pi-adaptative 0.81.37 → 0.81.39
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 +91 -0
- package/README.md +1 -1
- package/dist/bundled-resources/extensions/tmux-agent-manager/README.md +18 -1
- package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts +131 -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 +196 -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 +308 -0
- package/dist/bundled-resources/extensions/tmux-agent-manager/index.d.ts +22 -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 +585 -24
- package/dist/bundled-resources/extensions/tmux-agent-manager/index.js.map +1 -1
- package/dist/bundled-resources/extensions/tmux-agent-manager/index.ts +749 -27
- 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 +5 -5
- package/dist/bundled-resources/skills/tool-call-repair/references/text-protocol-grammar.md +28 -7
- package/dist/cli/args.d.ts +3 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +15 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/core/agent-paths.d.ts +49 -0
- package/dist/core/agent-paths.d.ts.map +1 -0
- package/dist/core/agent-paths.js +107 -0
- package/dist/core/agent-paths.js.map +1 -0
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +3 -3
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +234 -17
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +484 -62
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/autonomy/contracts.d.ts +9 -0
- package/dist/core/autonomy/contracts.d.ts.map +1 -1
- package/dist/core/autonomy/contracts.js.map +1 -1
- package/dist/core/autonomy/lane-tracker.d.ts +10 -1
- package/dist/core/autonomy/lane-tracker.d.ts.map +1 -1
- package/dist/core/autonomy/lane-tracker.js +5 -1
- package/dist/core/autonomy/lane-tracker.js.map +1 -1
- package/dist/core/background-lane-controller.d.ts +122 -6
- package/dist/core/background-lane-controller.d.ts.map +1 -1
- package/dist/core/background-lane-controller.js +447 -90
- 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/compaction-support.d.ts +13 -3
- 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-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/sqlite-runtime-index.d.ts.map +1 -1
- package/dist/core/context/sqlite-runtime-index.js +13 -7
- package/dist/core/context/sqlite-runtime-index.js.map +1 -1
- package/dist/core/context-gc.d.ts.map +1 -1
- package/dist/core/context-gc.js +16 -1
- 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 +137 -14
- 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/delegation/session-worker-result.d.ts +34 -4
- package/dist/core/delegation/session-worker-result.d.ts.map +1 -1
- package/dist/core/delegation/session-worker-result.js +64 -4
- package/dist/core/delegation/session-worker-result.js.map +1 -1
- package/dist/core/delegation/worker-actions.d.ts.map +1 -1
- package/dist/core/delegation/worker-actions.js +1 -1
- package/dist/core/delegation/worker-actions.js.map +1 -1
- package/dist/core/delegation/worker-result.d.ts +42 -1
- package/dist/core/delegation/worker-result.d.ts.map +1 -1
- package/dist/core/delegation/worker-result.js +68 -0
- package/dist/core/delegation/worker-result.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +23 -7
- 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 +1 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +51 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/goal-loop-controller.d.ts +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-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 +77 -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 +4 -0
- package/dist/core/goals/goal-continuation-prompt.d.ts.map +1 -1
- package/dist/core/goals/goal-continuation-prompt.js +51 -10
- package/dist/core/goals/goal-continuation-prompt.js.map +1 -1
- package/dist/core/goals/goal-runtime-snapshot.d.ts +101 -2
- package/dist/core/goals/goal-runtime-snapshot.d.ts.map +1 -1
- package/dist/core/goals/goal-runtime-snapshot.js +87 -4
- package/dist/core/goals/goal-runtime-snapshot.js.map +1 -1
- package/dist/core/goals/goal-state.d.ts +89 -1
- package/dist/core/goals/goal-state.d.ts.map +1 -1
- package/dist/core/goals/goal-state.js +71 -5
- package/dist/core/goals/goal-state.js.map +1 -1
- package/dist/core/goals/goal-tool-core.d.ts +56 -2
- package/dist/core/goals/goal-tool-core.d.ts.map +1 -1
- package/dist/core/goals/goal-tool-core.js +111 -5
- package/dist/core/goals/goal-tool-core.js.map +1 -1
- package/dist/core/goals/session-goal-state.d.ts +11 -2
- package/dist/core/goals/session-goal-state.d.ts.map +1 -1
- package/dist/core/goals/session-goal-state.js +32 -17
- package/dist/core/goals/session-goal-state.js.map +1 -1
- package/dist/core/keybindings.d.ts +10 -0
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +10 -2
- package/dist/core/keybindings.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/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/model-capability.d.ts +34 -0
- package/dist/core/model-capability.d.ts.map +1 -1
- package/dist/core/model-capability.js +42 -1
- package/dist/core/model-capability.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/models/adaptation-store.d.ts +7 -0
- package/dist/core/models/adaptation-store.d.ts.map +1 -1
- package/dist/core/models/adaptation-store.js +47 -11
- 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 +3 -0
- package/dist/core/models/fitness-store.d.ts.map +1 -1
- package/dist/core/models/fitness-store.js +11 -2
- package/dist/core/models/fitness-store.js.map +1 -1
- 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 +9 -7
- 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/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-matrix/codes.d.ts +72 -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/runtime.d.ts +63 -0
- package/dist/core/process-matrix/runtime.d.ts.map +1 -0
- package/dist/core/process-matrix/runtime.js +310 -0
- package/dist/core/process-matrix/runtime.js.map +1 -0
- package/dist/core/process-matrix/store.d.ts +22 -0
- package/dist/core/process-matrix/store.d.ts.map +1 -0
- package/dist/core/process-matrix/store.js +80 -0
- package/dist/core/process-matrix/store.js.map +1 -0
- package/dist/core/process-matrix/supervisor.d.ts +72 -0
- package/dist/core/process-matrix/supervisor.d.ts.map +1 -0
- package/dist/core/process-matrix/supervisor.js +130 -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 +20 -0
- 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 +29 -5
- package/dist/core/reflection-controller.d.ts.map +1 -1
- package/dist/core/reflection-controller.js +215 -126
- 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 +44 -0
- package/dist/core/reload-blockers.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +8 -7
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/runtime-builder.d.ts +58 -5
- package/dist/core/runtime-builder.d.ts.map +1 -1
- package/dist/core/runtime-builder.js +209 -25
- 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.map +1 -1
- package/dist/core/sdk.js +3 -3
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-role.d.ts +31 -0
- package/dist/core/session-role.d.ts.map +1 -0
- package/dist/core/session-role.js +52 -0
- package/dist/core/session-role.js.map +1 -0
- package/dist/core/settings-manager.d.ts +42 -3
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +94 -60
- 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 +11 -2
- package/dist/core/tasks/session-task-state.d.ts.map +1 -1
- package/dist/core/tasks/session-task-state.js +27 -11
- 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-state.d.ts +8 -0
- package/dist/core/tasks/task-state.d.ts.map +1 -1
- package/dist/core/tasks/task-state.js +28 -1
- package/dist/core/tasks/task-state.js.map +1 -1
- 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-recovery-log-records.d.ts +7 -0
- package/dist/core/tool-recovery-log-records.d.ts.map +1 -1
- package/dist/core/tool-recovery-log-records.js +14 -6
- 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 +37 -0
- package/dist/core/tool-selection/tool-performance-store.d.ts.map +1 -1
- package/dist/core/tool-selection/tool-performance-store.js +87 -3
- 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/bash.d.ts +18 -0
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +97 -18
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/delegate-status.d.ts +14 -0
- package/dist/core/tools/delegate-status.d.ts.map +1 -1
- package/dist/core/tools/delegate-status.js +82 -7
- package/dist/core/tools/delegate-status.js.map +1 -1
- package/dist/core/tools/delegate.d.ts.map +1 -1
- package/dist/core/tools/delegate.js +25 -8
- package/dist/core/tools/delegate.js.map +1 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +52 -44
- package/dist/core/tools/find.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/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +5 -4
- package/dist/core/tools/grep.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 +2 -2
- package/dist/core/tools/model-fitness.js.map +1 -1
- package/dist/core/tools/render-utils.d.ts.map +1 -1
- package/dist/core/tools/render-utils.js +1 -1
- package/dist/core/tools/render-utils.js.map +1 -1
- package/dist/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 +69 -13
- 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 +4 -0
- package/dist/core/tools/task-steps.d.ts.map +1 -1
- package/dist/core/tools/task-steps.js +63 -8
- package/dist/core/tools/task-steps.js.map +1 -1
- package/dist/core/tools/tmux-dispatch.d.ts +86 -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 +153 -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/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/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 +247 -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/main.d.ts.map +1 -1
- package/dist/main.js +94 -0
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts +9 -0
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +38 -0
- 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/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/interactive-mode.d.ts +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +4 -0
- package/dist/modes/interactive/interactive-mode.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/session-flow-commands.d.ts.map +1 -1
- package/dist/modes/interactive/session-flow-commands.js +24 -4
- package/dist/modes/interactive/session-flow-commands.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/shell.d.ts +7 -1
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/shell.js +39 -9
- 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/docs/development.md +2 -0
- package/docs/packages.md +1 -1
- package/docs/process-matrix.md +120 -0
- package/docs/settings.md +5 -2
- package/docs/tmux-agent-manager.md +85 -2
- package/docs/windows.md +52 -3
- package/docs/work-directory.md +29 -0
- 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/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/docs/integration-sweep-builder-blueprint-2026-07-09.md +0 -365
- package/docs/integration-sweep-resume-2026-07-09.md +0 -407
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
1
2
|
import { readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
2
3
|
import { basename, dirname, join } from "node:path";
|
|
3
4
|
import { classifyFailure, compactToolResultDetailsForRetention, computeRetryDelayMs, createCustomMessage, DEFAULT_RETRY_POLICY, DEFAULT_STREAM_IDLE, RetryController, sleepAbortable, withStreamIdleWatchdog, } from "@caupulican/pi-agent-core";
|
|
4
5
|
import { calculateContextTokens, compact, createDeterministicCompaction, estimateContextTokens, getLatestCompactionEntry, prepareCompaction, runCompactionLoop, shouldCompact, } from "@caupulican/pi-agent-core/node";
|
|
5
|
-
import { cleanupSessionResources, formatToolRepairStandingRule, generateTextToolProtocolPrimer, getSupportedThinkingLevels, isContextOverflow, modelsAreEqual, parseTextToolCalls, streamSimple, } from "@caupulican/pi-ai";
|
|
6
|
+
import { cleanupSessionResources, formatToolRepairStandingRule, formatVariantEnvelope, generateTextToolProtocolPrimer, getSupportedThinkingLevels, isContextOverflow, modelsAreEqual, parseTextToolCalls, streamSimple, } from "@caupulican/pi-ai";
|
|
6
7
|
import { Type } from "typebox";
|
|
7
8
|
import { getAgentDir } from "../config.js";
|
|
8
9
|
import { stripFrontmatter } from "../utils/frontmatter.js";
|
|
9
10
|
import { getProcessWorkRun } from "../utils/work-directory.js";
|
|
11
|
+
import { resourceDir, stateFile } from "./agent-paths.js";
|
|
10
12
|
import { formatNoApiKeyFoundMessage, formatNoModelSelectedMessage } from "./auth-guidance.js";
|
|
11
13
|
import { buildForegroundEnvelope, formatForegroundEnvelopeObservation } from "./autonomy/foreground-envelope.js";
|
|
12
14
|
import { evaluateToolGate } from "./autonomy/gates.js";
|
|
@@ -23,16 +25,18 @@ import { FailureCorpusRecorder } from "./failure-corpus.js";
|
|
|
23
25
|
import { GatewayRegistry } from "./gateways/channel-provider.js";
|
|
24
26
|
import { GoalLoopController } from "./goal-loop-controller.js";
|
|
25
27
|
import { buildGoalRuntimeSnapshot, } from "./goals/goal-runtime-snapshot.js";
|
|
28
|
+
import { applyGoalEvent } from "./goals/goal-state.js";
|
|
26
29
|
import { appendGoalStateSnapshot, getLatestGoalStateSnapshot } from "./goals/session-goal-state.js";
|
|
27
30
|
import { constrainStreamIdleToHttpTimeout } from "./http-dispatcher.js";
|
|
28
31
|
import { appendLearningDecisionSnapshot, getLearningDecisionSnapshots } from "./learning/session-learning-decision.js";
|
|
29
32
|
import { isPromotedFrontmatter, SkillCurator } from "./learning/skill-curator.js";
|
|
30
33
|
import { LocalRuntimeController } from "./local-runtime-controller.js";
|
|
31
34
|
import { MemoryController } from "./memory-controller.js";
|
|
32
|
-
import { deriveModelCapabilityProfile, filterToolNamesForCapability, } from "./model-capability.js";
|
|
35
|
+
import { deriveModelCapabilityProfile, evaluateLaneWorkerRefusal, filterToolNamesForCapability, } from "./model-capability.js";
|
|
36
|
+
import { isLocalOrManagedRouterModel } from "./model-router/tool-escalation.js";
|
|
33
37
|
import { formatModelRouterModel, ModelRouterController } from "./model-router-controller.js";
|
|
34
38
|
import { ModelSelectionController } from "./model-selection-controller.js";
|
|
35
|
-
import { ModelAdaptationStore } from "./models/adaptation-store.js";
|
|
39
|
+
import { ModelAdaptationStore, } from "./models/adaptation-store.js";
|
|
36
40
|
import { HF_TRANSFORMERS_PROVIDER, OLLAMA_PROVIDER } from "./models/local-registration.js";
|
|
37
41
|
import { DEFAULT_ADAPTIVE_STREAM_IDLE_CEILING_MS, estimateContextPromptTokens, resolveAdaptiveStreamIdleOptions, withModelPerfProfile, } from "./models/perf-profile.js";
|
|
38
42
|
import { ProfileFilterController } from "./profile-filter-controller.js";
|
|
@@ -53,7 +57,8 @@ import { ToolRecoveryLogger } from "./tool-recovery-logger.js";
|
|
|
53
57
|
import { formatToolRepairHealthReport } from "./tool-repair-health.js";
|
|
54
58
|
import { resolveCurrentToolRepairSettings } from "./tool-repair-settings.js";
|
|
55
59
|
import { ToolPerformanceStore } from "./tool-selection/tool-performance-store.js";
|
|
56
|
-
import { ToolSelectionController } from "./tool-selection/tool-selection-controller.js";
|
|
60
|
+
import { formatToolSelectionReport, ToolSelectionController } from "./tool-selection/tool-selection-controller.js";
|
|
61
|
+
import { disposePersistentShellSession } from "./tools/shell-session.js";
|
|
57
62
|
// ============================================================================
|
|
58
63
|
// Stream-idle watchdog wiring
|
|
59
64
|
// ============================================================================
|
|
@@ -71,6 +76,19 @@ const MODEL_ADAPTATION_REPAIR_THRESHOLD = 3;
|
|
|
71
76
|
const TEXT_TOOL_PROTOCOL_VERSION = 1;
|
|
72
77
|
const TEXT_TOOL_PROTOCOL_TRIALS_PER_VARIANT = 2;
|
|
73
78
|
const TEXT_TOOL_PROTOCOL_PARSE_FAILURE_THRESHOLD = 3;
|
|
79
|
+
/** How often the one-line envelope-format corrective steer (see
|
|
80
|
+
* {@link AgentSession._maybeInjectTextProtocolCorrectiveSteer}) re-fires after the first parse
|
|
81
|
+
* failure this session — every Nth failure thereafter, not every single one, so a model that keeps
|
|
82
|
+
* missing the envelope doesn't get the reminder spliced into every turn (the breaker's same-signature
|
|
83
|
+
* counter is what actually demotes it, at {@link TEXT_TOOL_PROTOCOL_PARSE_FAILURE_THRESHOLD}). */
|
|
84
|
+
const TEXT_TOOL_PROTOCOL_STEER_INTERVAL = 5;
|
|
85
|
+
/** Anti-loop cooldown: the evidence-gated auto-probe (see {@link
|
|
86
|
+
* AgentSession._maybeAutoProbeOnValidationEscalation}) skips a model whose persisted `toolProbe`
|
|
87
|
+
* verdict was written within this window, so a burst of validation-escalation events for a still-
|
|
88
|
+
* failing model — or a very recent explicit `/toolprobe` run, or a future circuit-breaker demote — does
|
|
89
|
+
* not re-fire the (multi-completion) probe every time. Independent of, and complementary to, the
|
|
90
|
+
* per-session `_autoProbedModels` latch. */
|
|
91
|
+
const AUTO_TOOL_PROBE_FRESHNESS_MS = 15 * 60 * 1000;
|
|
74
92
|
const TEXT_TOOL_PROTOCOL_VARIANTS = [
|
|
75
93
|
"tool-tag",
|
|
76
94
|
"tool-call",
|
|
@@ -123,6 +141,43 @@ export function parseSkillBlock(text) {
|
|
|
123
141
|
}
|
|
124
142
|
/** customType for spawned-usage roll-up entries (Cost Aggregation, Model A). */
|
|
125
143
|
export const SPAWNED_USAGE_CUSTOM_TYPE = "spawned_usage";
|
|
144
|
+
/**
|
|
145
|
+
* customType for a persisted runaway-loop-backstop entry: the agent loop stopped a turn stuck
|
|
146
|
+
* repeating one identical tool-call signature. This is the session-log/telemetry sink for
|
|
147
|
+
* {@link Agent.onRunawayStop} — see `_installAgentToolHooks`.
|
|
148
|
+
*/
|
|
149
|
+
export const RUNAWAY_STOP_CUSTOM_TYPE = "runaway_stop";
|
|
150
|
+
/**
|
|
151
|
+
* customType for a persisted tool-validation-escalation entry: the agent loop bounced the same
|
|
152
|
+
* tool-call validation failure enough times to escalate. This is the session-log/telemetry sink for
|
|
153
|
+
* {@link Agent.onToolValidationEscalation} — see `_installAgentToolHooks`.
|
|
154
|
+
*/
|
|
155
|
+
export const TOOL_VALIDATION_ESCALATION_CUSTOM_TYPE = "tool_validation_escalation";
|
|
156
|
+
/** Fallback {@link IsolatedCompletionOptions.laneKind} for callers that do not tag their lane. */
|
|
157
|
+
export const DEFAULT_ISOLATED_LANE_KIND = "isolated";
|
|
158
|
+
/**
|
|
159
|
+
* Derive a STABLE synthetic cache-affinity key for an isolated completion lane. Isolated calls
|
|
160
|
+
* deliberately never carry the real session id (see reflection-controller.ts's isolation invariants —
|
|
161
|
+
* an isolated call must not entangle with the main session), which today also means every isolated
|
|
162
|
+
* call looks like a brand-new, uncorrelated session to providers with session-affinity headers /
|
|
163
|
+
* `prompt_cache_key` (anthropic.ts's `x-session-affinity`, openai-responses.ts /
|
|
164
|
+
* openai-completions.ts's `prompt_cache_key`), defeating their cache routing.
|
|
165
|
+
*
|
|
166
|
+
* This key is deterministic per `(laneKind, model, systemPrompt)` — the SAME lane calling the SAME
|
|
167
|
+
* model with the SAME (static) system prompt always gets the SAME key, so repeat calls route to the
|
|
168
|
+
* same cache-warm backend — while remaining fully synthetic: it is a salted hash, namespaced with a
|
|
169
|
+
* `lane:` prefix, and never derived from or equal to the real session id.
|
|
170
|
+
*/
|
|
171
|
+
export function computeLaneAffinityKey(laneKind, model, systemPrompt) {
|
|
172
|
+
const modelKey = model ? `${model.provider}/${model.id}` : "unknown-model";
|
|
173
|
+
// NUL-separated fields: laneKind/modelKey are drawn from small caller-controlled vocabularies
|
|
174
|
+
// that never contain a raw NUL, so this cannot field-collide the way a plain colon/space join could.
|
|
175
|
+
const digest = createHash("sha256")
|
|
176
|
+
.update(["pi-lane-affinity-v1", laneKind, modelKey, systemPrompt].join("\u0000"))
|
|
177
|
+
.digest("hex")
|
|
178
|
+
.slice(0, 32);
|
|
179
|
+
return `lane:${laneKind}:${digest}`;
|
|
180
|
+
}
|
|
126
181
|
// ============================================================================
|
|
127
182
|
// Constants
|
|
128
183
|
// ============================================================================
|
|
@@ -166,6 +221,8 @@ export class AgentSession {
|
|
|
166
221
|
_resourceLoader;
|
|
167
222
|
_customTools;
|
|
168
223
|
_cwd;
|
|
224
|
+
/** Per-agent persistent shell session identity: stable across runtime reloads, disposed with the session. */
|
|
225
|
+
_shellSessionKey = `agent:${randomUUID()}`;
|
|
169
226
|
_agentDir;
|
|
170
227
|
_collectWorkspaceSources;
|
|
171
228
|
_localRuntimeController;
|
|
@@ -175,11 +232,22 @@ export class AgentSession {
|
|
|
175
232
|
_repairModeSessionCounts = new Map();
|
|
176
233
|
_textProtocolParseFailures = new Map();
|
|
177
234
|
_textProtocolParseObservedThisTurn = false;
|
|
235
|
+
/** Total text-protocol parse-failure events observed this session, backing the
|
|
236
|
+
* {@link TEXT_TOOL_PROTOCOL_STEER_INTERVAL} throttle on {@link _maybeInjectTextProtocolCorrectiveSteer}. */
|
|
237
|
+
_textProtocolCorrectiveSteerCount = 0;
|
|
238
|
+
/** Monotonic counter backing tool-probe/text-protocol-calibration spawned-usage reportIds
|
|
239
|
+
* (see {@link _nextProbeUsageReportId}); guarantees each probe/calibration completion in the
|
|
240
|
+
* session lands in the cost ledger exactly once, even across repeated /toolprobe invocations. */
|
|
241
|
+
_toolProbeUsageReportSeq = 0;
|
|
242
|
+
/** Anti-loop: modelKeys the evidence-gated auto-probe has already fired for THIS session (see
|
|
243
|
+
* {@link _maybeAutoProbeOnValidationEscalation}), so a burst of validation-escalation events for
|
|
244
|
+
* the same still-failing model never re-fires the probe more than once per session. */
|
|
245
|
+
_autoProbedModels = new Set();
|
|
178
246
|
_textProtocolValidationOutcomeThisTurn;
|
|
179
247
|
/** Assembles the session's base system prompt from live session state (see
|
|
180
248
|
* system-prompt-builder.ts); owns the paired _baseSystemPromptOptions. */
|
|
181
249
|
_systemPromptBuilder;
|
|
182
|
-
/**
|
|
250
|
+
/** Autonomy telemetry sink + status/diagnostic snapshots (see autonomy-telemetry.ts); owns
|
|
183
251
|
* the latest gate outcome and the bounded gate-outcome history. */
|
|
184
252
|
_autonomyTelemetry;
|
|
185
253
|
/** Goal auto-continue + research lane + scout-worker delegation + model-fitness probe (see
|
|
@@ -208,6 +276,13 @@ export class AgentSession {
|
|
|
208
276
|
_analytics;
|
|
209
277
|
_treeNavigator;
|
|
210
278
|
_lastCostGuardDecision;
|
|
279
|
+
/**
|
|
280
|
+
* `getSpawnedUsage().cost` snapshotted at the start of the CURRENT foreground prompt cycle (see
|
|
281
|
+
* `_promptUnserialized`), so the cost guard can attribute only background/spawned spend since THIS
|
|
282
|
+
* turn began, not the session's entire lifetime spend. Reset on every new user prompt; every
|
|
283
|
+
* round-trip within the same turn (tool-call iterations) shares this one baseline.
|
|
284
|
+
*/
|
|
285
|
+
_costGuardTurnBaselineUsd = 0;
|
|
211
286
|
/** Per-turn model-router subsystem (see model-router-controller.ts); owns the transient route/intent,
|
|
212
287
|
* the cheap-turn session buffer, the escalation/retry flags, and the sticky last-decision/skip-reason
|
|
213
288
|
* used by the status report. Its parallel routed drive path delegates every turn back to
|
|
@@ -339,6 +414,9 @@ export class AgentSession {
|
|
|
339
414
|
getActiveExtensions: () => this._extensionRunner.activeExtensions,
|
|
340
415
|
getContextWindow: () => this.model?.contextWindow,
|
|
341
416
|
getThinkingLevel: () => this.thinkingLevel,
|
|
417
|
+
// The evidence-gated tool-selection hint block — self-gated by kill switch/evidence
|
|
418
|
+
// thresholds inside getActiveHints() itself, so this is a plain always-on pass-through.
|
|
419
|
+
getToolSelectionHints: () => this._toolSelection.getActiveHints(),
|
|
342
420
|
});
|
|
343
421
|
this._autonomyTelemetry = new AutonomyTelemetry({
|
|
344
422
|
getSessionManager: () => this.sessionManager,
|
|
@@ -365,6 +443,7 @@ export class AgentSession {
|
|
|
365
443
|
isModelExhausted: (model) => this._billingFailover.isExhausted(`${model.provider}/${model.id}`),
|
|
366
444
|
getModel: () => this.model ?? undefined,
|
|
367
445
|
isDelegateToolActive: () => this.getActiveToolNames().includes("delegate"),
|
|
446
|
+
isGoalToolActive: () => this.getActiveToolNames().includes("goal"),
|
|
368
447
|
getCapabilityEnvelope: () => this.capabilityEnvelope,
|
|
369
448
|
getModelCapabilityProfile: () => this.getModelCapabilityProfile(),
|
|
370
449
|
emit: (event) => this._emit(event),
|
|
@@ -378,7 +457,10 @@ export class AgentSession {
|
|
|
378
457
|
readMemoryForLane: (query) => this._memory.readMemoryForLane(query),
|
|
379
458
|
addSpawnedUsage: (usage, opts) => this.addSpawnedUsage(usage, opts),
|
|
380
459
|
runIsolatedCompletion: (opts) => this.runIsolatedCompletion(opts),
|
|
381
|
-
continueGoalLoop
|
|
460
|
+
// RAW loop, deliberately bypassing the public `continueGoalLoop` — that method now delegates
|
|
461
|
+
// to this controller's own `continueGoalLoopExclusive` guard, so routing through it here would
|
|
462
|
+
// recurse into the guard from inside itself instead of driving the actual continuation pass.
|
|
463
|
+
continueGoalLoop: (options) => this._goalContinuation.continueGoalLoop(options),
|
|
382
464
|
collectWorkspaceSources: (args) => this._collectWorkspaceSources(args),
|
|
383
465
|
});
|
|
384
466
|
this._memory = new MemoryController({
|
|
@@ -404,6 +486,10 @@ export class AgentSession {
|
|
|
404
486
|
// conservative in the safe direction for the summarizer capacity check.
|
|
405
487
|
estimateSummarizationInputTokens: () => this._pipeline.estimateCurrentContextTokens(this.agent.state.messages),
|
|
406
488
|
emitWarning: (message) => this._emit({ type: "warning", message }),
|
|
489
|
+
// Route a managed-local summarizer through the same readiness/residency gate every
|
|
490
|
+
// other isolated consumer uses, so compact() never calls a local model that was never
|
|
491
|
+
// confirmed up, installed, or resident (no-op for cloud models).
|
|
492
|
+
ensureModelReady: (model) => this._localRuntimeController.ensureIsolatedModelReady(model),
|
|
407
493
|
});
|
|
408
494
|
this._pipeline = new ContextPipeline({
|
|
409
495
|
getTurnIndex: () => this._turnIndex,
|
|
@@ -419,8 +505,8 @@ export class AgentSession {
|
|
|
419
505
|
addSpawnedUsage: (usage, opts) => this.addSpawnedUsage(usage, opts),
|
|
420
506
|
runIsolatedCompletion: (opts) => this.runIsolatedCompletion(opts),
|
|
421
507
|
});
|
|
422
|
-
const failureCorpusPath =
|
|
423
|
-
this._toolRecoveryEventLogPath =
|
|
508
|
+
const failureCorpusPath = stateFile(this._agentDir, "failure-corpus.jsonl");
|
|
509
|
+
this._toolRecoveryEventLogPath = stateFile(this._agentDir, TOOL_RECOVERY_EVENT_LOG_FILE);
|
|
424
510
|
const toolRepairSettings = this._toolRepairSettings();
|
|
425
511
|
this._failureCorpus = new FailureCorpusRecorder({
|
|
426
512
|
filePath: failureCorpusPath,
|
|
@@ -459,6 +545,7 @@ export class AgentSession {
|
|
|
459
545
|
emitAutonomyTelemetry: (event) => this._emitAutonomyTelemetry(event),
|
|
460
546
|
resolveLaneModel: (pattern) => this._backgroundLanes.resolveLaneModel(pattern),
|
|
461
547
|
resolveCurationModelIfFit: () => this._resolveCurationModelIfFit(),
|
|
548
|
+
getToolProbeVerdict: (model) => this._toolProbeVerdict(model),
|
|
462
549
|
});
|
|
463
550
|
this._reflection = new ReflectionController({
|
|
464
551
|
getModel: () => this.model,
|
|
@@ -482,6 +569,7 @@ export class AgentSession {
|
|
|
482
569
|
this._goalContinuation = new GoalLoopController({
|
|
483
570
|
getGoalRuntimeSnapshot: (settings) => this.getGoalRuntimeSnapshot(settings),
|
|
484
571
|
prompt: (text, options) => this.prompt(text, options),
|
|
572
|
+
recordGoalContinuationPass: (pass) => this.recordGoalContinuationPass(pass),
|
|
485
573
|
});
|
|
486
574
|
this._extensionRunnerRef = config.extensionRunnerRef;
|
|
487
575
|
this._initialActiveToolNames = config.initialActiveToolNames;
|
|
@@ -498,6 +586,7 @@ export class AgentSession {
|
|
|
498
586
|
this._runtimeBuilder = new RuntimeBuilder({
|
|
499
587
|
getAgent: () => this.agent,
|
|
500
588
|
getCwd: () => this._cwd,
|
|
589
|
+
getShellSessionKey: () => this._shellSessionKey,
|
|
501
590
|
getAgentDir: () => this._agentDir,
|
|
502
591
|
getSessionManager: () => this.sessionManager,
|
|
503
592
|
getSettingsManager: () => this.settingsManager,
|
|
@@ -560,11 +649,13 @@ export class AgentSession {
|
|
|
560
649
|
startWorkerDelegation: (request) => this._backgroundLanes.startWorkerDelegation(request),
|
|
561
650
|
getWorkerLaneRecords: () => this._backgroundLanes.getLaneRecords(),
|
|
562
651
|
getWorkerResultSnapshots: () => this.getWorkerResultSnapshots(),
|
|
652
|
+
resolveManagedLaneId: (id) => this._backgroundLanes.resolveManagedLaneId(id),
|
|
563
653
|
runWorkerDelegationOnce: (request) => this.runWorkerDelegationOnce(request),
|
|
564
654
|
runModelFitness: (args) => this.runModelFitness(args),
|
|
565
655
|
resolveCurationModelIfFit: () => this._resolveCurationModelIfFit(),
|
|
566
656
|
runIsolatedCompletion: (opts) => this.runIsolatedCompletion(opts),
|
|
567
657
|
addSpawnedUsage: (usage, opts) => this.addSpawnedUsage(usage, opts),
|
|
658
|
+
getLaneWorkerRefusal: () => this.getLaneWorkerRefusal(),
|
|
568
659
|
createAgentContextSnapshot: () => this._createAgentContextSnapshot(),
|
|
569
660
|
getContextUsage: () => this.getContextUsage(),
|
|
570
661
|
isStreaming: () => this.isStreaming,
|
|
@@ -573,6 +664,10 @@ export class AgentSession {
|
|
|
573
664
|
getExtensionCommandContextActions: () => this._extensionCommandContextActions,
|
|
574
665
|
getExtensionShutdownHandler: () => this._extensionShutdownHandler,
|
|
575
666
|
getExtensionErrorListener: () => this._extensionErrorListener,
|
|
667
|
+
// Stop any pi-spawned local runtime the just-committed reload no longer routes to.
|
|
668
|
+
reconcileLocalRuntimes: () => {
|
|
669
|
+
this._localRuntimeController.reconcile(this._collectEligibleLocalModelsForReconcile());
|
|
670
|
+
},
|
|
576
671
|
});
|
|
577
672
|
this._analytics = new SessionAnalytics({
|
|
578
673
|
getState: () => this.state,
|
|
@@ -633,6 +728,7 @@ export class AgentSession {
|
|
|
633
728
|
getSessionManager: () => this.sessionManager,
|
|
634
729
|
getSettingsManager: () => this.settingsManager,
|
|
635
730
|
isStreaming: () => this.isStreaming,
|
|
731
|
+
getShellSessionKey: () => this._shellSessionKey,
|
|
636
732
|
});
|
|
637
733
|
this._profileFilter = new ProfileFilterController({
|
|
638
734
|
getSettingsManager: () => this.settingsManager,
|
|
@@ -847,13 +943,30 @@ export class AgentSession {
|
|
|
847
943
|
const settings = this._getAdaptedCompactionSettings();
|
|
848
944
|
const contextWindow = this.model?.contextWindow ?? 0;
|
|
849
945
|
if (settings.enabled && contextWindow > 0 && !this.isCompacting) {
|
|
946
|
+
const triggerTokens = this.model?.autoCompactionTriggerTokens;
|
|
850
947
|
const contextTokens = this._estimateCurrentContextTokens(authoritativeMessages);
|
|
851
|
-
if (shouldCompact(contextTokens, contextWindow, settings,
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
948
|
+
if (shouldCompact(contextTokens, contextWindow, settings, triggerTokens)) {
|
|
949
|
+
// This pre-check runs BEFORE context-gc (below, same transform pass), so the
|
|
950
|
+
// raw estimate above can't see this turn's own GC packing. Since context-gc later
|
|
951
|
+
// packs the SAME messages before they're ever sent, a raw-over-threshold turn that
|
|
952
|
+
// GC alone would bring back under threshold doesn't actually need compaction.
|
|
953
|
+
// Project this turn's GC pass read-only (writePayloads=false -- no digest/curation
|
|
954
|
+
// enqueue, no disk write, no artifact-reference release; see
|
|
955
|
+
// ContextPipeline.applyContextGc) to get the same packed output the real pass would
|
|
956
|
+
// produce for these messages, then re-check against ITS estimate. Packing only ever
|
|
957
|
+
// shrinks (never grows) a message, so the projected estimate is never higher than
|
|
958
|
+
// the raw one: this can only SUPPRESS an unnecessary compaction, never skip a
|
|
959
|
+
// genuinely needed one -- the hard near-full trigger inside shouldCompact still
|
|
960
|
+
// fires whenever the projected estimate itself remains over threshold.
|
|
961
|
+
const gcProjection = this._applyContextGc(authoritativeMessages, false);
|
|
962
|
+
const projectedContextTokens = this._estimateCurrentContextTokens(gcProjection.messages);
|
|
963
|
+
if (shouldCompact(projectedContextTokens, contextWindow, settings, triggerTokens)) {
|
|
964
|
+
const latestBefore = getLatestCompactionEntry(this.sessionManager.getBranch())?.id;
|
|
965
|
+
await this._runAutoCompaction("threshold", false);
|
|
966
|
+
const latestAfter = getLatestCompactionEntry(this.sessionManager.getBranch())?.id;
|
|
967
|
+
if (latestAfter && latestAfter !== latestBefore) {
|
|
968
|
+
currentMessages = this.agent.state.messages.slice();
|
|
969
|
+
}
|
|
857
970
|
}
|
|
858
971
|
}
|
|
859
972
|
}
|
|
@@ -888,6 +1001,15 @@ export class AgentSession {
|
|
|
888
1001
|
* model, full system prompt, converted messages, and tool schemas are known. The guard is a
|
|
889
1002
|
* projection threshold rather than a hard output cap: warning mode never reduces capability, while
|
|
890
1003
|
* opt-in downgrade changes only this request's reasoning effort. Best-effort: never throws.
|
|
1004
|
+
*
|
|
1005
|
+
* The ceiling is turn-cumulative: the next foreground call's projection is folded together with
|
|
1006
|
+
* background/research/worker/reflection spend recorded SINCE THIS TURN BEGAN — {@link getSpawnedUsage}'s
|
|
1007
|
+
* already-recorded rollup (the same read-side-deduped total the footer's SUBAGENTS line uses) minus the
|
|
1008
|
+
* baseline snapshotted at the top of `_promptUnserialized` ({@link _costGuardTurnBaselineUsd}) — so a
|
|
1009
|
+
* turn that is cheap in the foreground but has spent heavily via background lanes THIS turn still trips
|
|
1010
|
+
* the warning, while a prior turn's background spend does not keep every later turn's guard stuck
|
|
1011
|
+
* "over". A background lane that finishes mid-turn is attributed to whichever turn it completes in.
|
|
1012
|
+
* Per-lane dollar caps (research/worker `maxUsd`) are separate and untouched by this guard.
|
|
891
1013
|
*/
|
|
892
1014
|
_resolveCostGuardRequestReasoning(model, context, reasoning, requestMaxTokens) {
|
|
893
1015
|
try {
|
|
@@ -907,7 +1029,10 @@ export class AgentSession {
|
|
|
907
1029
|
cost: model.cost,
|
|
908
1030
|
longContextPricing: model.longContextPricing,
|
|
909
1031
|
});
|
|
910
|
-
|
|
1032
|
+
// Only spend recorded SINCE this turn's baseline counts -- never negative (a dedup/rollup
|
|
1033
|
+
// correction could otherwise move the total backward transiently).
|
|
1034
|
+
const cumulativeBackgroundUsd = Math.max(0, this.getSpawnedUsage().cost - this._costGuardTurnBaselineUsd);
|
|
1035
|
+
const decision = evaluateCostGuard(estUsd, { maxTurnUsd: guard.maxTurnUsd, action: guard.action }, cumulativeBackgroundUsd);
|
|
911
1036
|
this._lastCostGuardDecision = decision;
|
|
912
1037
|
if (!decision.over || guard.action !== "downgrade" || reasoning === undefined)
|
|
913
1038
|
return reasoning;
|
|
@@ -925,7 +1050,7 @@ export class AgentSession {
|
|
|
925
1050
|
}
|
|
926
1051
|
get _skillCurator() {
|
|
927
1052
|
if (!this._skillCuratorInstance) {
|
|
928
|
-
this._skillCuratorInstance = new SkillCurator(
|
|
1053
|
+
this._skillCuratorInstance = new SkillCurator(resourceDir("skills", this._agentDir));
|
|
929
1054
|
}
|
|
930
1055
|
return this._skillCuratorInstance;
|
|
931
1056
|
}
|
|
@@ -1024,6 +1149,28 @@ export class AgentSession {
|
|
|
1024
1149
|
}
|
|
1025
1150
|
return this.agent.streamFn(model, context, requestOptions);
|
|
1026
1151
|
}
|
|
1152
|
+
/** Builds a reportId that uniquely identifies one probe/calibration completion within the
|
|
1153
|
+
* session: the model, a caller-supplied `kind` (e.g. "read-task", "echo", or
|
|
1154
|
+
* "text-protocol:<variant>"), and a monotonic sequence number. The sequence number (not
|
|
1155
|
+
* wall-clock time or randomness) is what guarantees no collision even when the same model+kind
|
|
1156
|
+
* is probed again later in the session (e.g. a repeated /toolprobe run), so genuine repeat spend
|
|
1157
|
+
* is never silently deduped away. */
|
|
1158
|
+
_nextProbeUsageReportId(model, kind) {
|
|
1159
|
+
return `tool-probe:${this._modelRef(model)}:${kind}:${this._toolProbeUsageReportSeq++}`;
|
|
1160
|
+
}
|
|
1161
|
+
/** Awaits a tool-probe/text-protocol-calibration stream's result and, if the resolved message
|
|
1162
|
+
* carries reportable usage, rolls it into spawned usage under `reportId` so the turn-scoped cost
|
|
1163
|
+
* guard and daily usage see it. These trial completions previously spent tokens with no
|
|
1164
|
+
* addSpawnedUsage call, making them invisible to both. `addSpawnedUsage` dedups on `reportId`, so
|
|
1165
|
+
* a re-report of the same id is a no-op. */
|
|
1166
|
+
async _resolveProbeStreamCountingUsage(stream, label, reportId) {
|
|
1167
|
+
const message = await stream.result();
|
|
1168
|
+
const usage = message.usage;
|
|
1169
|
+
if (usage && (usage.cost.total > 0 || usage.totalTokens > 0)) {
|
|
1170
|
+
this.addSpawnedUsage(usage, { label, reportId });
|
|
1171
|
+
}
|
|
1172
|
+
return message;
|
|
1173
|
+
}
|
|
1027
1174
|
_textProtocolCalibrationContext(variant, token) {
|
|
1028
1175
|
const primer = generateTextToolProtocolPrimer([TEXT_TOOL_PROTOCOL_ECHO_TOOL], { variant });
|
|
1029
1176
|
const instruction = `Text tool protocol calibration trial. Using the protocol above, call echo with data exactly "${token}". Output only the tool-call envelope.`;
|
|
@@ -1055,7 +1202,8 @@ export class AgentSession {
|
|
|
1055
1202
|
messages: [{ role: "user", content: [{ type: "text", text: instruction }], timestamp: Date.now() }],
|
|
1056
1203
|
tools: [NATIVE_TOOL_PROBE_READ_TOOL],
|
|
1057
1204
|
}, { textToolCallProtocol: false, maxRetries: 0, temperature: 0, maxTokens: 768 });
|
|
1058
|
-
|
|
1205
|
+
const message = await this._resolveProbeStreamCountingUsage(stream, "tool-probe", this._nextProbeUsageReportId(model, "read-task"));
|
|
1206
|
+
return this._messageHasToolCallWithStringArgument(message, "read", "path", path);
|
|
1059
1207
|
}
|
|
1060
1208
|
async _runNativeEchoToolProbeTrial(model, token) {
|
|
1061
1209
|
const instruction = `Native tool-call capability probe: echo-only. Use provider-native tool calling, not prose. ` +
|
|
@@ -1065,7 +1213,8 @@ export class AgentSession {
|
|
|
1065
1213
|
messages: [{ role: "user", content: [{ type: "text", text: instruction }], timestamp: Date.now() }],
|
|
1066
1214
|
tools: [TEXT_TOOL_PROTOCOL_ECHO_TOOL],
|
|
1067
1215
|
}, { textToolCallProtocol: false, maxRetries: 0, temperature: 0, maxTokens: 256 });
|
|
1068
|
-
|
|
1216
|
+
const message = await this._resolveProbeStreamCountingUsage(stream, "tool-probe", this._nextProbeUsageReportId(model, "echo"));
|
|
1217
|
+
return this._messageHasToolCallWithStringArgument(message, "echo", "data", token);
|
|
1069
1218
|
}
|
|
1070
1219
|
async _gradeNativeToolCallingForModel(model, token) {
|
|
1071
1220
|
const path = join(getProcessWorkRun(this._agentDir, "probes", "native-tools").path, `pi-native-probe-${process.pid}-${Date.now()}.txt`);
|
|
@@ -1090,7 +1239,7 @@ export class AgentSession {
|
|
|
1090
1239
|
temperature: 0,
|
|
1091
1240
|
maxTokens: 256,
|
|
1092
1241
|
});
|
|
1093
|
-
const message = await stream.
|
|
1242
|
+
const message = await this._resolveProbeStreamCountingUsage(stream, "text-protocol-calibration", this._nextProbeUsageReportId(model, `text-protocol:${variant}`));
|
|
1094
1243
|
const text = message.content
|
|
1095
1244
|
.filter((block) => block.type === "text")
|
|
1096
1245
|
.map((block) => block.text)
|
|
@@ -1127,40 +1276,51 @@ export class AgentSession {
|
|
|
1127
1276
|
}
|
|
1128
1277
|
return { status: "failed", attemptedAt, variantsTried };
|
|
1129
1278
|
}
|
|
1279
|
+
/**
|
|
1280
|
+
* A PURE READER of the persisted calibration — never calibrates inline and
|
|
1281
|
+
* never throws out of the prompt path. A model whose flag is on but has no valid current-version
|
|
1282
|
+
* protocol on record falls back to native for this turn (with a warning pointing at /toolprobe)
|
|
1283
|
+
* instead of blocking the user's message behind up to 8 inline calibration completions or
|
|
1284
|
+
* aborting the turn entirely. Calibration now only ever happens off the hot path: explicit
|
|
1285
|
+
* /toolprobe, or the capability-gate spine's evidence-gated auto-probe.
|
|
1286
|
+
*/
|
|
1130
1287
|
async _ensureTextToolProtocolForActiveModel() {
|
|
1131
1288
|
const model = this.agent.state.model;
|
|
1132
1289
|
if (!this._textProtocolFlag(model)) {
|
|
1133
1290
|
this.agent.textToolCallProtocol = undefined;
|
|
1134
1291
|
return;
|
|
1135
1292
|
}
|
|
1293
|
+
// Force-enable (a global settings override or Model.textToolCallProtocol) wins regardless of
|
|
1294
|
+
// whether this model has ever been graded-probed — that is the point of an explicit override.
|
|
1295
|
+
// Preserve it exactly as before: default to the tool-tag variant, no inline calibration. Only
|
|
1296
|
+
// the graded-evidence path below (flag on solely because of a persisted toolProbe verdict)
|
|
1297
|
+
// needs a valid persisted protocol to proceed.
|
|
1298
|
+
const forceEnabled = this._toolRepairSettings().textProtocol === true || model?.textToolCallProtocol === true;
|
|
1136
1299
|
const modelKey = this._modelAdaptationKeyFor(model);
|
|
1137
|
-
if (!modelKey) {
|
|
1300
|
+
if (!modelKey || forceEnabled) {
|
|
1138
1301
|
this.agent.textToolCallProtocol = true;
|
|
1139
1302
|
return;
|
|
1140
1303
|
}
|
|
1141
1304
|
const profile = this._modelAdaptationStore.get(modelKey);
|
|
1142
|
-
if (profile.protocol?.version === TEXT_TOOL_PROTOCOL_VERSION) {
|
|
1143
|
-
if (profile.protocol.status === "failed") {
|
|
1144
|
-
this.agent.textToolCallProtocol = undefined;
|
|
1145
|
-
throw new Error(`Previous text tool protocol calibration failed for ${modelKey} at ${profile.protocol.attemptedAt}. ` +
|
|
1146
|
-
`Variants tried: ${profile.protocol.variantsTried.join(", ")}. ` +
|
|
1147
|
-
`Run /toolhealth for details or /toolprotocol-reset ${modelKey} to retry calibration.`);
|
|
1148
|
-
}
|
|
1305
|
+
if (profile.protocol?.version === TEXT_TOOL_PROTOCOL_VERSION && profile.protocol.status !== "failed") {
|
|
1149
1306
|
this.agent.textToolCallProtocol = { variant: profile.protocol.variant };
|
|
1150
1307
|
return;
|
|
1151
1308
|
}
|
|
1152
|
-
const result = await this._calibrateTextToolProtocolForModel(model, modelKey, { persistFailure: true });
|
|
1153
|
-
if (result.status === "calibrated") {
|
|
1154
|
-
this.agent.textToolCallProtocol = { variant: result.variant };
|
|
1155
|
-
return;
|
|
1156
|
-
}
|
|
1157
1309
|
this.agent.textToolCallProtocol = undefined;
|
|
1158
|
-
|
|
1159
|
-
|
|
1310
|
+
this._emit({
|
|
1311
|
+
type: "warning",
|
|
1312
|
+
message: profile.protocol?.status === "failed"
|
|
1313
|
+
? `Text tool protocol calibration for ${modelKey} previously failed (variants tried: ${profile.protocol.variantsTried.join(", ")}); falling back to native tool calls this turn. Run /toolprobe ${modelKey} to recalibrate.`
|
|
1314
|
+
: `Text tool protocol for ${modelKey} has no valid calibration on record; falling back to native tool calls this turn. Run /toolprobe ${modelKey} to calibrate.`,
|
|
1315
|
+
});
|
|
1160
1316
|
}
|
|
1161
1317
|
_modelRef(model) {
|
|
1162
1318
|
return `${model.provider}/${model.id}`;
|
|
1163
1319
|
}
|
|
1320
|
+
/** The persisted `/toolprobe` verdict on record for this model, if any (undefined = unprobed). */
|
|
1321
|
+
_toolProbeVerdict(model) {
|
|
1322
|
+
return this._modelAdaptationStore.get(this._modelRef(model)).toolProbe?.status;
|
|
1323
|
+
}
|
|
1164
1324
|
_formatToolProbeReport(results) {
|
|
1165
1325
|
const lines = [
|
|
1166
1326
|
"Tool probe results:",
|
|
@@ -1258,11 +1418,22 @@ export class AgentSession {
|
|
|
1258
1418
|
}
|
|
1259
1419
|
return { results, table: this._formatToolProbeReport(results) };
|
|
1260
1420
|
}
|
|
1421
|
+
/**
|
|
1422
|
+
* The text-protocol circuit breaker. Every parse failure (from either the
|
|
1423
|
+
* live per-completion {@link Agent.onTextToolProtocolParse} callback or the post-hoc detection in
|
|
1424
|
+
* {@link _recordTextToolProtocolParseOutcomeFromLastAssistant}) gets a throttled one-line
|
|
1425
|
+
* corrective steer for the next turn. On the 3rd consecutive SAME-SIGNATURE failure — graded
|
|
1426
|
+
* evidence a model genuinely cannot speak this dialect, not a single bad turn — the breaker also
|
|
1427
|
+
* demotes the persisted tool-probe verdict to "none" so {@link _textProtocolFlag} reads false next
|
|
1428
|
+
* turn and native is attempted instead of thrashing on a protocol this model has proven it can't
|
|
1429
|
+
* follow.
|
|
1430
|
+
*/
|
|
1261
1431
|
_handleTextToolProtocolParse(event) {
|
|
1262
1432
|
this._textProtocolParseObservedThisTurn = true;
|
|
1263
1433
|
const modelKey = `${event.provider}/${event.model}`;
|
|
1264
1434
|
if (event.status === "parsed")
|
|
1265
1435
|
return;
|
|
1436
|
+
this._maybeInjectTextProtocolCorrectiveSteer(event.variant);
|
|
1266
1437
|
const signature = `${event.variant}:${event.reason ?? "failed"}`;
|
|
1267
1438
|
const previous = this._textProtocolParseFailures.get(modelKey);
|
|
1268
1439
|
const repeats = previous?.signature === signature ? previous.repeats + 1 : 1;
|
|
@@ -1275,6 +1446,43 @@ export class AgentSession {
|
|
|
1275
1446
|
this.agent.textToolCallProtocol = undefined;
|
|
1276
1447
|
}
|
|
1277
1448
|
this._textProtocolParseFailures.delete(modelKey);
|
|
1449
|
+
// Demote on graded evidence -- TEXT_TOOL_PROTOCOL_PARSE_FAILURE_THRESHOLD identical-signature
|
|
1450
|
+
// parse failures in a row -- rather than thrashing every turn. The fresh probedAt doubles as
|
|
1451
|
+
// the capability-gate spine's auto-probe freshness gate, so this demotion doesn't immediately
|
|
1452
|
+
// trigger a re-probe/re-phone loop.
|
|
1453
|
+
const probedAt = new Date().toISOString();
|
|
1454
|
+
this._modelAdaptationStore.setToolProbe(modelKey, {
|
|
1455
|
+
version: TEXT_TOOL_PROTOCOL_VERSION,
|
|
1456
|
+
status: "none",
|
|
1457
|
+
probedAt,
|
|
1458
|
+
nativeGrade: profile.toolProbe?.nativeGrade,
|
|
1459
|
+
diagnostic: `Text protocol parsing failed ${TEXT_TOOL_PROTOCOL_PARSE_FAILURE_THRESHOLD}x in a row with signature "${signature}".`,
|
|
1460
|
+
}, probedAt);
|
|
1461
|
+
this._emit({
|
|
1462
|
+
type: "warning",
|
|
1463
|
+
message: `Text tool protocol for ${modelKey} stopped parsing after ${TEXT_TOOL_PROTOCOL_PARSE_FAILURE_THRESHOLD} attempts; demoted to native fallback. Run /toolprobe ${modelKey} to recalibrate.`,
|
|
1464
|
+
});
|
|
1465
|
+
}
|
|
1466
|
+
/**
|
|
1467
|
+
* A phone model whose envelope fails to parse gets no corrective guidance today —
|
|
1468
|
+
* the runaway-loop backstop only trips on repeated PARSED tool-call signatures (agent-loop.ts), so
|
|
1469
|
+
* an every-turn unparseable-prose model never trips it. Inject a one-line reminder of the envelope
|
|
1470
|
+
* shape as a nextTurn message, reusing {@link formatVariantEnvelope} so the reminder can never
|
|
1471
|
+
* drift from the grammar the primer actually teaches. Throttled to the first failure this session
|
|
1472
|
+
* and then every {@link TEXT_TOOL_PROTOCOL_STEER_INTERVAL}th after — the breaker above is what
|
|
1473
|
+
* actually demotes a genuinely-failing model at the 3rd same-signature failure; this is guidance,
|
|
1474
|
+
* not a second counter.
|
|
1475
|
+
*/
|
|
1476
|
+
_maybeInjectTextProtocolCorrectiveSteer(variant) {
|
|
1477
|
+
this._textProtocolCorrectiveSteerCount++;
|
|
1478
|
+
if (this._textProtocolCorrectiveSteerCount !== 1 &&
|
|
1479
|
+
this._textProtocolCorrectiveSteerCount % TEXT_TOOL_PROTOCOL_STEER_INTERVAL !== 0) {
|
|
1480
|
+
return;
|
|
1481
|
+
}
|
|
1482
|
+
const reminder = `Reminder: to call a tool, emit exactly this envelope shape: ${formatVariantEnvelope(variant, "TOOL", '{"arg":"value"}')} — no other format is recognized. Reasoning may appear as prose before the envelope, never inside it.`;
|
|
1483
|
+
this.sendCustomMessage({ customType: "text-protocol-corrective-steer", content: reminder, display: false }, { deliverAs: "nextTurn" }).catch(() => {
|
|
1484
|
+
// Best-effort steer; a failure to queue it must not break parse-failure handling.
|
|
1485
|
+
});
|
|
1278
1486
|
}
|
|
1279
1487
|
_handleTextToolProtocolValidationOutcome(event) {
|
|
1280
1488
|
if (event.source !== "text-protocol")
|
|
@@ -1543,10 +1751,10 @@ export class AgentSession {
|
|
|
1543
1751
|
...this._profileFilter.profileDeniedResourceObservations(),
|
|
1544
1752
|
...this._profileFilter.getInertExtensionWarnings(),
|
|
1545
1753
|
...this._unboundToolGrantWarnings,
|
|
1546
|
-
//
|
|
1754
|
+
// Auto-built per-turn foreground envelope (observe-only; not enforced). Falls back to a
|
|
1547
1755
|
// live preview when no turn has run yet so /context always shows the current scope.
|
|
1548
1756
|
formatForegroundEnvelopeObservation(this._currentForegroundEnvelope ?? this._buildForegroundEnvelopeFromState()),
|
|
1549
|
-
//
|
|
1757
|
+
// A user disable always beats a profile grant — surface the conflict.
|
|
1550
1758
|
...["tools", "skills", "prompts", "extensions"].flatMap((kind) => this.settingsManager
|
|
1551
1759
|
.getProfileGrantsOverriddenByUserDisable(kind)
|
|
1552
1760
|
.map((entry) => `profile grants ${kind} "${entry}" but your disable list overrides it (user disable wins; re-enable to use)`)),
|
|
@@ -1558,7 +1766,10 @@ export class AgentSession {
|
|
|
1558
1766
|
return formatContextCompositionDashboard(this.getContextCompositionReport());
|
|
1559
1767
|
}
|
|
1560
1768
|
formatToolRepairHealthReport() {
|
|
1561
|
-
return
|
|
1769
|
+
return [
|
|
1770
|
+
formatToolRepairHealthReport(this._modelAdaptationStore, new Date(), this._toolRecoveryLogger.getStats()),
|
|
1771
|
+
formatToolSelectionReport(this._toolSelection.getReport()),
|
|
1772
|
+
].join("\n\n");
|
|
1562
1773
|
}
|
|
1563
1774
|
async flushToolRecoveryLogsForTests(timeoutMs = 1000) {
|
|
1564
1775
|
await this._toolRecoveryLogger.flush(timeoutMs);
|
|
@@ -1625,6 +1836,119 @@ export class AgentSession {
|
|
|
1625
1836
|
_installAgentToolHooks() {
|
|
1626
1837
|
this.agent.beforeToolCall = this._toolGate.beforeToolCall;
|
|
1627
1838
|
this.agent.afterToolCall = this._toolGate.afterToolCall;
|
|
1839
|
+
this.agent.onRunawayStop = (info) => this._handleRunawayStop(info);
|
|
1840
|
+
this.agent.onToolValidationEscalation = (event) => this._handleToolValidationEscalation(event);
|
|
1841
|
+
}
|
|
1842
|
+
/**
|
|
1843
|
+
* The runaway-loop backstop ({@link Agent.maxStallTurns}) stopped a turn stuck repeating one
|
|
1844
|
+
* identical tool-call signature. Previously silent — this is the first host handler. Records a
|
|
1845
|
+
* session-log/telemetry entry (see {@link RUNAWAY_STOP_CUSTOM_TYPE}) and surfaces a user-visible
|
|
1846
|
+
* warning through the same event the context-window/compaction backstops use.
|
|
1847
|
+
*/
|
|
1848
|
+
_handleRunawayStop(info) {
|
|
1849
|
+
const record = {
|
|
1850
|
+
signature: info.signature,
|
|
1851
|
+
repeats: info.repeats,
|
|
1852
|
+
model: this.model?.id,
|
|
1853
|
+
provider: this.model?.provider,
|
|
1854
|
+
at: new Date().toISOString(),
|
|
1855
|
+
};
|
|
1856
|
+
this.sessionManager.appendCustomEntry(RUNAWAY_STOP_CUSTOM_TYPE, record);
|
|
1857
|
+
this._emit({
|
|
1858
|
+
type: "warning",
|
|
1859
|
+
message: `Stopped: the model repeated the same tool call ${info.repeats} times in a row without making progress. Review the last tool result and steer or retry with a different approach.`,
|
|
1860
|
+
});
|
|
1861
|
+
}
|
|
1862
|
+
/** Anti-loop: true when this model's persisted tool-probe verdict was written within the
|
|
1863
|
+
* auto-probe freshness window ({@link AUTO_TOOL_PROBE_FRESHNESS_MS}) — covers a very recent
|
|
1864
|
+
* explicit `/toolprobe` run or a fresh circuit-breaker demote from an EARLIER session, complementing
|
|
1865
|
+
* the in-session {@link _autoProbedModels} latch. */
|
|
1866
|
+
_hasFreshToolProbeVerdict(modelKey) {
|
|
1867
|
+
const probedAt = this._modelAdaptationStore.get(modelKey).toolProbe?.probedAt;
|
|
1868
|
+
if (!probedAt)
|
|
1869
|
+
return false;
|
|
1870
|
+
const age = Date.now() - new Date(probedAt).getTime();
|
|
1871
|
+
return Number.isFinite(age) && age >= 0 && age < AUTO_TOOL_PROBE_FRESHNESS_MS;
|
|
1872
|
+
}
|
|
1873
|
+
/**
|
|
1874
|
+
* Evidence-gated native→phone auto-probe for a LOCAL/MANAGED model (never cloud — see
|
|
1875
|
+
* {@link isLocalOrManagedRouterModel}) that just crossed the tool-argument-validation escalation
|
|
1876
|
+
* threshold — repeated identical validation failures with no successful native call in between,
|
|
1877
|
+
* which is exactly the graded evidence {@link Agent.onToolValidationEscalation} already requires
|
|
1878
|
+
* before firing. Runs the SAME probe `/toolprobe` uses ({@link _probeToolCallingForModel}: native
|
|
1879
|
+
* trials first, so a model that can actually tool-call natively still resolves to verdict
|
|
1880
|
+
* "native" and is never phoned) entirely OFF the hot path — fired here but never awaited by the
|
|
1881
|
+
* caller, so a slow or failing probe can never block or throw the user's in-flight turn.
|
|
1882
|
+
* Anti-loop: skipped when this session already auto-probed this model, or a fresh persisted
|
|
1883
|
+
* verdict already exists ({@link _hasFreshToolProbeVerdict}) — otherwise a model that keeps
|
|
1884
|
+
* failing validation every turn would re-fire the (multi-completion) probe every single turn.
|
|
1885
|
+
*/
|
|
1886
|
+
_maybeAutoProbeOnValidationEscalation(model) {
|
|
1887
|
+
const modelKey = this._modelRef(model);
|
|
1888
|
+
if (this._autoProbedModels.has(modelKey) || this._hasFreshToolProbeVerdict(modelKey))
|
|
1889
|
+
return;
|
|
1890
|
+
this._autoProbedModels.add(modelKey);
|
|
1891
|
+
void this._probeToolCallingForModel(model)
|
|
1892
|
+
.then((result) => {
|
|
1893
|
+
if (this._disposed)
|
|
1894
|
+
return;
|
|
1895
|
+
const detail = result.verdict === "text-protocol"
|
|
1896
|
+
? ` (variant ${result.variant}); it will use the text tool protocol starting next turn`
|
|
1897
|
+
: result.verdict === "none"
|
|
1898
|
+
? " — no working tool-call path was found; run /toolprobe for details"
|
|
1899
|
+
: "; native tool calls stay in use";
|
|
1900
|
+
this._emit({
|
|
1901
|
+
type: "warning",
|
|
1902
|
+
message: `Auto-probed ${modelKey} after repeated native tool-call validation failures: verdict "${result.verdict}"${detail}.`,
|
|
1903
|
+
});
|
|
1904
|
+
})
|
|
1905
|
+
.catch((error) => {
|
|
1906
|
+
if (this._disposed)
|
|
1907
|
+
return;
|
|
1908
|
+
this._emit({
|
|
1909
|
+
type: "warning",
|
|
1910
|
+
message: `Auto-probe for ${modelKey} (triggered by repeated tool-call validation failures) did not complete: ${error instanceof Error ? error.message : String(error)}.`,
|
|
1911
|
+
});
|
|
1912
|
+
});
|
|
1913
|
+
}
|
|
1914
|
+
/**
|
|
1915
|
+
* A repeated identical tool-argument-validation failure crossed the escalation threshold
|
|
1916
|
+
* ({@link Agent.toolValidationEscalationThreshold}) — the graded evidence the capability-gate
|
|
1917
|
+
* spine acts on. Always records a session-log/telemetry entry (see {@link
|
|
1918
|
+
* TOOL_VALIDATION_ESCALATION_CUSTOM_TYPE}), then branches on the failing model's class:
|
|
1919
|
+
* - LOCAL/MANAGED ({@link isLocalOrManagedRouterModel}, never cloud): the failure is evidence the
|
|
1920
|
+
* model may lack native tool-calling, so it fires the evidence-gated native→phone auto-probe
|
|
1921
|
+
* off the hot path ({@link _maybeAutoProbeOnValidationEscalation}). Escalating a local model's
|
|
1922
|
+
* ROUTER TIER on a tool-call failure would not fix a capability problem, so this branch never
|
|
1923
|
+
* touches the model router.
|
|
1924
|
+
* - CLOUD (known tool-capable): the failure is evidence the routed tier is too weak for this
|
|
1925
|
+
* request, so it escalates via {@link ModelRouterController.requestValidationFailureEscalation}
|
|
1926
|
+
* — de-conflated from the beforeToolCall mutation gate ({@link
|
|
1927
|
+
* ModelRouterController.maybeEscalateToolCall}/`shouldEscalateModelRouterTool`): repeated
|
|
1928
|
+
* validation failure is grounds to escalate REGARDLESS of the failing tool's mutation status,
|
|
1929
|
+
* so a read-only tool's repeated failure now escalates too (previously a no-op, since the old
|
|
1930
|
+
* code reused the mutation gate verbatim for this unrelated signal). Cloud models are never
|
|
1931
|
+
* probe-gated or phoned by this handler.
|
|
1932
|
+
* If the registry can no longer resolve `event.model`/`event.provider` (e.g. the model was
|
|
1933
|
+
* unregistered mid-session), falls back to the cloud/tier-escalation path — the previously
|
|
1934
|
+
* existing behavior — rather than silently dropping the signal.
|
|
1935
|
+
*/
|
|
1936
|
+
_handleToolValidationEscalation(event) {
|
|
1937
|
+
const record = {
|
|
1938
|
+
tool: event.tool,
|
|
1939
|
+
signature: event.signature,
|
|
1940
|
+
repeats: event.repeats,
|
|
1941
|
+
model: event.model,
|
|
1942
|
+
provider: event.provider,
|
|
1943
|
+
at: new Date().toISOString(),
|
|
1944
|
+
};
|
|
1945
|
+
this.sessionManager.appendCustomEntry(TOOL_VALIDATION_ESCALATION_CUSTOM_TYPE, record);
|
|
1946
|
+
const model = this._modelRegistry.find(event.provider, event.model);
|
|
1947
|
+
if (model && isLocalOrManagedRouterModel(model)) {
|
|
1948
|
+
this._maybeAutoProbeOnValidationEscalation(model);
|
|
1949
|
+
return;
|
|
1950
|
+
}
|
|
1951
|
+
this._modelRouter.requestValidationFailureEscalation();
|
|
1628
1952
|
}
|
|
1629
1953
|
// =========================================================================
|
|
1630
1954
|
// Event Subscription
|
|
@@ -1970,18 +2294,19 @@ export class AgentSession {
|
|
|
1970
2294
|
this.abortCompaction();
|
|
1971
2295
|
this.abortBranchSummary();
|
|
1972
2296
|
this.abortBash();
|
|
2297
|
+
disposePersistentShellSession(this._shellSessionKey);
|
|
1973
2298
|
this._cancelPrefixWarm();
|
|
1974
2299
|
this.agent.abort();
|
|
1975
|
-
//
|
|
2300
|
+
// Stop any deployment-registered gateway channels / schedulers.
|
|
1976
2301
|
void this._gatewayRegistry.stop().catch(() => { });
|
|
1977
|
-
//
|
|
2302
|
+
// Abort any in-flight background reflection so it cannot keep spending tokens or
|
|
1978
2303
|
// write memory/skills against this now-disposed session.
|
|
1979
2304
|
this._disposed = true;
|
|
1980
2305
|
this._reflectionAbort.abort();
|
|
1981
2306
|
// Abort any in-flight research pass or delegated worker for the same reason: a disposed
|
|
1982
2307
|
// session must not keep spending tokens or persist evidence against dead state.
|
|
1983
2308
|
this._backgroundLanes.abortInFlightLanes();
|
|
1984
|
-
//
|
|
2309
|
+
// Clear the hooks this session installed on the shared agent so their closures stop
|
|
1985
2310
|
// pinning this (deactivated) session — and all its history/maps — in memory if the agent
|
|
1986
2311
|
// instance outlives the session.
|
|
1987
2312
|
this.agent.afterToolCall = undefined;
|
|
@@ -1994,7 +2319,7 @@ export class AgentSession {
|
|
|
1994
2319
|
this._disconnectFromAgent();
|
|
1995
2320
|
this._eventListeners = [];
|
|
1996
2321
|
// Best-effort memory cleanup (release locks/handles). Write-side onSessionEnd is wired on a
|
|
1997
|
-
// true session-end hook
|
|
2322
|
+
// true session-end hook; file-store shutdown is a no-op.
|
|
1998
2323
|
void this._memory
|
|
1999
2324
|
.getMemoryManager()
|
|
2000
2325
|
.shutdownAll()
|
|
@@ -2049,7 +2374,7 @@ export class AgentSession {
|
|
|
2049
2374
|
getActiveToolNames() {
|
|
2050
2375
|
return this.agent.state.tools.map((t) => t.name);
|
|
2051
2376
|
}
|
|
2052
|
-
/**
|
|
2377
|
+
/** Build a foreground {@link CapabilityEnvelope} from the live session state (active tools, cwd, cost ceiling). */
|
|
2053
2378
|
_buildForegroundEnvelopeFromState() {
|
|
2054
2379
|
return buildForegroundEnvelope({
|
|
2055
2380
|
turnIndex: this._turnIndex,
|
|
@@ -2059,7 +2384,7 @@ export class AgentSession {
|
|
|
2059
2384
|
});
|
|
2060
2385
|
}
|
|
2061
2386
|
/**
|
|
2062
|
-
*
|
|
2387
|
+
* (Re)build the foreground envelope for the current turn. Visibility only -- the foreground
|
|
2063
2388
|
* envelope is NOT enforced this round. Best-effort: never throws into the turn.
|
|
2064
2389
|
*/
|
|
2065
2390
|
_refreshForegroundEnvelope() {
|
|
@@ -2070,7 +2395,7 @@ export class AgentSession {
|
|
|
2070
2395
|
// Visibility only: a failure to build the envelope must never disturb the turn.
|
|
2071
2396
|
}
|
|
2072
2397
|
}
|
|
2073
|
-
/**
|
|
2398
|
+
/** The auto-constructed foreground envelope for the current/most-recent turn (visibility only). */
|
|
2074
2399
|
getForegroundEnvelope() {
|
|
2075
2400
|
return this._currentForegroundEnvelope;
|
|
2076
2401
|
}
|
|
@@ -2199,7 +2524,7 @@ export class AgentSession {
|
|
|
2199
2524
|
}
|
|
2200
2525
|
/**
|
|
2201
2526
|
* Build a system prompt for a specific tool surface WITHOUT touching the session's base prompt
|
|
2202
|
-
* state (
|
|
2527
|
+
* state (used by the router's model swap; see {@link SystemPromptBuilder.buildSystemPromptForToolNames}).
|
|
2203
2528
|
*/
|
|
2204
2529
|
_buildSystemPromptForToolNames(toolNames) {
|
|
2205
2530
|
return this._systemPromptBuilder.buildSystemPromptForToolNames(toolNames);
|
|
@@ -2236,6 +2561,12 @@ export class AgentSession {
|
|
|
2236
2561
|
getTransformersRuntime(modelId, baseUrl) {
|
|
2237
2562
|
return this._localRuntimeController.getTransformersRuntime(modelId, baseUrl);
|
|
2238
2563
|
}
|
|
2564
|
+
/** Shared {@link PrismLlamaCppRuntime} for pi's own managed prism install — see
|
|
2565
|
+
* {@link LocalRuntimeController.getPrismLlamaCppRuntime}. Delegates so `/models` and the
|
|
2566
|
+
* readiness gate share the SAME cached instance, same contract as getLocalRuntime above. */
|
|
2567
|
+
getPrismLlamaCppRuntime() {
|
|
2568
|
+
return this._localRuntimeController.getPrismLlamaCppRuntime();
|
|
2569
|
+
}
|
|
2239
2570
|
/** models.json registers a local model's baseUrl as `<server>/v1` (OpenAI-compat); the runtime's
|
|
2240
2571
|
* own health/boot endpoints are on the Ollama-native server root. Delegates to
|
|
2241
2572
|
* {@link LocalRuntimeController}; kept here for `_warnIfManualModelChoiceIsRisky`'s own use. */
|
|
@@ -2250,6 +2581,27 @@ export class AgentSession {
|
|
|
2250
2581
|
async _ensureRouteModelReady(resolved) {
|
|
2251
2582
|
return this._localRuntimeController.ensureRouteModelReady(resolved);
|
|
2252
2583
|
}
|
|
2584
|
+
/**
|
|
2585
|
+
* Every local model the CURRENT (post-reload) configuration could still route a turn to —
|
|
2586
|
+
* the foreground model plus any router tier (cheap/medium/expensive) that still resolves to a
|
|
2587
|
+
* real, authed, non-exhausted model. Fed to {@link LocalRuntimeController.reconcile} via the
|
|
2588
|
+
* `reconcileLocalRuntimes` hook above, ONLY after a reload generation has fully committed, so a
|
|
2589
|
+
* local model dropped from the live configuration has its pi-spawned runtime stopped instead of
|
|
2590
|
+
* leaking a child process, while one still referenced here is left untouched. Read-only — never
|
|
2591
|
+
* used for routing itself.
|
|
2592
|
+
*/
|
|
2593
|
+
_collectEligibleLocalModelsForReconcile() {
|
|
2594
|
+
const models = [];
|
|
2595
|
+
const foregroundModel = this.agent.state.model;
|
|
2596
|
+
if (foregroundModel)
|
|
2597
|
+
models.push(foregroundModel);
|
|
2598
|
+
for (const tier of ["cheap", "medium", "expensive"]) {
|
|
2599
|
+
const resolved = this._modelRouter.resolveConfiguredTierModel(tier);
|
|
2600
|
+
if (resolved)
|
|
2601
|
+
models.push(resolved);
|
|
2602
|
+
}
|
|
2603
|
+
return models;
|
|
2604
|
+
}
|
|
2253
2605
|
getModelRouterStatus(formatLabel) {
|
|
2254
2606
|
return this._modelRouter.getStatus(formatLabel);
|
|
2255
2607
|
}
|
|
@@ -2310,6 +2662,10 @@ export class AgentSession {
|
|
|
2310
2662
|
return this._promptUnserialized(text, options);
|
|
2311
2663
|
}
|
|
2312
2664
|
async _promptUnserialized(text, options) {
|
|
2665
|
+
// Start of a new foreground prompt cycle -- rebaseline the cost guard's background-spend
|
|
2666
|
+
// window so a PRIOR turn's background/spawned spend doesn't keep this turn's guard permanently
|
|
2667
|
+
// tripped. Every round trip within this same turn (tool-call iterations) shares this baseline.
|
|
2668
|
+
this._costGuardTurnBaselineUsd = this.getSpawnedUsage().cost;
|
|
2313
2669
|
this._applyToolRepairLayerSettings();
|
|
2314
2670
|
this._cancelPrefixWarm();
|
|
2315
2671
|
const expandPromptTemplates = options?.expandPromptTemplates ?? true;
|
|
@@ -2322,7 +2678,7 @@ export class AgentSession {
|
|
|
2322
2678
|
// selected/authenticated — can un-register it from _earlyDisplayedUserMessages instead of
|
|
2323
2679
|
// leaking the reference forever.
|
|
2324
2680
|
let userMessage;
|
|
2325
|
-
//
|
|
2681
|
+
// Effectiveness feedback: remember the recall page + the query so we can score, after the
|
|
2326
2682
|
// response, whether the agent actually used the recalled context.
|
|
2327
2683
|
let injectedRecall = "";
|
|
2328
2684
|
let recallQuery = "";
|
|
@@ -2445,7 +2801,7 @@ export class AgentSession {
|
|
|
2445
2801
|
}
|
|
2446
2802
|
// Build messages array (recall page, then custom message if any, then user message)
|
|
2447
2803
|
messages = [];
|
|
2448
|
-
//
|
|
2804
|
+
// Cross-session similarity recall. For a substantive turn, ask the memory providers to
|
|
2449
2805
|
// prefetch a relevant <memory_context> page from past sessions and prepend it as data ahead of
|
|
2450
2806
|
// the user message. Best-effort and gated: trivial turns are skipped, and providers return ""
|
|
2451
2807
|
// (no page) when nothing is relevant — so it stays net-negative and the GC packs stale pages.
|
|
@@ -2457,8 +2813,8 @@ export class AgentSession {
|
|
|
2457
2813
|
recallQuery = expandedText;
|
|
2458
2814
|
// Inject as a GC-managed custom context message (role "custom", customType
|
|
2459
2815
|
// "memory_context"), NOT a persisted user message: the semantic-memory context-GC packs
|
|
2460
|
-
// stale recall pages so they don't accumulate forever
|
|
2461
|
-
// only re-reads user/assistant text so recalled snippets can't recirculate
|
|
2816
|
+
// stale recall pages so they don't accumulate forever, and the transcript index
|
|
2817
|
+
// only re-reads user/assistant text so recalled snippets can't recirculate.
|
|
2462
2818
|
messages.push(createCustomMessage("memory_context", recall, false, undefined, new Date().toISOString()));
|
|
2463
2819
|
}
|
|
2464
2820
|
}
|
|
@@ -2528,7 +2884,7 @@ export class AgentSession {
|
|
|
2528
2884
|
this._textProtocolValidationOutcomeThisTurn = undefined;
|
|
2529
2885
|
await this._modelRouter.runRoutedTurn(messages, routedTurnModel, routedTurnRouteDecision);
|
|
2530
2886
|
this._recordTextToolProtocolParseOutcomeFromLastAssistant();
|
|
2531
|
-
//
|
|
2887
|
+
// Score whether the agent actually used the recalled context, so the recall gate can adapt.
|
|
2532
2888
|
if (injectedRecall) {
|
|
2533
2889
|
const response = this._findLastAssistantMessage();
|
|
2534
2890
|
const responseText = response
|
|
@@ -2968,8 +3324,12 @@ export class AgentSession {
|
|
|
2968
3324
|
getBaseKeepRecentTokens: () => settings.keepRecentTokens,
|
|
2969
3325
|
resolveModelAndAuth: async (modelTier) => {
|
|
2970
3326
|
const model = modelTier === "cheap" ? selectedCompactionModel : sessionModel;
|
|
2971
|
-
|
|
2972
|
-
|
|
3327
|
+
// Return the resolution result AS-IS: it may have fallen back to a different model
|
|
3328
|
+
// (e.g. session model, when the tier's model failed auth or the readiness gate),
|
|
3329
|
+
// and `failure` must reach the retry loop's auth-failed escalation rather than be
|
|
3330
|
+
// dropped — dropping it would pair the wrong model with the fallback's credentials
|
|
3331
|
+
// and silently skip the loop's visible failure/escalation handling.
|
|
3332
|
+
return this._resolveCompactionModelAndAuth(model, sessionModel);
|
|
2973
3333
|
},
|
|
2974
3334
|
summarizeAndVerify: async (params, model, apiKey, headers, branch) => {
|
|
2975
3335
|
const preparation = prepareCompaction(branch, {
|
|
@@ -3548,6 +3908,9 @@ export class AgentSession {
|
|
|
3548
3908
|
reportSpawnedUsage: (usage, opts) => {
|
|
3549
3909
|
this.addSpawnedUsage(usage, opts);
|
|
3550
3910
|
},
|
|
3911
|
+
reportManagedLane: (event) => {
|
|
3912
|
+
this._backgroundLanes.recordManagedLane(event);
|
|
3913
|
+
},
|
|
3551
3914
|
}, {
|
|
3552
3915
|
getModel: () => this.model,
|
|
3553
3916
|
isIdle: () => !this.isStreaming,
|
|
@@ -3608,15 +3971,15 @@ export class AgentSession {
|
|
|
3608
3971
|
registerContextMemoryProvider(provider) {
|
|
3609
3972
|
this._memory.registerContextMemoryProvider(provider);
|
|
3610
3973
|
}
|
|
3611
|
-
/**
|
|
3974
|
+
/** The gateway/scheduler registry. A deployment runner registers providers and drives start/stop. */
|
|
3612
3975
|
get gateways() {
|
|
3613
3976
|
return this._gatewayRegistry;
|
|
3614
3977
|
}
|
|
3615
|
-
/**
|
|
3978
|
+
/** Register a deployment-supplied transport channel (gateway). */
|
|
3616
3979
|
registerChannelProvider(provider) {
|
|
3617
3980
|
this._gatewayRegistry.registerChannel(provider);
|
|
3618
3981
|
}
|
|
3619
|
-
/**
|
|
3982
|
+
/** Register a deployment-supplied job scheduler (cron). */
|
|
3620
3983
|
registerJobScheduler(provider) {
|
|
3621
3984
|
this._gatewayRegistry.registerScheduler(provider);
|
|
3622
3985
|
}
|
|
@@ -3775,7 +4138,32 @@ export class AgentSession {
|
|
|
3775
4138
|
* Retrieve the latest valid goal state snapshot from the session log.
|
|
3776
4139
|
*/
|
|
3777
4140
|
getGoalStateSnapshot() {
|
|
3778
|
-
return getLatestGoalStateSnapshot(this.sessionManager
|
|
4141
|
+
return getLatestGoalStateSnapshot(this.sessionManager);
|
|
4142
|
+
}
|
|
4143
|
+
/**
|
|
4144
|
+
* Persist one submitted continuation pass's turn/wall-clock/spend contribution onto the active
|
|
4145
|
+
* goal's durable cumulative budget (see `GoalState.continuationTurnsUsed` et al.). This is the
|
|
4146
|
+
* "persistence dep" `GoalLoopController` calls once per pass actually submitted — it, not the
|
|
4147
|
+
* loop controller, is where USD gets attributed: it reads the session's OWN cumulative model
|
|
4148
|
+
* spend (`getCostSummary().ownCost` — deliberately excludes worker/subagent spend, which is
|
|
4149
|
+
* tracked and budgeted separately) and threads that single absolute reading into a
|
|
4150
|
+
* `record_continuation_budget` event; the pure reducer in `goal-state.ts` derives the delta.
|
|
4151
|
+
* A no-op when no goal state exists (defensive — in practice this is only ever called right
|
|
4152
|
+
* after a pass the loop already confirmed was submitted against an active goal).
|
|
4153
|
+
*/
|
|
4154
|
+
recordGoalContinuationPass(pass) {
|
|
4155
|
+
const state = this.getGoalStateSnapshot();
|
|
4156
|
+
if (!state)
|
|
4157
|
+
return;
|
|
4158
|
+
const sessionCostUsd = this.getCostSummary().ownCost;
|
|
4159
|
+
const updated = applyGoalEvent(state, {
|
|
4160
|
+
type: "record_continuation_budget",
|
|
4161
|
+
turns: pass.turns,
|
|
4162
|
+
wallClockMs: pass.wallClockMs,
|
|
4163
|
+
sessionCostUsd,
|
|
4164
|
+
now: new Date().toISOString(),
|
|
4165
|
+
});
|
|
4166
|
+
this.saveGoalStateSnapshot(updated);
|
|
3779
4167
|
}
|
|
3780
4168
|
/** Save native task-step state to the active session log. */
|
|
3781
4169
|
saveTaskStepsStateSnapshot(state) {
|
|
@@ -3783,7 +4171,7 @@ export class AgentSession {
|
|
|
3783
4171
|
}
|
|
3784
4172
|
/** Retrieve the latest valid native task-step state from the active session log. */
|
|
3785
4173
|
getTaskStepsStateSnapshot() {
|
|
3786
|
-
return getLatestTaskStepsStateSnapshot(this.sessionManager
|
|
4174
|
+
return getLatestTaskStepsStateSnapshot(this.sessionManager);
|
|
3787
4175
|
}
|
|
3788
4176
|
/**
|
|
3789
4177
|
* Save a snapshot of the evidence bundle to the session log.
|
|
@@ -3806,7 +4194,7 @@ export class AgentSession {
|
|
|
3806
4194
|
getLaneRecords() {
|
|
3807
4195
|
return this._backgroundLanes.getLaneRecords();
|
|
3808
4196
|
}
|
|
3809
|
-
//
|
|
4197
|
+
// Autonomy telemetry + gate-outcome history live in AutonomyTelemetry (see
|
|
3810
4198
|
// autonomy-telemetry.ts). These stubs keep the god file's internal call surface stable while the
|
|
3811
4199
|
// sink logic and the owned gate-outcome fields live there.
|
|
3812
4200
|
_emitAutonomyTelemetry(event) {
|
|
@@ -3815,7 +4203,7 @@ export class AgentSession {
|
|
|
3815
4203
|
_recordGateOutcome(outcome) {
|
|
3816
4204
|
this._autonomyTelemetry.recordGateOutcome(outcome);
|
|
3817
4205
|
}
|
|
3818
|
-
/**
|
|
4206
|
+
/** Copies of the bounded gate-outcome history, oldest first, latest last. */
|
|
3819
4207
|
getGateOutcomeHistory() {
|
|
3820
4208
|
return this._autonomyTelemetry.getGateOutcomeHistory();
|
|
3821
4209
|
}
|
|
@@ -3831,10 +4219,18 @@ export class AgentSession {
|
|
|
3831
4219
|
getLearningDecisionSnapshots() {
|
|
3832
4220
|
return getLearningDecisionSnapshots(this.sessionManager.getEntries());
|
|
3833
4221
|
}
|
|
4222
|
+
/**
|
|
4223
|
+
* The single injection point that makes the goal-continuation snapshot lane-aware:
|
|
4224
|
+
* `laneRecords` feeds BOTH `evaluateGoalContinuation`'s "waiting" branch (a worker dispatched
|
|
4225
|
+
* against an open requirement) and the per-goal worker-spend overlay — read fresh here so BOTH the
|
|
4226
|
+
* goal loop (`GoalLoopController`) and the idle scheduler (`BackgroundLaneController`) see the
|
|
4227
|
+
* same live lane state, since both reach this same method.
|
|
4228
|
+
*/
|
|
3834
4229
|
getGoalRuntimeSnapshot(settings) {
|
|
3835
4230
|
return buildGoalRuntimeSnapshot({
|
|
3836
|
-
|
|
4231
|
+
sessionManager: this.sessionManager,
|
|
3837
4232
|
settings,
|
|
4233
|
+
laneRecords: this._backgroundLanes.getLaneRecords(),
|
|
3838
4234
|
});
|
|
3839
4235
|
}
|
|
3840
4236
|
/**
|
|
@@ -3847,6 +4243,25 @@ export class AgentSession {
|
|
|
3847
4243
|
mode: this.settingsManager.getModelCapabilitySettings().mode,
|
|
3848
4244
|
});
|
|
3849
4245
|
}
|
|
4246
|
+
/**
|
|
4247
|
+
* Whether the CURRENT session model may drive a worktree-sync lane worker (see
|
|
4248
|
+
* `evaluateLaneWorkerRefusal` in model-capability.ts): full capability class, a DECLARED
|
|
4249
|
+
* (registry) context window, an ADVERTISED native tool-call path (`Model.textToolCallProtocol`
|
|
4250
|
+
* unset/false -- `true` means phone-only), and no graded `/toolprobe` demotion to
|
|
4251
|
+
* "text-protocol"/"none" on record. An unprobed model (no verdict on record yet) is eligible on
|
|
4252
|
+
* its advertised support alone. `undefined` means eligible.
|
|
4253
|
+
*/
|
|
4254
|
+
getLaneWorkerRefusal() {
|
|
4255
|
+
const profile = this.getModelCapabilityProfile();
|
|
4256
|
+
const model = this.model;
|
|
4257
|
+
const verdict = model ? this._toolProbeVerdict(model) : undefined;
|
|
4258
|
+
return evaluateLaneWorkerRefusal({
|
|
4259
|
+
capabilityClass: profile.class,
|
|
4260
|
+
contextWindow: profile.contextWindow,
|
|
4261
|
+
toolCallingAdvertised: model?.textToolCallProtocol !== true,
|
|
4262
|
+
toolCallingDemoted: verdict === "text-protocol" || verdict === "none",
|
|
4263
|
+
});
|
|
4264
|
+
}
|
|
3850
4265
|
/**
|
|
3851
4266
|
* Run one bounded, read-only research pass and persist its results. Delegates to
|
|
3852
4267
|
* {@link BackgroundLaneController}; see there for the full gating/budget/dedupe contract.
|
|
@@ -3875,8 +4290,15 @@ export class AgentSession {
|
|
|
3875
4290
|
async continueGoalOnce(options) {
|
|
3876
4291
|
return this._goalContinuation.continueGoalOnce(options);
|
|
3877
4292
|
}
|
|
4293
|
+
/**
|
|
4294
|
+
* Public entry point for BOTH idle autosteer and manual (`/goal start`, `/goal-continue`)
|
|
4295
|
+
* continuation. Delegates to {@link BackgroundLaneController.continueGoalLoopExclusive}, the
|
|
4296
|
+
* single-flight guard that prevents two goal loops from racing to submit prompts through the
|
|
4297
|
+
* same session (which throws "Agent is already processing" from the second submission). Do not
|
|
4298
|
+
* call `this._goalContinuation.continueGoalLoop` directly from here — that bypasses the guard.
|
|
4299
|
+
*/
|
|
3878
4300
|
async continueGoalLoop(options) {
|
|
3879
|
-
return this.
|
|
4301
|
+
return this._backgroundLanes.continueGoalLoopExclusive(options);
|
|
3880
4302
|
}
|
|
3881
4303
|
/**
|
|
3882
4304
|
* Run a one-shot LLM completion fully ISOLATED from the main session — the load-bearing primitive
|
|
@@ -3886,7 +4308,7 @@ export class AgentSession {
|
|
|
3886
4308
|
return this._reflection.runIsolatedCompletion(opts);
|
|
3887
4309
|
}
|
|
3888
4310
|
/**
|
|
3889
|
-
* Native end-of-loop reflection pass
|
|
4311
|
+
* Native end-of-loop reflection pass. Delegates to {@link ReflectionController}; returns null
|
|
3890
4312
|
* when the demand gate skips or in a child session.
|
|
3891
4313
|
*/
|
|
3892
4314
|
async runReflectionPass(input) {
|