@code-yeongyu/senpi 2026.8.29 → 2026.8.30-3
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 +172 -0
- package/dist/core/agent-session.d.ts +47 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +406 -39
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +155 -37
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/compaction/compaction-execution.d.ts +14 -0
- package/dist/core/compaction/compaction-execution.d.ts.map +1 -0
- package/dist/core/compaction/compaction-execution.js +121 -0
- package/dist/core/compaction/compaction-execution.js.map +1 -0
- package/dist/core/compaction/compaction-settings.d.ts +17 -0
- package/dist/core/compaction/compaction-settings.d.ts.map +1 -0
- package/dist/core/compaction/compaction-settings.js +17 -0
- package/dist/core/compaction/compaction-settings.js.map +1 -0
- package/dist/core/compaction/compaction.d.ts +13 -26
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +7 -136
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/compaction/ideal-compaction-settings.d.ts +9 -0
- package/dist/core/compaction/ideal-compaction-settings.d.ts.map +1 -0
- package/dist/core/compaction/ideal-compaction-settings.js +7 -0
- package/dist/core/compaction/ideal-compaction-settings.js.map +1 -0
- package/dist/core/compaction-settings-access.d.ts +19 -0
- package/dist/core/compaction-settings-access.d.ts.map +1 -0
- package/dist/core/compaction-settings-access.js +10 -0
- package/dist/core/compaction-settings-access.js.map +1 -0
- package/dist/core/compaction-settings-resolver.d.ts +22 -0
- package/dist/core/compaction-settings-resolver.d.ts.map +1 -0
- package/dist/core/compaction-settings-resolver.js +46 -0
- package/dist/core/compaction-settings-resolver.js.map +1 -0
- package/dist/core/credential-accounts.d.ts.map +1 -1
- package/dist/core/credential-accounts.js +23 -9
- package/dist/core/credential-accounts.js.map +1 -1
- package/dist/core/credential-pool/env-slots.d.ts.map +1 -1
- package/dist/core/credential-pool/env-slots.js +2 -0
- package/dist/core/credential-pool/env-slots.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/context-pipeline.d.ts +18 -0
- package/dist/core/extensions/builtin/compaction/context-pipeline.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/context-pipeline.js +32 -0
- package/dist/core/extensions/builtin/compaction/context-pipeline.js.map +1 -0
- package/dist/core/extensions/builtin/compaction/deterministic-fallback.d.ts +8 -2
- package/dist/core/extensions/builtin/compaction/deterministic-fallback.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/deterministic-fallback.js +164 -48
- package/dist/core/extensions/builtin/compaction/deterministic-fallback.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/emergency-prune.d.ts +17 -0
- package/dist/core/extensions/builtin/compaction/emergency-prune.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/emergency-prune.js +64 -0
- package/dist/core/extensions/builtin/compaction/emergency-prune.js.map +1 -0
- package/dist/core/extensions/builtin/compaction/extension-wiring.d.ts +27 -0
- package/dist/core/extensions/builtin/compaction/extension-wiring.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/extension-wiring.js +84 -0
- package/dist/core/extensions/builtin/compaction/extension-wiring.js.map +1 -0
- package/dist/core/extensions/builtin/compaction/idle-retry.d.ts +1 -1
- package/dist/core/extensions/builtin/compaction/idle-retry.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/idle-retry.js +1 -1
- package/dist/core/extensions/builtin/compaction/idle-retry.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/idle.d.ts +1 -0
- package/dist/core/extensions/builtin/compaction/idle.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/idle.js +13 -2
- package/dist/core/extensions/builtin/compaction/idle.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/index.d.ts +1 -1
- package/dist/core/extensions/builtin/compaction/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/index.js +148 -150
- package/dist/core/extensions/builtin/compaction/index.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/log.d.ts +1 -1
- package/dist/core/extensions/builtin/compaction/log.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/log.js +2 -0
- package/dist/core/extensions/builtin/compaction/log.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/model-selection.d.ts +14 -0
- package/dist/core/extensions/builtin/compaction/model-selection.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/model-selection.js +37 -0
- package/dist/core/extensions/builtin/compaction/model-selection.js.map +1 -0
- package/dist/core/extensions/builtin/compaction/model-usability-budget.d.ts +30 -0
- package/dist/core/extensions/builtin/compaction/model-usability-budget.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/model-usability-budget.js +74 -0
- package/dist/core/extensions/builtin/compaction/model-usability-budget.js.map +1 -0
- package/dist/core/extensions/builtin/compaction/openai-remote-dependencies.d.ts +9 -0
- package/dist/core/extensions/builtin/compaction/openai-remote-dependencies.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/openai-remote-dependencies.js +2 -0
- package/dist/core/extensions/builtin/compaction/openai-remote-dependencies.js.map +1 -0
- package/dist/core/extensions/builtin/compaction/openai-remote.d.ts +3 -6
- package/dist/core/extensions/builtin/compaction/openai-remote.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/openai-remote.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/orchestration.d.ts +46 -0
- package/dist/core/extensions/builtin/compaction/orchestration.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/orchestration.js +103 -0
- package/dist/core/extensions/builtin/compaction/orchestration.js.map +1 -0
- package/dist/core/extensions/builtin/compaction/policy.d.ts +12 -2
- package/dist/core/extensions/builtin/compaction/policy.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/policy.js +52 -26
- package/dist/core/extensions/builtin/compaction/policy.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/retained-message-safety.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/retained-message-safety.js +31 -8
- package/dist/core/extensions/builtin/compaction/retained-message-safety.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/speculation-lead.d.ts +8 -0
- package/dist/core/extensions/builtin/compaction/speculation-lead.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/speculation-lead.js +17 -0
- package/dist/core/extensions/builtin/compaction/speculation-lead.js.map +1 -0
- package/dist/core/extensions/builtin/compaction/speculative-job.d.ts +22 -0
- package/dist/core/extensions/builtin/compaction/speculative-job.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/speculative-job.js +16 -0
- package/dist/core/extensions/builtin/compaction/speculative-job.js.map +1 -0
- package/dist/core/extensions/builtin/compaction/speculative-summary.d.ts +22 -0
- package/dist/core/extensions/builtin/compaction/speculative-summary.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/speculative-summary.js +131 -0
- package/dist/core/extensions/builtin/compaction/speculative-summary.js.map +1 -0
- package/dist/core/extensions/builtin/compaction/speculative.d.ts +8 -13
- package/dist/core/extensions/builtin/compaction/speculative.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/speculative.js +7 -196
- package/dist/core/extensions/builtin/compaction/speculative.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/token-budget-reminder.d.ts +24 -0
- package/dist/core/extensions/builtin/compaction/token-budget-reminder.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/token-budget-reminder.js +25 -0
- package/dist/core/extensions/builtin/compaction/token-budget-reminder.js.map +1 -0
- package/dist/core/extensions/builtin/compaction/tool-admission.d.ts +27 -0
- package/dist/core/extensions/builtin/compaction/tool-admission.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/tool-admission.js +56 -0
- package/dist/core/extensions/builtin/compaction/tool-admission.js.map +1 -0
- package/dist/core/extensions/builtin/cursor-cli-oauth/stream.d.ts.map +1 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/stream.js +8 -28
- package/dist/core/extensions/builtin/cursor-cli-oauth/stream.js.map +1 -1
- package/dist/core/extensions/builtin/permission-system/external-dir.d.ts.map +1 -1
- package/dist/core/extensions/builtin/permission-system/external-dir.js +15 -5
- package/dist/core/extensions/builtin/permission-system/external-dir.js.map +1 -1
- package/dist/core/extensions/builtin/permission-system/parsers.d.ts.map +1 -1
- package/dist/core/extensions/builtin/permission-system/parsers.js +16 -1
- package/dist/core/extensions/builtin/permission-system/parsers.js.map +1 -1
- package/dist/core/extensions/builtin/terminal/manager.d.ts +5 -0
- package/dist/core/extensions/builtin/terminal/manager.d.ts.map +1 -1
- package/dist/core/extensions/builtin/terminal/manager.js +31 -3
- package/dist/core/extensions/builtin/terminal/manager.js.map +1 -1
- package/dist/core/extensions/builtin/terminal/monitor-permission.d.ts +8 -0
- package/dist/core/extensions/builtin/terminal/monitor-permission.d.ts.map +1 -0
- package/dist/core/extensions/builtin/terminal/monitor-permission.js +16 -0
- package/dist/core/extensions/builtin/terminal/monitor-permission.js.map +1 -0
- package/dist/core/extensions/builtin/terminal/monitor-registry.d.ts +13 -0
- package/dist/core/extensions/builtin/terminal/monitor-registry.d.ts.map +1 -1
- package/dist/core/extensions/builtin/terminal/monitor-registry.js +403 -3
- package/dist/core/extensions/builtin/terminal/monitor-registry.js.map +1 -1
- package/dist/core/extensions/builtin/terminal/runtime-session.d.ts +11 -0
- package/dist/core/extensions/builtin/terminal/runtime-session.d.ts.map +1 -1
- package/dist/core/extensions/builtin/terminal/runtime-session.js +18 -2
- package/dist/core/extensions/builtin/terminal/runtime-session.js.map +1 -1
- package/dist/core/extensions/builtin/terminal/session-bundle.d.ts.map +1 -1
- package/dist/core/extensions/builtin/terminal/session-bundle.js +1 -0
- package/dist/core/extensions/builtin/terminal/session-bundle.js.map +1 -1
- package/dist/core/extensions/builtin/terminal/tools/kill-bash.d.ts.map +1 -1
- package/dist/core/extensions/builtin/terminal/tools/kill-bash.js +5 -2
- package/dist/core/extensions/builtin/terminal/tools/kill-bash.js.map +1 -1
- package/dist/core/extensions/builtin/terminal/tools/monitor.d.ts +4 -0
- package/dist/core/extensions/builtin/terminal/tools/monitor.d.ts.map +1 -1
- package/dist/core/extensions/builtin/terminal/tools/monitor.js +40 -2
- package/dist/core/extensions/builtin/terminal/tools/monitor.js.map +1 -1
- package/dist/core/model-resolver.js +2 -2
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +5 -0
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +10 -1
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +15 -85
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +15 -17
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/settings-public-types.d.ts +11 -0
- package/dist/core/settings-public-types.d.ts.map +1 -0
- package/dist/core/settings-public-types.js +2 -0
- package/dist/core/settings-public-types.js.map +1 -0
- package/dist/core/settings-shapes.d.ts +36 -0
- package/dist/core/settings-shapes.d.ts.map +1 -0
- package/dist/core/settings-shapes.js +2 -0
- package/dist/core/settings-shapes.js.map +1 -0
- package/dist/core/shared-host-policy.d.ts +6 -0
- package/dist/core/shared-host-policy.d.ts.map +1 -0
- package/dist/core/shared-host-policy.js +7 -0
- package/dist/core/shared-host-policy.js.map +1 -0
- package/dist/core/terminal-settings.d.ts +22 -0
- package/dist/core/terminal-settings.d.ts.map +1 -0
- package/dist/core/terminal-settings.js +2 -0
- package/dist/core/terminal-settings.js.map +1 -0
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +97 -15
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/index.d.ts +1 -0
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +8 -0
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/output-accumulator.d.ts +1 -1
- package/dist/core/tools/output-accumulator.d.ts.map +1 -1
- package/dist/core/tools/output-accumulator.js +76 -34
- package/dist/core/tools/output-accumulator.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +17 -5
- package/dist/main.js.map +1 -1
- package/dist/modes/index.d.ts +1 -1
- package/dist/modes/index.d.ts.map +1 -1
- package/dist/modes/index.js +1 -1
- package/dist/modes/index.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts +7 -0
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +34 -8
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/grok/chrome.d.ts +2 -0
- package/dist/modes/interactive/grok/chrome.d.ts.map +1 -1
- package/dist/modes/interactive/grok/chrome.js.map +1 -1
- package/dist/modes/interactive/interactive-host-runtime.d.ts +132 -1
- package/dist/modes/interactive/interactive-host-runtime.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-host-runtime.js +633 -117
- package/dist/modes/interactive/interactive-host-runtime.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +7 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +114 -2
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/rpc/connection-handler.d.ts +8 -1
- package/dist/modes/rpc/connection-handler.d.ts.map +1 -1
- package/dist/modes/rpc/connection-handler.js +158 -49
- package/dist/modes/rpc/connection-handler.js.map +1 -1
- package/dist/modes/rpc/host-ensure.d.ts +19 -0
- package/dist/modes/rpc/host-ensure.d.ts.map +1 -1
- package/dist/modes/rpc/host-ensure.js +79 -15
- package/dist/modes/rpc/host-ensure.js.map +1 -1
- package/dist/modes/rpc/host-lifecycle.d.ts +29 -0
- package/dist/modes/rpc/host-lifecycle.d.ts.map +1 -1
- package/dist/modes/rpc/host-lifecycle.js +96 -25
- package/dist/modes/rpc/host-lifecycle.js.map +1 -1
- package/dist/modes/rpc/host-watchdog.d.ts +2 -0
- package/dist/modes/rpc/host-watchdog.d.ts.map +1 -1
- package/dist/modes/rpc/host-watchdog.js +23 -12
- package/dist/modes/rpc/host-watchdog.js.map +1 -1
- package/dist/modes/rpc/multi-session-host.js +6 -4
- package/dist/modes/rpc/multi-session-host.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +20 -4
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +76 -17
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-input-validation.d.ts +1 -0
- package/dist/modes/rpc/rpc-input-validation.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-input-validation.js +66 -0
- package/dist/modes/rpc/rpc-input-validation.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +86 -1
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/modes/rpc/session-binding.d.ts +1 -0
- package/dist/modes/rpc/session-binding.d.ts.map +1 -1
- package/dist/modes/rpc/session-binding.js +21 -1
- package/dist/modes/rpc/session-binding.js.map +1 -1
- package/dist/modes/rpc/session-command-router.d.ts.map +1 -1
- package/dist/modes/rpc/session-command-router.js +1 -0
- package/dist/modes/rpc/session-command-router.js.map +1 -1
- package/dist/modes/rpc/session-event-writer.d.ts +2 -0
- package/dist/modes/rpc/session-event-writer.d.ts.map +1 -1
- package/dist/modes/rpc/session-event-writer.js +54 -7
- package/dist/modes/rpc/session-event-writer.js.map +1 -1
- package/dist/modes/rpc/session-extension-ui-requests.d.ts +1 -0
- package/dist/modes/rpc/session-extension-ui-requests.d.ts.map +1 -1
- package/dist/modes/rpc/session-extension-ui-requests.js +5 -0
- package/dist/modes/rpc/session-extension-ui-requests.js.map +1 -1
- package/dist/modes/rpc/session-registry.d.ts +10 -2
- package/dist/modes/rpc/session-registry.d.ts.map +1 -1
- package/dist/modes/rpc/session-registry.js +58 -4
- package/dist/modes/rpc/session-registry.js.map +1 -1
- package/dist/modes/rpc/socket-event-fanout.d.ts +22 -0
- package/dist/modes/rpc/socket-event-fanout.d.ts.map +1 -0
- package/dist/modes/rpc/socket-event-fanout.js +84 -0
- package/dist/modes/rpc/socket-event-fanout.js.map +1 -0
- package/docs/rpc.md +22 -2
- package/docs/settings.md +34 -0
- package/docs/windows.md +2 -0
- package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +62 -0
- package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/worker-indirect-eval.js +139 -90
- package/node_modules/@code-yeongyu/senpi-codemode/src/prompt/eval-prompt.ts +4 -4
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/env/nodejs.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/env/nodejs.js +40 -20
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/env/nodejs.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.d.ts +3 -3
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/shell-output.d.ts +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/shell-output.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/shell-output.js +28 -9
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/shell-output.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
- package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js +67 -38
- package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent/measure.d.ts +20 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent/measure.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent/measure.js +443 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent/measure.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.d.ts +2 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.js +2 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/index.d.ts +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/index.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/index.js +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/index.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/cloudflare-ai-gateway.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/cloudflare-workers-ai.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/fireworks.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode-go.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/together.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/zai-coding-cn.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/zai.json +1 -1
- package/node_modules/@earendil-works/pi-ai/package.json +2 -2
- package/node_modules/@earendil-works/pi-pty/dist/screen-operations.d.ts +42 -0
- package/node_modules/@earendil-works/pi-pty/dist/screen-operations.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-pty/dist/screen-operations.js +34 -0
- package/node_modules/@earendil-works/pi-pty/dist/screen-operations.js.map +1 -0
- package/node_modules/@earendil-works/pi-pty/dist/screen-text.d.ts +8 -0
- package/node_modules/@earendil-works/pi-pty/dist/screen-text.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-pty/dist/screen-text.js +51 -0
- package/node_modules/@earendil-works/pi-pty/dist/screen-text.js.map +1 -0
- package/node_modules/@earendil-works/pi-pty/dist/screen.d.ts +45 -0
- package/node_modules/@earendil-works/pi-pty/dist/screen.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-pty/dist/screen.js +178 -55
- package/node_modules/@earendil-works/pi-pty/dist/screen.js.map +1 -1
- package/node_modules/@earendil-works/pi-pty/package.json +1 -1
- package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.d.ts +7 -0
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.js +5 -0
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/mux.d.ts +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/mux.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/mux.js +2 -2
- package/node_modules/@earendil-works/pi-tui/dist/mux.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/terminal.d.ts +1 -0
- package/node_modules/@earendil-works/pi-tui/dist/terminal.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/terminal.js +19 -0
- package/node_modules/@earendil-works/pi-tui/dist/terminal.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/package.json +1 -1
- package/package.json +7 -7
|
@@ -14,10 +14,11 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import { randomUUID } from "node:crypto";
|
|
16
16
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
17
|
+
import { rm } from "node:fs/promises";
|
|
17
18
|
import { basename, dirname } from "node:path";
|
|
18
19
|
import { isDeepStrictEqual } from "node:util";
|
|
19
20
|
import { ProviderRetryWatchdogAbortError, prepareAgentToolCall } from "@earendil-works/pi-agent-core";
|
|
20
|
-
import { contentText, SERVER_FALLBACK_ABORTED_DIAGNOSTIC } from "@earendil-works/pi-ai";
|
|
21
|
+
import { contentText, measureCursorHistorySerializedBytes, SERVER_FALLBACK_ABORTED_DIAGNOSTIC, } from "@earendil-works/pi-ai";
|
|
21
22
|
import { cleanupSessionResources, cursorOverflowCompactionSettings, isClassifierRefusal, isContextOverflow, isCursorPayloadResourceExhausted, isCursorQuotaResourceExhausted, isCursorZeroTokenResourceExhausted, isProviderStreamStallError, isProviderTimeoutError, isRecoverableLength, isRetryableAssistantError, modelsAreEqual, resetApiProviders, shouldRetryOverflowWithoutCompact, streamSimple, } from "@earendil-works/pi-ai/compat";
|
|
22
23
|
import { extract429RetryAfterMs, parseRetryAfterMsMarker } from "@earendil-works/pi-ai/utils/retry-hint";
|
|
23
24
|
import { retryBackoffDelayMs } from "@earendil-works/pi-ai/utils/retry-profile/backoff";
|
|
@@ -40,6 +41,8 @@ import { buildDynamicSystemPrompt } from "./dynamic-prompt/index.js";
|
|
|
40
41
|
import { areExperimentalFeaturesEnabled } from "./experimental.js";
|
|
41
42
|
import { exportSessionToHtml } from "./export-html/index.js";
|
|
42
43
|
import { createToolHtmlRenderer } from "./export-html/tool-renderer.js";
|
|
44
|
+
import { ModelUsabilityBudgetError, projectModelUsabilityBudget, } from "./extensions/builtin/compaction/model-usability-budget.js";
|
|
45
|
+
import { resolveReserveTokens } from "./extensions/builtin/compaction/policy.js";
|
|
43
46
|
import { CODEX_RESPONSES_API } from "./extensions/builtin/service-tier.js";
|
|
44
47
|
import { deriveExtensionRegistrationId } from "./extensions/builtin/tool-search/engine/marker.js";
|
|
45
48
|
import { getToolSearchService } from "./extensions/builtin/tool-search/service.js";
|
|
@@ -47,7 +50,7 @@ import { ExecuteToolError, ExtensionRunner, wrapRegisteredTools, } from "./exten
|
|
|
47
50
|
import { emitSessionShutdownEvent } from "./extensions/runner.js";
|
|
48
51
|
import { normalizeToolExposure, RUNTIME_EXTENSION_PATH } from "./extensions/types.js";
|
|
49
52
|
import { shouldWarnHighReasoning } from "./high-reasoning-warning.js";
|
|
50
|
-
import { filterContextExcludedMessages } from "./messages.js";
|
|
53
|
+
import { convertToLlm, filterContextExcludedMessages, } from "./messages.js";
|
|
51
54
|
import { ModelRegistry } from "./model-registry.js";
|
|
52
55
|
import { getModelNarrowingPatterns, resolveModelScope } from "./model-resolver.js";
|
|
53
56
|
import { PROMPT_CACHE_SAFE_WAIT_ENV, resolvePromptCacheSafeWaitSeconds } from "./prompt-cache-budget.js";
|
|
@@ -70,9 +73,21 @@ import { getSupportedThinkingLevels, supportsMax, supportsXhigh } from "./thinki
|
|
|
70
73
|
import { resetTimings, time } from "./timings.js";
|
|
71
74
|
import { createLocalBashOperations } from "./tools/bash.js";
|
|
72
75
|
import { composeFilesystemPolicies } from "./tools/filesystem-policy.js";
|
|
73
|
-
import { createAllToolDefinitions } from "./tools/index.js";
|
|
76
|
+
import { createAllToolDefinitions, temporarilyDisabledToolNames } from "./tools/index.js";
|
|
74
77
|
import { createToolDefinitionFromAgentTool } from "./tools/tool-definition-wrapper.js";
|
|
75
78
|
import { addUsageToTotals, createUsageTotals } from "./usage-totals.js";
|
|
79
|
+
/** Built-in shell tools routed exclusively through eval when experimental.bashEvalOnly is enabled. */
|
|
80
|
+
const EVAL_ONLY_SHELL_TOOL_NAMES = ["bash", "powershell"];
|
|
81
|
+
/** Workflow tool routed exclusively through eval when experimental.workflowEvalOnly is enabled. */
|
|
82
|
+
const EVAL_ONLY_WORKFLOW_TOOL_NAMES = ["workflow"];
|
|
83
|
+
/** Sample eval-cell call for an eval-only tool, using the argument name that tool actually takes. */
|
|
84
|
+
function evalHelperCall(name) {
|
|
85
|
+
if (EVAL_ONLY_SHELL_TOOL_NAMES.includes(name))
|
|
86
|
+
return `tool.${name}({ command: "..." })`;
|
|
87
|
+
if (EVAL_ONLY_WORKFLOW_TOOL_NAMES.includes(name))
|
|
88
|
+
return `tool.${name}({ action: "..." })`;
|
|
89
|
+
return `tool.${name}({ ... })`;
|
|
90
|
+
}
|
|
76
91
|
const TURN_RETRY_SUPPRESSION_PREFIX = "senpi:no-turn-retry:";
|
|
77
92
|
const DEFERRED_RETRY_QUEUE_OWNERS = new WeakSet();
|
|
78
93
|
/** Format the user-attributed payload for one or more explicit skill invocations. */
|
|
@@ -310,6 +325,121 @@ function isSameOverflowSource(message, model, upstreamModelId) {
|
|
|
310
325
|
const THINKING_LEVELS_WITH_MAX = ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
|
|
311
326
|
/** Caps explicit skill expansion so one prompt cannot consume unbounded context. */
|
|
312
327
|
export const MAX_SKILL_EXPANSIONS_PER_PROMPT = 5;
|
|
328
|
+
/** Cursor ingest rejects large verbatim tool payloads. The bound is UTF-8 bytes. */
|
|
329
|
+
export const CURSOR_TOOL_RESULT_MAX_CHARS = 2000;
|
|
330
|
+
export const CURSOR_TOOL_RESULT_MAX_BYTES = 50_000;
|
|
331
|
+
const CURSOR_TRUNCATION_MARKER = "\n...[truncated]";
|
|
332
|
+
export function truncateToolResultBodies(messages, maxChars = CURSOR_TOOL_RESULT_MAX_CHARS, maxBytes = CURSOR_TOOL_RESULT_MAX_BYTES, convert = (candidate) => convertToLlm(candidate)) {
|
|
333
|
+
if (!Array.isArray(messages) || messages.length === 0)
|
|
334
|
+
return { messages, changed: false };
|
|
335
|
+
const segmenter = new Intl.Segmenter(undefined, { granularity: "grapheme" });
|
|
336
|
+
const markerChars = [...segmenter.segment(CURSOR_TRUNCATION_MARKER)].length;
|
|
337
|
+
const result = messages.slice();
|
|
338
|
+
let changed = false;
|
|
339
|
+
// Apply the per-result character cap first, independent of the aggregate wire cap.
|
|
340
|
+
for (let messageIndex = result.length - 1; messageIndex >= 0; messageIndex--) {
|
|
341
|
+
const message = result[messageIndex];
|
|
342
|
+
if (message.role !== "toolResult" || !Array.isArray(message.content))
|
|
343
|
+
continue;
|
|
344
|
+
let content = message.content;
|
|
345
|
+
for (let partIndex = content.length - 1; partIndex >= 0; partIndex--) {
|
|
346
|
+
const part = content[partIndex];
|
|
347
|
+
if (part.type === "image" && typeof part.data === "string")
|
|
348
|
+
continue;
|
|
349
|
+
if (part.type !== "text" || typeof part.text !== "string")
|
|
350
|
+
continue;
|
|
351
|
+
const graphemes = [...segmenter.segment(part.text)].map((item) => item.segment);
|
|
352
|
+
if (graphemes.length <= maxChars)
|
|
353
|
+
continue;
|
|
354
|
+
const kept = graphemes.slice(0, Math.max(0, maxChars - markerChars)).join("");
|
|
355
|
+
const nextText = kept + CURSOR_TRUNCATION_MARKER;
|
|
356
|
+
content = content === message.content ? content.slice() : content;
|
|
357
|
+
content[partIndex] = { ...part, text: nextText };
|
|
358
|
+
result[messageIndex] = { ...message, content };
|
|
359
|
+
changed = true;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
const measure = (candidate) => {
|
|
363
|
+
const converted = convert(candidate);
|
|
364
|
+
const activeUserMessageIndex = converted.at(-1)?.role === "user" ? converted.length - 1 : -1;
|
|
365
|
+
return measureCursorHistorySerializedBytes(converted, activeUserMessageIndex);
|
|
366
|
+
};
|
|
367
|
+
const fits = (candidate = result) => measure(candidate) <= maxBytes;
|
|
368
|
+
if (fits())
|
|
369
|
+
return { messages: changed ? result : messages, changed };
|
|
370
|
+
// Empty the oldest result bodies. Search the monotonic prefix of candidates
|
|
371
|
+
// rather than serializing once for every result (admission must stay bounded).
|
|
372
|
+
const emptyToolResult = (message) => {
|
|
373
|
+
if (message.role !== "toolResult" || !Array.isArray(message.content))
|
|
374
|
+
return message;
|
|
375
|
+
const emptiedContent = message.content.map((part) => part.type === "text" ? { ...part, text: "" } : part.type === "image" ? { ...part, data: "" } : part);
|
|
376
|
+
const content = emptiedContent.filter((part, index) => {
|
|
377
|
+
if (index === 0)
|
|
378
|
+
return true;
|
|
379
|
+
const previous = emptiedContent[index - 1];
|
|
380
|
+
const empty = part.type === "text" ? part.text === "" : part.type === "image" && part.data === "";
|
|
381
|
+
const previousEmpty = previous.type === "text" ? previous.text === "" : previous.type === "image" && previous.data === "";
|
|
382
|
+
return !empty || !previousEmpty;
|
|
383
|
+
});
|
|
384
|
+
return { ...message, content };
|
|
385
|
+
};
|
|
386
|
+
const toolResultIndexes = result.flatMap((message, index) => message.role === "toolResult" && Array.isArray(message.content) ? [index] : []);
|
|
387
|
+
const withEmptyPrefix = (count) => {
|
|
388
|
+
const candidate = result.slice();
|
|
389
|
+
for (let i = 0; i < count; i++)
|
|
390
|
+
candidate[toolResultIndexes[i]] = emptyToolResult(candidate[toolResultIndexes[i]]);
|
|
391
|
+
return candidate;
|
|
392
|
+
};
|
|
393
|
+
let low = 0;
|
|
394
|
+
let high = toolResultIndexes.length;
|
|
395
|
+
while (low < high) {
|
|
396
|
+
const middle = Math.floor((low + high) / 2);
|
|
397
|
+
if (fits(withEmptyPrefix(middle + 1)))
|
|
398
|
+
high = middle;
|
|
399
|
+
else
|
|
400
|
+
low = middle + 1;
|
|
401
|
+
}
|
|
402
|
+
const emptyCount = Math.min(low + 1, toolResultIndexes.length);
|
|
403
|
+
if (emptyCount > 0) {
|
|
404
|
+
result.splice(0, result.length, ...withEmptyPrefix(emptyCount));
|
|
405
|
+
changed = true;
|
|
406
|
+
}
|
|
407
|
+
if (fits())
|
|
408
|
+
return { messages: changed ? result : messages, changed };
|
|
409
|
+
// If metadata alone exceeds the cap, discard the oldest complete turns. This
|
|
410
|
+
// search is also monotonic and avoids quadratic whole-history reserialization.
|
|
411
|
+
const turnRanges = [];
|
|
412
|
+
const isConvertedUser = (message) => convert([message])[0]?.role === "user";
|
|
413
|
+
for (let index = 0; index < result.length; index++) {
|
|
414
|
+
if (!isConvertedUser(result[index]))
|
|
415
|
+
continue;
|
|
416
|
+
const nextUser = result.findIndex((message, nextIndex) => nextIndex > index && isConvertedUser(message));
|
|
417
|
+
turnRanges.push([index, nextUser < 0 ? result.length : nextUser]);
|
|
418
|
+
}
|
|
419
|
+
const withoutTurns = (count) => {
|
|
420
|
+
if (count === 0)
|
|
421
|
+
return result;
|
|
422
|
+
const start = turnRanges[0]?.[0] ?? 0;
|
|
423
|
+
const end = turnRanges[count - 1]?.[1] ?? start;
|
|
424
|
+
return [...result.slice(0, start), ...result.slice(end)];
|
|
425
|
+
};
|
|
426
|
+
low = 0;
|
|
427
|
+
high = turnRanges.length;
|
|
428
|
+
while (low < high) {
|
|
429
|
+
const middle = Math.floor((low + high) / 2);
|
|
430
|
+
if (fits(withoutTurns(middle + 1)))
|
|
431
|
+
high = middle;
|
|
432
|
+
else
|
|
433
|
+
low = middle + 1;
|
|
434
|
+
}
|
|
435
|
+
const turnCount = Math.min(low + 1, turnRanges.length);
|
|
436
|
+
if (turnCount > 0) {
|
|
437
|
+
const next = withoutTurns(turnCount);
|
|
438
|
+
result.splice(0, result.length, ...next);
|
|
439
|
+
changed = true;
|
|
440
|
+
}
|
|
441
|
+
return { messages: changed ? result : messages, changed };
|
|
442
|
+
}
|
|
313
443
|
// ============================================================================
|
|
314
444
|
// AgentSession Class
|
|
315
445
|
// ============================================================================
|
|
@@ -395,6 +525,10 @@ export class AgentSession {
|
|
|
395
525
|
this._pendingBashMessages = [];
|
|
396
526
|
this._turnIndex = 0;
|
|
397
527
|
this._baseToolDefinitions = new Map();
|
|
528
|
+
/** Policy tools withheld from the model, retained so disarming can restore direct access. */
|
|
529
|
+
this._withheldEvalOnlyToolNames = new Set();
|
|
530
|
+
/** Eval-only hint names this session published, so a disarm can withdraw exactly those. */
|
|
531
|
+
this._publishedEvalOnlyHintNames = new Set();
|
|
398
532
|
this._extensionMode = "print";
|
|
399
533
|
// Tool registry for extension getTools/setTools
|
|
400
534
|
this._toolRegistry = new Map();
|
|
@@ -516,6 +650,8 @@ export class AgentSession {
|
|
|
516
650
|
this._extensionRunnerRef = config.extensionRunnerRef;
|
|
517
651
|
this._initialActiveToolNames = config.initialActiveToolNames;
|
|
518
652
|
this._defaultToolNames = config.defaultToolNames ? new Set(config.defaultToolNames) : undefined;
|
|
653
|
+
this._evalOnlyToolNamesOverride = config.evalOnlyToolNames ? new Set(config.evalOnlyToolNames) : undefined;
|
|
654
|
+
this._evalOnlyToolNames = this._resolveEvalOnlyToolNames();
|
|
519
655
|
this._allowedToolNames = config.allowedToolNames ? new Set(config.allowedToolNames) : undefined;
|
|
520
656
|
this._excludedToolNames = config.excludedToolNames ? new Set(config.excludedToolNames) : undefined;
|
|
521
657
|
this._baseToolsOverride = config.baseToolsOverride;
|
|
@@ -727,6 +863,14 @@ export class AgentSession {
|
|
|
727
863
|
(this.agent.prepareNextTurn
|
|
728
864
|
? async (_turn, signal) => await this.agent.prepareNextTurn?.(signal)
|
|
729
865
|
: undefined);
|
|
866
|
+
const previousTransformContext = this.agent.transformContext;
|
|
867
|
+
this.agent.transformContext = async (messages, signal) => {
|
|
868
|
+
const transformed = previousTransformContext ? await previousTransformContext(messages, signal) : messages;
|
|
869
|
+
if (this.model?.provider === "cursor" || this.model?.provider === "cursor-cli-oauth") {
|
|
870
|
+
return ((await truncateToolResultBodies(transformed, CURSOR_TOOL_RESULT_MAX_CHARS, CURSOR_TOOL_RESULT_MAX_BYTES, (candidate) => this.agent.convertToLlm(candidate))).messages ?? transformed);
|
|
871
|
+
}
|
|
872
|
+
return transformed;
|
|
873
|
+
};
|
|
730
874
|
this.agent.prepareNextTurnWithContext = async (turn, signal) => {
|
|
731
875
|
// Enforce compaction only when this prepare precedes an actual provider
|
|
732
876
|
// admission: a tool continuation or queued steer/follow-up messages. A
|
|
@@ -735,7 +879,8 @@ export class AgentSession {
|
|
|
735
879
|
const compactBeforeNextAdmission = async () => {
|
|
736
880
|
const provider = this.model?.provider;
|
|
737
881
|
// Cursor rebuilds the full conversation each hop. Compacting here
|
|
738
|
-
// mutates rootPrompt mid-run and poisons conversationId.
|
|
882
|
+
// mutates rootPrompt mid-run and poisons conversationId (#984).
|
|
883
|
+
// Still truncate verbatim toolResult bodies so the skip cannot send MB-scale payloads (#1043).
|
|
739
884
|
if (provider === "cursor" || provider === "cursor-cli-oauth") {
|
|
740
885
|
return false;
|
|
741
886
|
}
|
|
@@ -816,6 +961,19 @@ export class AgentSession {
|
|
|
816
961
|
// Event Subscription
|
|
817
962
|
// =========================================================================
|
|
818
963
|
/** Emit an event to all listeners */
|
|
964
|
+
_emitEntryAppended(entryId) {
|
|
965
|
+
if (this._extensionMode !== "rpc")
|
|
966
|
+
return;
|
|
967
|
+
const entry = this.sessionManager.getEntry(entryId);
|
|
968
|
+
if (entry)
|
|
969
|
+
this._emit({ type: "entry_appended", entry });
|
|
970
|
+
}
|
|
971
|
+
/** Append a transport-provided entry and publish it on the RPC event stream. */
|
|
972
|
+
appendSessionEntry(entry) {
|
|
973
|
+
this.sessionManager.appendEntry(entry);
|
|
974
|
+
this.agent.state.messages = this.sessionManager.buildSessionContext().messages;
|
|
975
|
+
this._emitEntryAppended(entry.id);
|
|
976
|
+
}
|
|
819
977
|
_emit(event) {
|
|
820
978
|
this._logSessionEvent(event);
|
|
821
979
|
for (const l of this._eventListeners) {
|
|
@@ -976,6 +1134,7 @@ export class AgentSession {
|
|
|
976
1134
|
_invalidateCompactionForModelSelection() {
|
|
977
1135
|
this.abortCompaction();
|
|
978
1136
|
this.abortBranchSummary();
|
|
1137
|
+
this._delegatedCompactionKey = undefined;
|
|
979
1138
|
this._incrementMessageRevision();
|
|
980
1139
|
}
|
|
981
1140
|
_getIdleWaitPromise() {
|
|
@@ -1367,7 +1526,7 @@ export class AgentSession {
|
|
|
1367
1526
|
event.message.role === "assistant" ||
|
|
1368
1527
|
event.message.role === "toolResult") {
|
|
1369
1528
|
// Regular LLM message - persist as SessionMessageEntry
|
|
1370
|
-
this.sessionManager.appendMessage(event.message);
|
|
1529
|
+
this._emitEntryAppended(this.sessionManager.appendMessage(event.message));
|
|
1371
1530
|
this._incrementMessageRevision();
|
|
1372
1531
|
}
|
|
1373
1532
|
// Other message types (bashExecution, compactionSummary, branchSummary) are persisted elsewhere
|
|
@@ -2001,6 +2160,9 @@ export class AgentSession {
|
|
|
2001
2160
|
async executeTool(toolName, params, options) {
|
|
2002
2161
|
let activeTools = this.getActiveToolNames();
|
|
2003
2162
|
let tool = this.agent.state.tools.find((candidate) => candidate.name === toolName);
|
|
2163
|
+
if (!tool && this._isEvalOnlyPolicyArmed() && this._evalOnlyToolNames?.has(toolName)) {
|
|
2164
|
+
tool = this._toolRegistry.get(toolName);
|
|
2165
|
+
}
|
|
2004
2166
|
if (!tool &&
|
|
2005
2167
|
options?.activateInactiveTool === true &&
|
|
2006
2168
|
this._toolDefinitions.has(toolName) &&
|
|
@@ -2075,6 +2237,45 @@ export class AgentSession {
|
|
|
2075
2237
|
return false;
|
|
2076
2238
|
return this._lazyToolActivators.some((activate) => activate(toolName));
|
|
2077
2239
|
}
|
|
2240
|
+
_isEvalOnlyPolicyArmed() {
|
|
2241
|
+
return this._evalOnlyToolNames !== undefined && this._toolRegistry.has("eval");
|
|
2242
|
+
}
|
|
2243
|
+
/**
|
|
2244
|
+
* Resolve the eval-only policy from settings so a reload picks up a flag change.
|
|
2245
|
+
* An explicitly configured set stays authoritative for SDK embedders and tests.
|
|
2246
|
+
*/
|
|
2247
|
+
_resolveEvalOnlyToolNames() {
|
|
2248
|
+
if (this._evalOnlyToolNamesOverride !== undefined)
|
|
2249
|
+
return this._evalOnlyToolNamesOverride;
|
|
2250
|
+
const names = [
|
|
2251
|
+
...(this.settingsManager.getExperimentalBashEvalOnly() ? EVAL_ONLY_SHELL_TOOL_NAMES : []),
|
|
2252
|
+
...(this.settingsManager.getExperimentalWorkflowEvalOnly() ? EVAL_ONLY_WORKFLOW_TOOL_NAMES : []),
|
|
2253
|
+
];
|
|
2254
|
+
return names.length > 0 ? new Set(names) : undefined;
|
|
2255
|
+
}
|
|
2256
|
+
/**
|
|
2257
|
+
* Publish per-tool eval-only redirect hints so a direct call names its own eval helper.
|
|
2258
|
+
*
|
|
2259
|
+
* Hints published here are tracked so a disarm - or a shrinking armed set, e.g. bash+workflow
|
|
2260
|
+
* down to workflow only - withdraws the stale ones. Only tracked names are ever deleted, so
|
|
2261
|
+
* hints owned by other publishers survive.
|
|
2262
|
+
*/
|
|
2263
|
+
_publishEvalOnlyToolHints() {
|
|
2264
|
+
const armed = this._isEvalOnlyPolicyArmed() ? (this._evalOnlyToolNames ?? new Set()) : undefined;
|
|
2265
|
+
for (const name of this._publishedEvalOnlyHintNames) {
|
|
2266
|
+
if (armed?.has(name))
|
|
2267
|
+
continue;
|
|
2268
|
+
delete this.agent.removedToolHints[name];
|
|
2269
|
+
}
|
|
2270
|
+
this._publishedEvalOnlyHintNames.clear();
|
|
2271
|
+
if (!armed)
|
|
2272
|
+
return;
|
|
2273
|
+
for (const name of armed) {
|
|
2274
|
+
this.agent.removedToolHints[name] =
|
|
2275
|
+
`Run ${name} inside an eval cell via ${evalHelperCall(name)}; hooks and permissions still apply.`;
|
|
2276
|
+
this._publishedEvalOnlyHintNames.add(name);
|
|
2277
|
+
}
|
|
2278
|
+
}
|
|
2078
2279
|
/**
|
|
2079
2280
|
* Set active tools by name.
|
|
2080
2281
|
* Only tools in the registry can be enabled. Unknown tool names are ignored.
|
|
@@ -2102,7 +2303,23 @@ export class AgentSession {
|
|
|
2102
2303
|
setActiveToolsByName(toolNames) {
|
|
2103
2304
|
const tools = [];
|
|
2104
2305
|
const validToolNames = [];
|
|
2105
|
-
|
|
2306
|
+
const policyArmed = this._isEvalOnlyPolicyArmed();
|
|
2307
|
+
this._publishEvalOnlyToolHints();
|
|
2308
|
+
const policyNames = this._evalOnlyToolNames;
|
|
2309
|
+
let filteredToolNames = toolNames;
|
|
2310
|
+
if (policyArmed && policyNames) {
|
|
2311
|
+
for (const name of toolNames) {
|
|
2312
|
+
if (policyNames.has(name))
|
|
2313
|
+
this._withheldEvalOnlyToolNames.add(name);
|
|
2314
|
+
}
|
|
2315
|
+
filteredToolNames = toolNames.filter((name) => !policyNames.has(name));
|
|
2316
|
+
}
|
|
2317
|
+
else {
|
|
2318
|
+
this._withheldEvalOnlyToolNames.clear();
|
|
2319
|
+
}
|
|
2320
|
+
// Remember the unfiltered request so a later disarm can restore withheld shell tools.
|
|
2321
|
+
this._requestedActiveToolNames = [...new Set([...toolNames, ...this._withheldEvalOnlyToolNames])];
|
|
2322
|
+
for (const name of filteredToolNames) {
|
|
2106
2323
|
const tool = this._toolRegistry.get(name);
|
|
2107
2324
|
if (tool) {
|
|
2108
2325
|
tools.push(tool);
|
|
@@ -2116,8 +2333,14 @@ export class AgentSession {
|
|
|
2116
2333
|
this._baseSystemPrompt = this._rebuildSystemPrompt(validToolNames);
|
|
2117
2334
|
this.agent.state.systemPrompt = this._systemPromptOverride ?? this._baseSystemPrompt;
|
|
2118
2335
|
if (activeToolNamesChanged) {
|
|
2119
|
-
|
|
2120
|
-
|
|
2336
|
+
// A tool change emitted while extensions are still binding belongs to the
|
|
2337
|
+
// binding itself, not to a mid-session change. The session was already
|
|
2338
|
+
// committed to the client, so cancelling or invalidating work it started
|
|
2339
|
+
// against that session would be spurious.
|
|
2340
|
+
if (this._extensionBindingPromptReadiness === undefined) {
|
|
2341
|
+
this.abortCompaction();
|
|
2342
|
+
this._incrementMessageRevision();
|
|
2343
|
+
}
|
|
2121
2344
|
}
|
|
2122
2345
|
}
|
|
2123
2346
|
/** Whether compaction or branch summarization is currently running */
|
|
@@ -2259,9 +2482,26 @@ export class AgentSession {
|
|
|
2259
2482
|
appendSystemPrompt: loaderAppendSystemPrompt.length > 0 ? loaderAppendSystemPrompt.join("\n\n") : undefined,
|
|
2260
2483
|
};
|
|
2261
2484
|
const basePrompt = loaderSystemPrompt ?? buildDynamicSystemPrompt(this._baseSystemPromptOptions);
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2485
|
+
const prompt = loaderAppendSystemPrompt.length > 0 ? `${basePrompt}\n\n${loaderAppendSystemPrompt.join("\n\n")}` : basePrompt;
|
|
2486
|
+
if (!this._isEvalOnlyPolicyArmed())
|
|
2487
|
+
return prompt;
|
|
2488
|
+
const armed = this._evalOnlyToolNames ?? new Set();
|
|
2489
|
+
const sentences = [];
|
|
2490
|
+
const shellHelpers = EVAL_ONLY_SHELL_TOOL_NAMES.filter((name) => armed.has(name)).map(evalHelperCall);
|
|
2491
|
+
if (shellHelpers.length > 0) {
|
|
2492
|
+
sentences.push(`Shell commands run ONLY inside eval cells via ${shellHelpers.join(" or ")}; hooks and permissions still apply.`);
|
|
2493
|
+
}
|
|
2494
|
+
if (armed.has("workflow")) {
|
|
2495
|
+
sentences.push(`The workflow tool runs ONLY inside eval cells via ${evalHelperCall("workflow")}; hooks and permissions still apply.`);
|
|
2496
|
+
}
|
|
2497
|
+
// SDK embedders can arm names outside the built-in groups; they still need eval guidance.
|
|
2498
|
+
const otherHelpers = [...armed]
|
|
2499
|
+
.filter((name) => !EVAL_ONLY_SHELL_TOOL_NAMES.includes(name) && name !== "workflow")
|
|
2500
|
+
.map(evalHelperCall);
|
|
2501
|
+
if (otherHelpers.length > 0) {
|
|
2502
|
+
sentences.push(`These tools run ONLY inside eval cells via ${otherHelpers.join(" or ")}; hooks and permissions still apply.`);
|
|
2503
|
+
}
|
|
2504
|
+
return sentences.length > 0 ? `${prompt}\n\n${sentences.join("\n\n")}` : prompt;
|
|
2265
2505
|
}
|
|
2266
2506
|
/**
|
|
2267
2507
|
* Send a prompt to the agent.
|
|
@@ -3053,7 +3293,7 @@ export class AgentSession {
|
|
|
3053
3293
|
}
|
|
3054
3294
|
_appendCustomMessage(appMessage) {
|
|
3055
3295
|
this.agent.state.messages.push(appMessage);
|
|
3056
|
-
this.sessionManager.appendCustomMessageEntry(appMessage.customType, appMessage.content, appMessage.display, appMessage.details);
|
|
3296
|
+
this._emitEntryAppended(this.sessionManager.appendCustomMessageEntry(appMessage.customType, appMessage.content, appMessage.display, appMessage.details));
|
|
3057
3297
|
this._incrementMessageRevision();
|
|
3058
3298
|
this._emit({ type: "message_start", message: appMessage });
|
|
3059
3299
|
this._emit({ type: "message_end", message: appMessage });
|
|
@@ -3298,6 +3538,43 @@ export class AgentSession {
|
|
|
3298
3538
|
async setModel(model) {
|
|
3299
3539
|
return this._setModel(model, true);
|
|
3300
3540
|
}
|
|
3541
|
+
assertModelUsable(model = this.model, liveContextTokens = 0) {
|
|
3542
|
+
if (!model || model.contextWindow <= 0)
|
|
3543
|
+
return;
|
|
3544
|
+
const projection = projectModelUsabilityBudget({
|
|
3545
|
+
model,
|
|
3546
|
+
systemPrompt: this.agent.state.systemPrompt,
|
|
3547
|
+
tools: this.agent.state.tools,
|
|
3548
|
+
liveContextTokens,
|
|
3549
|
+
compaction: this.settingsManager.getCompactionSettings(),
|
|
3550
|
+
});
|
|
3551
|
+
if (!projection.usable)
|
|
3552
|
+
throw new ModelUsabilityBudgetError(projection);
|
|
3553
|
+
}
|
|
3554
|
+
_getDownswitchLiveContextTokens(model) {
|
|
3555
|
+
const currentModel = this.model;
|
|
3556
|
+
if (!currentModel)
|
|
3557
|
+
return 0;
|
|
3558
|
+
const compaction = this.settingsManager.getCompactionSettings();
|
|
3559
|
+
const currentBudget = projectModelUsabilityBudget({
|
|
3560
|
+
model: currentModel,
|
|
3561
|
+
systemPrompt: this.agent.state.systemPrompt,
|
|
3562
|
+
tools: this.agent.state.tools,
|
|
3563
|
+
compaction,
|
|
3564
|
+
});
|
|
3565
|
+
const targetBudget = projectModelUsabilityBudget({
|
|
3566
|
+
model,
|
|
3567
|
+
systemPrompt: this.agent.state.systemPrompt,
|
|
3568
|
+
tools: this.agent.state.tools,
|
|
3569
|
+
compaction,
|
|
3570
|
+
});
|
|
3571
|
+
const currentUsableContext = currentBudget.contextWindow - currentBudget.requiredTokens;
|
|
3572
|
+
const targetUsableContext = targetBudget.contextWindow - targetBudget.requiredTokens;
|
|
3573
|
+
if (targetUsableContext >= currentUsableContext)
|
|
3574
|
+
return 0;
|
|
3575
|
+
const fixedPrefixTokens = currentBudget.systemPromptTokens + currentBudget.activeToolSchemaTokens;
|
|
3576
|
+
return Math.max(0, (this.getContextUsage()?.tokens ?? 0) - fixedPrefixTokens);
|
|
3577
|
+
}
|
|
3301
3578
|
/**
|
|
3302
3579
|
* Set the model for this session without changing the global model defaults.
|
|
3303
3580
|
* The selection is still persisted in this session's history.
|
|
@@ -3306,6 +3583,7 @@ export class AgentSession {
|
|
|
3306
3583
|
return this._setModel(model, false);
|
|
3307
3584
|
}
|
|
3308
3585
|
async _setModel(model, updateGlobalDefaults) {
|
|
3586
|
+
this.assertModelUsable(model, this._getDownswitchLiveContextTokens(model));
|
|
3309
3587
|
if (!(await this._modelRuntime.checkAuth(model.provider))) {
|
|
3310
3588
|
throw new Error(`No API key for ${model.provider}/${model.id}`);
|
|
3311
3589
|
}
|
|
@@ -3336,10 +3614,14 @@ export class AgentSession {
|
|
|
3336
3614
|
}
|
|
3337
3615
|
async _switchActiveModel(model, opts) {
|
|
3338
3616
|
const previousModel = this.model;
|
|
3339
|
-
if (opts.invalidateCompaction &&
|
|
3617
|
+
if (opts.invalidateCompaction &&
|
|
3618
|
+
(this._modelSelectionChangesContext(previousModel, model) ||
|
|
3619
|
+
previousModel?.provider !== model.provider ||
|
|
3620
|
+
previousModel?.id !== model.id)) {
|
|
3340
3621
|
this._invalidateCompactionForModelSelection();
|
|
3341
3622
|
}
|
|
3342
3623
|
const thinking = this._getThinkingForModelSwitch(model, opts.ephemeralThinkingLevel);
|
|
3624
|
+
const liveContextTokens = this._getDownswitchLiveContextTokens(model);
|
|
3343
3625
|
this.agent.state.model = model;
|
|
3344
3626
|
this.agent.abortServerSideFallback =
|
|
3345
3627
|
this.settingsManager.getAbortServerSideFallback() && this._retryFallback.hasConfiguredChain();
|
|
@@ -3371,7 +3653,20 @@ export class AgentSession {
|
|
|
3371
3653
|
this._emitServiceTierChangeIfNeeded(previousTier, previousFastMode);
|
|
3372
3654
|
if (!opts.emitModelSelect)
|
|
3373
3655
|
return undefined;
|
|
3374
|
-
|
|
3656
|
+
const previousSystemPrompt = this.agent.state.systemPrompt;
|
|
3657
|
+
try {
|
|
3658
|
+
const systemPromptChange = await this._emitModelSelect(model, previousModel, opts.modelSelectSource);
|
|
3659
|
+
this.assertModelUsable(model, liveContextTokens);
|
|
3660
|
+
return systemPromptChange;
|
|
3661
|
+
}
|
|
3662
|
+
catch (error) {
|
|
3663
|
+
if (previousModel)
|
|
3664
|
+
this.agent.state.model = previousModel;
|
|
3665
|
+
else
|
|
3666
|
+
delete this.agent.state.model;
|
|
3667
|
+
this.agent.state.systemPrompt = previousSystemPrompt;
|
|
3668
|
+
throw error;
|
|
3669
|
+
}
|
|
3375
3670
|
}
|
|
3376
3671
|
_applyEphemeralThinkingLevel(level) {
|
|
3377
3672
|
const previousLevel = this.agent.state.thinkingLevel;
|
|
@@ -3408,7 +3703,11 @@ export class AgentSession {
|
|
|
3408
3703
|
nextIndex = direction === "forward" ? (currentIndex + 1) % len : (currentIndex - 1 + len) % len;
|
|
3409
3704
|
}
|
|
3410
3705
|
const next = favoriteModels[nextIndex];
|
|
3411
|
-
const
|
|
3706
|
+
const liveContextTokens = this._getDownswitchLiveContextTokens(next.model);
|
|
3707
|
+
this.assertModelUsable(next.model, liveContextTokens);
|
|
3708
|
+
const invalidatesCompaction = this._modelSelectionChangesContext(currentModel, next.model) ||
|
|
3709
|
+
currentModel?.provider !== next.model.provider ||
|
|
3710
|
+
currentModel?.id !== next.model.id;
|
|
3412
3711
|
if (invalidatesCompaction) {
|
|
3413
3712
|
this._invalidateCompactionForModelSelection();
|
|
3414
3713
|
}
|
|
@@ -3431,16 +3730,28 @@ export class AgentSession {
|
|
|
3431
3730
|
source: "cycle",
|
|
3432
3731
|
});
|
|
3433
3732
|
this._emitServiceTierChangeIfNeeded(previousTier, previousFastMode);
|
|
3434
|
-
const
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3733
|
+
const previousSystemPrompt = this.agent.state.systemPrompt;
|
|
3734
|
+
try {
|
|
3735
|
+
const systemPromptChange = await this._emitModelSelect(next.model, currentModel, "cycle");
|
|
3736
|
+
this.assertModelUsable(next.model, liveContextTokens);
|
|
3737
|
+
const cycleResult = {
|
|
3738
|
+
model: next.model,
|
|
3739
|
+
thinkingLevel: this.thinkingLevel,
|
|
3740
|
+
isScoped: true,
|
|
3741
|
+
};
|
|
3742
|
+
if (systemPromptChange) {
|
|
3743
|
+
cycleResult.systemPromptChange = systemPromptChange;
|
|
3744
|
+
}
|
|
3745
|
+
return cycleResult;
|
|
3746
|
+
}
|
|
3747
|
+
catch (error) {
|
|
3748
|
+
if (currentModel)
|
|
3749
|
+
this.agent.state.model = currentModel;
|
|
3750
|
+
else
|
|
3751
|
+
delete this.agent.state.model;
|
|
3752
|
+
this.agent.state.systemPrompt = previousSystemPrompt;
|
|
3753
|
+
throw error;
|
|
3442
3754
|
}
|
|
3443
|
-
return cycleResult;
|
|
3444
3755
|
}
|
|
3445
3756
|
// =========================================================================
|
|
3446
3757
|
// Thinking Level Management
|
|
@@ -3610,6 +3921,7 @@ export class AgentSession {
|
|
|
3610
3921
|
setSteeringMode(mode) {
|
|
3611
3922
|
this.agent.steeringMode = mode;
|
|
3612
3923
|
this.settingsManager.setSteeringMode(mode);
|
|
3924
|
+
this._emitSessionSettingsChanged();
|
|
3613
3925
|
}
|
|
3614
3926
|
/**
|
|
3615
3927
|
* Set follow-up message mode.
|
|
@@ -3618,6 +3930,7 @@ export class AgentSession {
|
|
|
3618
3930
|
setFollowUpMode(mode) {
|
|
3619
3931
|
this.agent.followUpMode = mode;
|
|
3620
3932
|
this.settingsManager.setFollowUpMode(mode);
|
|
3933
|
+
this._emitSessionSettingsChanged();
|
|
3621
3934
|
}
|
|
3622
3935
|
// =========================================================================
|
|
3623
3936
|
// Compaction
|
|
@@ -4100,7 +4413,7 @@ export class AgentSession {
|
|
|
4100
4413
|
if (sourceChanged) {
|
|
4101
4414
|
return await this._rejectCompaction(request, requestId, operationId, "stale-revision", false);
|
|
4102
4415
|
}
|
|
4103
|
-
if (this._wouldCompactionOverflow(pathEntries, compactionResult, fromExtension, model)) {
|
|
4416
|
+
if (await this._wouldCompactionOverflow(pathEntries, compactionResult, fromExtension, model)) {
|
|
4104
4417
|
return await this._rejectCompaction(request, requestId, operationId, "would-overflow", false);
|
|
4105
4418
|
}
|
|
4106
4419
|
const compactionEntryId = this.sessionManager.appendCompaction(compactionResult.summary, compactionResult.firstKeptEntryId, compactionResult.tokensBefore, compactionResult.details, fromExtension, compactionResult.usage);
|
|
@@ -4141,6 +4454,7 @@ export class AgentSession {
|
|
|
4141
4454
|
})) {
|
|
4142
4455
|
throw new CompactionCancelledError();
|
|
4143
4456
|
}
|
|
4457
|
+
this._delegatedCompactionKey = undefined;
|
|
4144
4458
|
if (request.owner === "compaction" && this._compactionAbortController === request.controller) {
|
|
4145
4459
|
this._compactionAbortController = undefined;
|
|
4146
4460
|
}
|
|
@@ -4191,7 +4505,7 @@ export class AgentSession {
|
|
|
4191
4505
|
finishCompactionWork();
|
|
4192
4506
|
}
|
|
4193
4507
|
}
|
|
4194
|
-
_wouldCompactionOverflow(pathEntries, compactionResult, fromExtension, model) {
|
|
4508
|
+
async _wouldCompactionOverflow(pathEntries, compactionResult, fromExtension, model) {
|
|
4195
4509
|
const currentLeaf = pathEntries[pathEntries.length - 1];
|
|
4196
4510
|
if (!currentLeaf)
|
|
4197
4511
|
return false;
|
|
@@ -4206,10 +4520,18 @@ export class AgentSession {
|
|
|
4206
4520
|
details: compactionResult.details,
|
|
4207
4521
|
fromHook: fromExtension,
|
|
4208
4522
|
};
|
|
4209
|
-
|
|
4523
|
+
let simulatedMessages = buildSessionContext([...pathEntries, simulatedCompactionEntry], simulatedCompactionEntry.id).messages;
|
|
4524
|
+
// Size the same retained context that will be admitted to Cursor. Persisted JSONL
|
|
4525
|
+
// remains verbatim, but the in-memory request representation is bounded first.
|
|
4526
|
+
if (model.provider === "cursor" || model.provider === "cursor-cli-oauth") {
|
|
4527
|
+
simulatedMessages = truncateToolResultBodies(simulatedMessages).messages ?? simulatedMessages;
|
|
4528
|
+
}
|
|
4210
4529
|
const contextTokens = estimateMessagesTokens(filterContextExcludedMessages(simulatedMessages));
|
|
4211
4530
|
const settings = this.settingsManager.getCompactionSettings();
|
|
4212
|
-
|
|
4531
|
+
const reserveTokens = settings.reserveScalingEnabled === false
|
|
4532
|
+
? settings.reserveTokens
|
|
4533
|
+
: resolveReserveTokens(model.contextWindow, settings.reserveTokens);
|
|
4534
|
+
return contextTokens > model.contextWindow - reserveTokens;
|
|
4213
4535
|
}
|
|
4214
4536
|
/**
|
|
4215
4537
|
* Replaces agent state with the canonical session context while keeping exact
|
|
@@ -4237,6 +4559,9 @@ export class AgentSession {
|
|
|
4237
4559
|
// also emitted with accepted:false so the compaction extension's circuit-breaker
|
|
4238
4560
|
// bookkeeping stops being dead code; other builtin session_compact handlers guard
|
|
4239
4561
|
// on event.accepted.
|
|
4562
|
+
if (rejectionCause === "external-owner" && this.model) {
|
|
4563
|
+
this._delegatedCompactionKey = { provider: this.model.provider, id: this.model.id };
|
|
4564
|
+
}
|
|
4240
4565
|
const trimmedExtensionReason = extensionReason?.trim();
|
|
4241
4566
|
const detailedMessage = trimmedExtensionReason
|
|
4242
4567
|
? `Compaction rejected: ${trimmedExtensionReason}`
|
|
@@ -4370,6 +4695,9 @@ export class AgentSession {
|
|
|
4370
4695
|
if (!model)
|
|
4371
4696
|
return;
|
|
4372
4697
|
const settings = this.settingsManager.getCompactionSettings();
|
|
4698
|
+
const reserveTokens = settings.reserveScalingEnabled === false
|
|
4699
|
+
? settings.reserveTokens
|
|
4700
|
+
: resolveReserveTokens(model.contextWindow, settings.reserveTokens);
|
|
4373
4701
|
const isOversized = () => {
|
|
4374
4702
|
const providerMessages = filterContextExcludedMessages([...this.agent.state.messages, ...messages]);
|
|
4375
4703
|
const estimate = estimateContextTokens(providerMessages);
|
|
@@ -4380,7 +4708,7 @@ export class AgentSession {
|
|
|
4380
4708
|
const contextTokens = usageMessage?.role === "assistant" && this._isAssistantFromBeforeLatestCompaction(usageMessage)
|
|
4381
4709
|
? estimateMessagesTokens(providerMessages)
|
|
4382
4710
|
: estimate.tokens;
|
|
4383
|
-
return contextTokens > model.contextWindow -
|
|
4711
|
+
return contextTokens > model.contextWindow - reserveTokens;
|
|
4384
4712
|
};
|
|
4385
4713
|
if (!settings.enabled || !isOversized())
|
|
4386
4714
|
return;
|
|
@@ -4573,15 +4901,15 @@ export class AgentSession {
|
|
|
4573
4901
|
return claimant !== undefined && !claimant.signal.aborted;
|
|
4574
4902
|
}
|
|
4575
4903
|
_isCompactionDelegated() {
|
|
4576
|
-
const state = this._compactionLifecycle.state;
|
|
4577
4904
|
const model = this.model;
|
|
4578
|
-
return (
|
|
4579
|
-
state.rejectionCause === "external-owner" &&
|
|
4580
|
-
state.model !== undefined &&
|
|
4905
|
+
return (this._delegatedCompactionKey !== undefined &&
|
|
4581
4906
|
model !== undefined &&
|
|
4582
|
-
|
|
4907
|
+
this._delegatedCompactionKey.provider === model.provider &&
|
|
4908
|
+
this._delegatedCompactionKey.id === model.id);
|
|
4583
4909
|
}
|
|
4584
4910
|
async _runPrePromptCompaction(lastAssistantMessage, skipAbortedCheck, reason = "pre_prompt", willRetry = false, allowSummaryOnly = false) {
|
|
4911
|
+
if (this._isCompactionDelegated())
|
|
4912
|
+
return false;
|
|
4585
4913
|
const controller = new AbortController();
|
|
4586
4914
|
const requestId = randomUUID();
|
|
4587
4915
|
this._claimCompactionController(controller, "compaction");
|
|
@@ -4754,6 +5082,8 @@ export class AgentSession {
|
|
|
4754
5082
|
* @returns Whether the post-run loop should call `agent.continue()`
|
|
4755
5083
|
*/
|
|
4756
5084
|
async _runAutoCompaction(reason, willRetry) {
|
|
5085
|
+
if (this._isCompactionDelegated())
|
|
5086
|
+
return false;
|
|
4757
5087
|
const finishCompactionWork = this._sessionWorkBarrier.begin();
|
|
4758
5088
|
const agentMessagesAtStart = this.agent.state.messages.slice();
|
|
4759
5089
|
const autoCompactionController = new AbortController();
|
|
@@ -4887,6 +5217,15 @@ export class AgentSession {
|
|
|
4887
5217
|
*/
|
|
4888
5218
|
setAutoCompactionEnabled(enabled) {
|
|
4889
5219
|
this.settingsManager.setCompactionEnabled(enabled);
|
|
5220
|
+
this._emitSessionSettingsChanged();
|
|
5221
|
+
}
|
|
5222
|
+
_emitSessionSettingsChanged() {
|
|
5223
|
+
this._emit({
|
|
5224
|
+
type: "session_settings_changed",
|
|
5225
|
+
steeringMode: this.steeringMode,
|
|
5226
|
+
followUpMode: this.followUpMode,
|
|
5227
|
+
autoCompactionEnabled: this.autoCompactionEnabled,
|
|
5228
|
+
});
|
|
4890
5229
|
}
|
|
4891
5230
|
/** Whether auto-compaction is enabled */
|
|
4892
5231
|
get autoCompactionEnabled() {
|
|
@@ -4984,6 +5323,7 @@ export class AgentSession {
|
|
|
4984
5323
|
: undefined;
|
|
4985
5324
|
}
|
|
4986
5325
|
_refreshCurrentModelFromRegistry() {
|
|
5326
|
+
this._delegatedCompactionKey = undefined;
|
|
4987
5327
|
const currentModel = this.model;
|
|
4988
5328
|
if (!currentModel) {
|
|
4989
5329
|
return;
|
|
@@ -5308,8 +5648,11 @@ export class AgentSession {
|
|
|
5308
5648
|
}),
|
|
5309
5649
|
})),
|
|
5310
5650
|
].filter((tool) => isAllowedTool(tool.definition.name));
|
|
5651
|
+
// Withheld tools stay in _baseToolDefinitions (and therefore in _toolRegistry, which
|
|
5652
|
+
// getRegisteredTool serves to the Cursor exec bridge) but are dropped from the model-facing
|
|
5653
|
+
// definitions so they never reach the prompt. See temporarilyDisabledToolNames.
|
|
5311
5654
|
const definitionRegistry = new Map(Array.from(this._baseToolDefinitions.entries())
|
|
5312
|
-
.filter(([name]) => isAllowedTool(name))
|
|
5655
|
+
.filter(([name]) => isAllowedTool(name) && !temporarilyDisabledToolNames.has(name))
|
|
5313
5656
|
.map(([name, definition]) => [
|
|
5314
5657
|
name,
|
|
5315
5658
|
{
|
|
@@ -5351,13 +5694,22 @@ export class AgentSession {
|
|
|
5351
5694
|
toolRegistry.set(tool.name, tool);
|
|
5352
5695
|
}
|
|
5353
5696
|
this._toolRegistry = toolRegistry;
|
|
5697
|
+
this._publishEvalOnlyToolHints();
|
|
5354
5698
|
const isDirectlyExposed = (name) => {
|
|
5355
5699
|
const entry = this._toolDefinitions.get(name);
|
|
5356
5700
|
return entry !== undefined && normalizeToolExposure(entry.definition).exposure === "direct";
|
|
5357
5701
|
};
|
|
5358
|
-
|
|
5702
|
+
// A withheld tool is dropped from the DEFAULT selection only. An explicit activeToolNames
|
|
5703
|
+
// request names the tool deliberately, and callers that do so (tests, SDK embedders,
|
|
5704
|
+
// filesystem-policy wiring) still expect it to activate.
|
|
5705
|
+
const hasExplicitActiveToolNames = options?.activeToolNames !== undefined;
|
|
5706
|
+
const nextActiveToolNames = (options?.activeToolNames
|
|
5707
|
+
? [...options.activeToolNames]
|
|
5708
|
+
: [...(this._requestedActiveToolNames ?? previousActiveToolNames)]).filter((name) => {
|
|
5359
5709
|
if (!isAllowedTool(name))
|
|
5360
5710
|
return false;
|
|
5711
|
+
if (!hasExplicitActiveToolNames && temporarilyDisabledToolNames.has(name))
|
|
5712
|
+
return false;
|
|
5361
5713
|
const previousRegistrationIds = options?.previousActiveToolRegistrationIds;
|
|
5362
5714
|
if (!previousRegistrationIds)
|
|
5363
5715
|
return true;
|
|
@@ -5388,6 +5740,7 @@ export class AgentSession {
|
|
|
5388
5740
|
this.setActiveToolsByName([...new Set(nextActiveToolNames)]);
|
|
5389
5741
|
}
|
|
5390
5742
|
_buildRuntime(options) {
|
|
5743
|
+
this._delegatedCompactionKey = undefined;
|
|
5391
5744
|
const autoResizeImages = this.settingsManager.getImageAutoResize();
|
|
5392
5745
|
const shellCommandPrefix = this.settingsManager.getShellCommandPrefix();
|
|
5393
5746
|
const shellPath = this.settingsManager.getShellPath();
|
|
@@ -5439,7 +5792,9 @@ export class AgentSession {
|
|
|
5439
5792
|
const oldExtensionIdentities = oldExtensionRunner.getExtensionIdentities();
|
|
5440
5793
|
const previousFlagValues = oldExtensionRunner.getFlagValues();
|
|
5441
5794
|
const previousActiveToolRegistrationIds = new Map();
|
|
5442
|
-
|
|
5795
|
+
// Cover withheld eval-only tools too: the rebuild drops any seeded name missing from this
|
|
5796
|
+
// map, which would strand shell tools when the policy disarms during this reload.
|
|
5797
|
+
for (const name of this._requestedActiveToolNames ?? this.getActiveToolNames()) {
|
|
5443
5798
|
const entry = this._toolDefinitions.get(name);
|
|
5444
5799
|
if (entry)
|
|
5445
5800
|
previousActiveToolRegistrationIds.set(name, deriveExtensionRegistrationId(entry.sourceInfo, name));
|
|
@@ -5450,6 +5805,12 @@ export class AgentSession {
|
|
|
5450
5805
|
});
|
|
5451
5806
|
time("shutdown", "reload");
|
|
5452
5807
|
await this.settingsManager.reload();
|
|
5808
|
+
this._delegatedCompactionKey = undefined;
|
|
5809
|
+
// Capture the unfiltered request BEFORE the rebuild reassigns it, so a policy that
|
|
5810
|
+
// disarms during this reload can still restore its withheld shell tools.
|
|
5811
|
+
const requestedActiveToolNamesBeforeRebuild = [...(this._requestedActiveToolNames ?? this.getActiveToolNames())];
|
|
5812
|
+
// A flag change must take effect on reload, matching documented settings hot-reload behavior.
|
|
5813
|
+
this._evalOnlyToolNames = this._resolveEvalOnlyToolNames();
|
|
5453
5814
|
this.syncQueueModesFromSettings();
|
|
5454
5815
|
resetApiProviders();
|
|
5455
5816
|
time("settings", "reload");
|
|
@@ -5474,7 +5835,7 @@ export class AgentSession {
|
|
|
5474
5835
|
time("resources", "reload");
|
|
5475
5836
|
try {
|
|
5476
5837
|
this._buildRuntime({
|
|
5477
|
-
activeToolNames:
|
|
5838
|
+
activeToolNames: requestedActiveToolNamesBeforeRebuild,
|
|
5478
5839
|
flagValues: previousFlagValues,
|
|
5479
5840
|
includeAllExtensionTools: true,
|
|
5480
5841
|
previousActiveToolRegistrationIds,
|
|
@@ -6179,12 +6540,13 @@ export class AgentSession {
|
|
|
6179
6540
|
try {
|
|
6180
6541
|
const result = await executeBashWithOperations(resolvedCommand, this.sessionManager.getCwd(), options?.operations ?? createLocalBashOperations({ shellPath }), {
|
|
6181
6542
|
onChunk: (delta) => {
|
|
6182
|
-
onChunk?.(delta);
|
|
6543
|
+
const callbackResult = onChunk?.(delta);
|
|
6183
6544
|
this._emit({
|
|
6184
6545
|
type: "bash_execution_update",
|
|
6185
6546
|
id: options?.id,
|
|
6186
6547
|
delta,
|
|
6187
6548
|
});
|
|
6549
|
+
return callbackResult;
|
|
6188
6550
|
},
|
|
6189
6551
|
signal: abortController.signal,
|
|
6190
6552
|
});
|
|
@@ -6232,6 +6594,10 @@ export class AgentSession {
|
|
|
6232
6594
|
abortController.abort();
|
|
6233
6595
|
}
|
|
6234
6596
|
}
|
|
6597
|
+
/** Remove a host-owned full-output spill after a remote observer failed. */
|
|
6598
|
+
async cleanupBashOutput(path) {
|
|
6599
|
+
await rm(path, { force: true });
|
|
6600
|
+
}
|
|
6235
6601
|
/** Whether a bash command is currently running */
|
|
6236
6602
|
get isBashRunning() {
|
|
6237
6603
|
return this._bashAbortControllers.size > 0;
|
|
@@ -6433,6 +6799,7 @@ export class AgentSession {
|
|
|
6433
6799
|
}
|
|
6434
6800
|
// Update agent state (preserving exact messages still awaiting persistence)
|
|
6435
6801
|
this._restoreAgentMessagesFromSession();
|
|
6802
|
+
this._delegatedCompactionKey = undefined;
|
|
6436
6803
|
this._incrementMessageRevision();
|
|
6437
6804
|
// Emit session_tree event
|
|
6438
6805
|
await this._extensionRunner.emit({
|