@code-yeongyu/senpi 2026.7.20 → 2026.7.22
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 +41 -0
- package/README.md +1 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +1 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/core/agent-session.d.ts +32 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +409 -68
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.js +1 -1
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +2 -2
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +67 -16
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/compaction/stream-watchdog.d.ts +31 -0
- package/dist/core/compaction/stream-watchdog.d.ts.map +1 -0
- package/dist/core/compaction/stream-watchdog.js +78 -0
- package/dist/core/compaction/stream-watchdog.js.map +1 -0
- package/dist/core/extensions/builtin/btw/index.d.ts +3 -0
- package/dist/core/extensions/builtin/btw/index.d.ts.map +1 -0
- package/dist/core/extensions/builtin/btw/index.js +120 -0
- package/dist/core/extensions/builtin/btw/index.js.map +1 -0
- package/dist/core/extensions/builtin/btw/panel.d.ts +21 -0
- package/dist/core/extensions/builtin/btw/panel.d.ts.map +1 -0
- package/dist/core/extensions/builtin/btw/panel.js +61 -0
- package/dist/core/extensions/builtin/btw/panel.js.map +1 -0
- package/dist/core/extensions/builtin/btw/side-query.d.ts +31 -0
- package/dist/core/extensions/builtin/btw/side-query.d.ts.map +1 -0
- package/dist/core/extensions/builtin/btw/side-query.js +68 -0
- package/dist/core/extensions/builtin/btw/side-query.js.map +1 -0
- package/dist/core/extensions/builtin/compaction/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/index.js +47 -11
- package/dist/core/extensions/builtin/compaction/index.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/openai-remote.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/openai-remote.js +3 -1
- package/dist/core/extensions/builtin/compaction/openai-remote.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/speculative.d.ts +17 -0
- package/dist/core/extensions/builtin/compaction/speculative.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/speculative.js +93 -26
- package/dist/core/extensions/builtin/compaction/speculative.js.map +1 -1
- package/dist/core/extensions/builtin/config-reload/index.d.ts +39 -0
- package/dist/core/extensions/builtin/config-reload/index.d.ts.map +1 -0
- package/dist/core/extensions/builtin/config-reload/index.js +659 -0
- package/dist/core/extensions/builtin/config-reload/index.js.map +1 -0
- package/dist/core/extensions/builtin/config-reload/log.d.ts +55 -0
- package/dist/core/extensions/builtin/config-reload/log.d.ts.map +1 -0
- package/dist/core/extensions/builtin/config-reload/log.js +128 -0
- package/dist/core/extensions/builtin/config-reload/log.js.map +1 -0
- package/dist/core/extensions/builtin/config-reload/protocol.d.ts +71 -0
- package/dist/core/extensions/builtin/config-reload/protocol.d.ts.map +1 -0
- package/dist/core/extensions/builtin/config-reload/protocol.js +83 -0
- package/dist/core/extensions/builtin/config-reload/protocol.js.map +1 -0
- package/dist/core/extensions/builtin/config-reload/watch-engine.d.ts +43 -0
- package/dist/core/extensions/builtin/config-reload/watch-engine.d.ts.map +1 -0
- package/dist/core/extensions/builtin/config-reload/watch-engine.js +298 -0
- package/dist/core/extensions/builtin/config-reload/watch-engine.js.map +1 -0
- package/dist/core/extensions/builtin/goal/command-registration.d.ts +2 -2
- package/dist/core/extensions/builtin/goal/command-registration.d.ts.map +1 -1
- package/dist/core/extensions/builtin/goal/command-registration.js +3 -4
- package/dist/core/extensions/builtin/goal/command-registration.js.map +1 -1
- package/dist/core/extensions/builtin/goal/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/goal/index.js +11 -27
- package/dist/core/extensions/builtin/goal/index.js.map +1 -1
- package/dist/core/extensions/builtin/goal/tool-registration.d.ts +2 -2
- package/dist/core/extensions/builtin/goal/tool-registration.d.ts.map +1 -1
- package/dist/core/extensions/builtin/goal/tool-registration.js +2 -3
- package/dist/core/extensions/builtin/goal/tool-registration.js.map +1 -1
- package/dist/core/extensions/builtin/goal/turn-usage.d.ts +20 -0
- package/dist/core/extensions/builtin/goal/turn-usage.d.ts.map +1 -0
- package/dist/core/extensions/builtin/goal/turn-usage.js +61 -0
- package/dist/core/extensions/builtin/goal/turn-usage.js.map +1 -0
- package/dist/core/extensions/builtin/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/index.js +9 -0
- package/dist/core/extensions/builtin/index.js.map +1 -1
- package/dist/core/extensions/builtin/look-at/arguments.d.ts +27 -0
- package/dist/core/extensions/builtin/look-at/arguments.d.ts.map +1 -0
- package/dist/core/extensions/builtin/look-at/arguments.js +109 -0
- package/dist/core/extensions/builtin/look-at/arguments.js.map +1 -0
- package/dist/core/extensions/builtin/look-at/commands.d.ts +9 -0
- package/dist/core/extensions/builtin/look-at/commands.d.ts.map +1 -0
- package/dist/core/extensions/builtin/look-at/commands.js +102 -0
- package/dist/core/extensions/builtin/look-at/commands.js.map +1 -0
- package/dist/core/extensions/builtin/look-at/image-input.d.ts +21 -0
- package/dist/core/extensions/builtin/look-at/image-input.d.ts.map +1 -0
- package/dist/core/extensions/builtin/look-at/image-input.js +151 -0
- package/dist/core/extensions/builtin/look-at/image-input.js.map +1 -0
- package/dist/core/extensions/builtin/look-at/index.d.ts +3 -0
- package/dist/core/extensions/builtin/look-at/index.d.ts.map +1 -0
- package/dist/core/extensions/builtin/look-at/index.js +58 -0
- package/dist/core/extensions/builtin/look-at/index.js.map +1 -0
- package/dist/core/extensions/builtin/look-at/model-selector.d.ts +9 -0
- package/dist/core/extensions/builtin/look-at/model-selector.d.ts.map +1 -0
- package/dist/core/extensions/builtin/look-at/model-selector.js +77 -0
- package/dist/core/extensions/builtin/look-at/model-selector.js.map +1 -0
- package/dist/core/extensions/builtin/look-at/prompts.d.ts +5 -0
- package/dist/core/extensions/builtin/look-at/prompts.d.ts.map +1 -0
- package/dist/core/extensions/builtin/look-at/prompts.js +19 -0
- package/dist/core/extensions/builtin/look-at/prompts.js.map +1 -0
- package/dist/core/extensions/builtin/look-at/render.d.ts +26 -0
- package/dist/core/extensions/builtin/look-at/render.d.ts.map +1 -0
- package/dist/core/extensions/builtin/look-at/render.js +70 -0
- package/dist/core/extensions/builtin/look-at/render.js.map +1 -0
- package/dist/core/extensions/builtin/look-at/runner.d.ts +16 -0
- package/dist/core/extensions/builtin/look-at/runner.d.ts.map +1 -0
- package/dist/core/extensions/builtin/look-at/runner.js +108 -0
- package/dist/core/extensions/builtin/look-at/runner.js.map +1 -0
- package/dist/core/extensions/builtin/look-at/settings.d.ts +13 -0
- package/dist/core/extensions/builtin/look-at/settings.d.ts.map +1 -0
- package/dist/core/extensions/builtin/look-at/settings.js +20 -0
- package/dist/core/extensions/builtin/look-at/settings.js.map +1 -0
- package/dist/core/extensions/builtin/mcp/commands.d.ts.map +1 -1
- package/dist/core/extensions/builtin/mcp/commands.js +2 -0
- package/dist/core/extensions/builtin/mcp/commands.js.map +1 -1
- package/dist/core/extensions/builtin/mcp/config-schema.d.ts +6 -0
- package/dist/core/extensions/builtin/mcp/config-schema.d.ts.map +1 -1
- package/dist/core/extensions/builtin/mcp/config-schema.js +1 -0
- package/dist/core/extensions/builtin/mcp/config-schema.js.map +1 -1
- package/dist/core/extensions/builtin/mcp/config.d.ts.map +1 -1
- package/dist/core/extensions/builtin/mcp/config.js +9 -1
- package/dist/core/extensions/builtin/mcp/config.js.map +1 -1
- package/dist/core/extensions/builtin/mcp/service.d.ts.map +1 -1
- package/dist/core/extensions/builtin/mcp/service.js +22 -6
- package/dist/core/extensions/builtin/mcp/service.js.map +1 -1
- package/dist/core/extensions/builtin/mcp/startup-race.d.ts +10 -0
- package/dist/core/extensions/builtin/mcp/startup-race.d.ts.map +1 -1
- package/dist/core/extensions/builtin/mcp/startup-race.js +18 -1
- package/dist/core/extensions/builtin/mcp/startup-race.js.map +1 -1
- package/dist/core/extensions/builtin/model-fallback/index.d.ts +4 -0
- package/dist/core/extensions/builtin/model-fallback/index.d.ts.map +1 -0
- package/dist/core/extensions/builtin/model-fallback/index.js +55 -0
- package/dist/core/extensions/builtin/model-fallback/index.js.map +1 -0
- package/dist/core/extensions/builtin/model-fallback/settings.d.ts +6 -0
- package/dist/core/extensions/builtin/model-fallback/settings.d.ts.map +1 -0
- package/dist/core/extensions/builtin/model-fallback/settings.js +11 -0
- package/dist/core/extensions/builtin/model-fallback/settings.js.map +1 -0
- package/dist/core/extensions/builtin/model-fallback/ui.d.ts +12 -0
- package/dist/core/extensions/builtin/model-fallback/ui.d.ts.map +1 -0
- package/dist/core/extensions/builtin/model-fallback/ui.js +72 -0
- package/dist/core/extensions/builtin/model-fallback/ui.js.map +1 -0
- package/dist/core/extensions/builtin/nested-agents-md/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/nested-agents-md/index.js +4 -1
- package/dist/core/extensions/builtin/nested-agents-md/index.js.map +1 -1
- package/dist/core/extensions/builtin/rules/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/rules/index.js +4 -1
- package/dist/core/extensions/builtin/rules/index.js.map +1 -1
- package/dist/core/extensions/builtin/terminal/output-format.d.ts +28 -0
- package/dist/core/extensions/builtin/terminal/output-format.d.ts.map +1 -0
- package/dist/core/extensions/builtin/terminal/output-format.js +74 -0
- package/dist/core/extensions/builtin/terminal/output-format.js.map +1 -0
- package/dist/core/extensions/builtin/terminal/runtime-session.d.ts +3 -0
- package/dist/core/extensions/builtin/terminal/runtime-session.d.ts.map +1 -1
- package/dist/core/extensions/builtin/terminal/runtime-session.js +22 -2
- package/dist/core/extensions/builtin/terminal/runtime-session.js.map +1 -1
- package/dist/core/extensions/builtin/terminal/shared.d.ts +7 -0
- package/dist/core/extensions/builtin/terminal/shared.d.ts.map +1 -1
- package/dist/core/extensions/builtin/terminal/shared.js +14 -0
- package/dist/core/extensions/builtin/terminal/shared.js.map +1 -1
- package/dist/core/extensions/builtin/terminal/tools/bash-output.d.ts +5 -1
- package/dist/core/extensions/builtin/terminal/tools/bash-output.d.ts.map +1 -1
- package/dist/core/extensions/builtin/terminal/tools/bash-output.js +88 -6
- package/dist/core/extensions/builtin/terminal/tools/bash-output.js.map +1 -1
- package/dist/core/extensions/builtin/terminal/tools/bash.d.ts +12 -1
- package/dist/core/extensions/builtin/terminal/tools/bash.d.ts.map +1 -1
- package/dist/core/extensions/builtin/terminal/tools/bash.js +82 -8
- package/dist/core/extensions/builtin/terminal/tools/bash.js.map +1 -1
- package/dist/core/extensions/builtin/terminal/tools/render.d.ts +16 -0
- package/dist/core/extensions/builtin/terminal/tools/render.d.ts.map +1 -0
- package/dist/core/extensions/builtin/terminal/tools/render.js +30 -0
- package/dist/core/extensions/builtin/terminal/tools/render.js.map +1 -0
- package/dist/core/extensions/builtin/terminal/tools/spawn.d.ts +2 -0
- package/dist/core/extensions/builtin/terminal/tools/spawn.d.ts.map +1 -1
- package/dist/core/extensions/builtin/terminal/tools/spawn.js +1 -1
- package/dist/core/extensions/builtin/terminal/tools/spawn.js.map +1 -1
- package/dist/core/extensions/builtin/todotools/tools/todo.d.ts.map +1 -1
- package/dist/core/extensions/builtin/todotools/tools/todo.js +22 -6
- package/dist/core/extensions/builtin/todotools/tools/todo.js.map +1 -1
- package/dist/core/extensions/builtin/webfetch/webfetch/fetcher.d.ts +1 -0
- package/dist/core/extensions/builtin/webfetch/webfetch/fetcher.d.ts.map +1 -1
- package/dist/core/extensions/builtin/webfetch/webfetch/fetcher.js +13 -4
- package/dist/core/extensions/builtin/webfetch/webfetch/fetcher.js.map +1 -1
- package/dist/core/extensions/builtin/webfetch/webfetch/renderers.d.ts.map +1 -1
- package/dist/core/extensions/builtin/webfetch/webfetch/renderers.js +17 -2
- package/dist/core/extensions/builtin/webfetch/webfetch/renderers.js.map +1 -1
- package/dist/core/extensions/builtin/webfetch/webfetch/tool.d.ts +8 -1
- package/dist/core/extensions/builtin/webfetch/webfetch/tool.d.ts.map +1 -1
- package/dist/core/extensions/builtin/webfetch/webfetch/tool.js +45 -3
- package/dist/core/extensions/builtin/webfetch/webfetch/tool.js.map +1 -1
- package/dist/core/extensions/builtin/websearch/websearch/renderers.d.ts.map +1 -1
- package/dist/core/extensions/builtin/websearch/websearch/renderers.js +13 -4
- package/dist/core/extensions/builtin/websearch/websearch/renderers.js.map +1 -1
- package/dist/core/extensions/builtin/websearch/websearch/search.d.ts +3 -2
- package/dist/core/extensions/builtin/websearch/websearch/search.d.ts.map +1 -1
- package/dist/core/extensions/builtin/websearch/websearch/search.js +2 -1
- package/dist/core/extensions/builtin/websearch/websearch/search.js.map +1 -1
- package/dist/core/extensions/builtin/websearch/websearch/tool.d.ts.map +1 -1
- package/dist/core/extensions/builtin/websearch/websearch/tool.js +17 -1
- package/dist/core/extensions/builtin/websearch/websearch/tool.js.map +1 -1
- package/dist/core/extensions/builtin/websearch/websearch/types.d.ts +2 -0
- package/dist/core/extensions/builtin/websearch/websearch/types.d.ts.map +1 -1
- package/dist/core/extensions/builtin/websearch/websearch/types.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +6 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +71 -3
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +96 -10
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/model-config-schema.d.ts +1942 -0
- package/dist/core/model-config-schema.d.ts.map +1 -0
- package/dist/core/model-config-schema.js +197 -0
- package/dist/core/model-config-schema.js.map +1 -0
- package/dist/core/model-config.d.ts +2 -578
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js +1 -194
- package/dist/core/model-config.js.map +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +1 -0
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +9 -3
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/provider-composer.d.ts +1 -0
- package/dist/core/provider-composer.d.ts.map +1 -1
- package/dist/core/provider-composer.js +3 -2
- package/dist/core/provider-composer.js.map +1 -1
- package/dist/core/provider-display-names.d.ts.map +1 -1
- package/dist/core/provider-display-names.js +1 -0
- package/dist/core/provider-display-names.js.map +1 -1
- package/dist/core/retry-fallback/chains.d.ts +29 -0
- package/dist/core/retry-fallback/chains.d.ts.map +1 -0
- package/dist/core/retry-fallback/chains.js +109 -0
- package/dist/core/retry-fallback/chains.js.map +1 -0
- package/dist/core/retry-fallback/controller.d.ts +77 -0
- package/dist/core/retry-fallback/controller.d.ts.map +1 -0
- package/dist/core/retry-fallback/controller.js +157 -0
- package/dist/core/retry-fallback/controller.js.map +1 -0
- package/dist/core/retry-fallback/cooldown.d.ts +21 -0
- package/dist/core/retry-fallback/cooldown.d.ts.map +1 -0
- package/dist/core/retry-fallback/cooldown.js +49 -0
- package/dist/core/retry-fallback/cooldown.js.map +1 -0
- package/dist/core/retry-fallback/log.d.ts +10 -0
- package/dist/core/retry-fallback/log.d.ts.map +1 -0
- package/dist/core/retry-fallback/log.js +128 -0
- package/dist/core/retry-fallback/log.js.map +1 -0
- package/dist/core/retry-fallback/validate.d.ts +8 -0
- package/dist/core/retry-fallback/validate.d.ts.map +1 -0
- package/dist/core/retry-fallback/validate.js +63 -0
- package/dist/core/retry-fallback/validate.js.map +1 -0
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +1 -0
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts +39 -3
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +125 -16
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +33 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +153 -6
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts +2 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +30 -20
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/todo-strike.d.ts +8 -0
- package/dist/modes/interactive/components/todo-strike.d.ts.map +1 -0
- package/dist/modes/interactive/components/todo-strike.js +35 -0
- package/dist/modes/interactive/components/todo-strike.js.map +1 -0
- package/dist/modes/interactive/components/tool-execution-renderer.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution-renderer.js +8 -1
- package/dist/modes/interactive/components/tool-execution-renderer.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +4 -0
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +51 -2
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +6 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +124 -4
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/tool-progress.d.ts +8 -0
- package/dist/modes/interactive/tool-progress.d.ts.map +1 -0
- package/dist/modes/interactive/tool-progress.js +26 -0
- package/dist/modes/interactive/tool-progress.js.map +1 -0
- package/dist/modes/interactive/tool-result-reveal.d.ts +18 -0
- package/dist/modes/interactive/tool-result-reveal.d.ts.map +1 -0
- package/dist/modes/interactive/tool-result-reveal.js +155 -0
- package/dist/modes/interactive/tool-result-reveal.js.map +1 -0
- package/dist/utils/fs-watch.d.ts +2 -2
- package/dist/utils/fs-watch.d.ts.map +1 -1
- package/dist/utils/fs-watch.js +2 -2
- package/dist/utils/fs-watch.js.map +1 -1
- package/docs/extensions.md +79 -1
- package/docs/mcp.md +10 -1
- package/docs/models.md +102 -1
- package/docs/providers.md +3 -1
- package/docs/settings.md +35 -0
- package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +24 -0
- package/node_modules/@code-yeongyu/senpi-codemode/package.json +3 -3
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/cell-handler.ts +13 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js +76 -8
- package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/agent.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/agent.js +26 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/agent.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.js +24 -2
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/types.d.ts +5 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/types.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/types.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/package.json +2 -2
- package/node_modules/@earendil-works/pi-ai/README.md +2 -0
- 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 +68 -25
- package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/lazy.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/lazy.js +33 -6
- package/node_modules/@earendil-works/pi-ai/dist/api/lazy.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.js +6 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/transform-messages.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/transform-messages.js +62 -52
- package/node_modules/@earendil-works/pi-ai/dist/api/transform-messages.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api-registry.d.ts +19 -0
- package/node_modules/@earendil-works/pi-ai/dist/api-registry.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api-registry.js +50 -0
- package/node_modules/@earendil-works/pi-ai/dist/api-registry.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/compat.d.ts +2 -17
- package/node_modules/@earendil-works/pi-ai/dist/compat.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/compat.js +3 -52
- package/node_modules/@earendil-works/pi-ai/dist/compat.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/env-api-keys.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/env-api-keys.js +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/env-api-keys.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.d.ts +45 -0
- package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js +45 -0
- package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/index.d.ts +5 -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 +5 -0
- package/node_modules/@earendil-works/pi-ai/dist/index.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/model.d.ts +27 -0
- package/node_modules/@earendil-works/pi-ai/dist/model.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/model.js +2 -0
- package/node_modules/@earendil-works/pi-ai/dist/model.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts +1178 -1072
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.js +2 -0
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/alibaba-token-plan.d.ts +3 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/alibaba-token-plan.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/alibaba-token-plan.js +15 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/alibaba-token-plan.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/alibaba-token-plan.models.d.ts +64 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/alibaba-token-plan.models.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/alibaba-token-plan.models.js +5 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/alibaba-token-plan.models.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/all.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/all.js +2 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/all.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/alibaba-token-plan.json +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/google.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/kimi-coding.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/vercel-ai-gateway.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/faux.d.ts +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/faux.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/faux.js +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/faux.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/google.models.d.ts +8 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/google.models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/google.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.models.d.ts +0 -4
- package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/opencode.models.d.ts +12 -4
- package/node_modules/@earendil-works/pi-ai/dist/providers/opencode.models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/opencode.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.d.ts +20 -4
- package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.d.ts +16 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/index.d.ts +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/index.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/index.js +8 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/index.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-stream-helpers.d.ts +20 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-stream-helpers.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-stream-helpers.js +79 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-stream-helpers.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-tag-scanner.d.ts +2 -18
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-tag-scanner.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-tag-scanner.js +4 -218
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-tag-scanner.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-tag-syntax.d.ts +38 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-tag-syntax.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-tag-syntax.js +210 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-tag-syntax.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/recovery-stream.d.ts +9 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/recovery-stream.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/recovery-stream.js +231 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/recovery-stream.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/recovery-wrapper-state.d.ts +38 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/recovery-wrapper-state.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/recovery-wrapper-state.js +84 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/recovery-wrapper-state.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/stream-boundary.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/stream-boundary.js +20 -57
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/stream-boundary.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/stream.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/stream.js +16 -99
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/stream.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/index.d.ts +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/index.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/index.js +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/index.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/recovery-stream.d.ts +5 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/recovery-stream.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/recovery-stream.js +6 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/recovery-stream.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-code-mask.d.ts +19 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-code-mask.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-code-mask.js +185 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-code-mask.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-content-lifecycle.d.ts +11 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-content-lifecycle.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-content-lifecycle.js +24 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-content-lifecycle.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-diagnostics.d.ts +4 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-diagnostics.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-diagnostics.js +13 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-diagnostics.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-event-stream.d.ts +15 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-event-stream.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-event-stream.js +37 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-event-stream.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-message-snapshot.d.ts +4 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-message-snapshot.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-message-snapshot.js +61 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-message-snapshot.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-native-projection.d.ts +29 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-native-projection.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-native-projection.js +148 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-native-projection.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-stream-failure.d.ts +5 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-stream-failure.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-stream-failure.js +36 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-stream-failure.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-stream-terminal.d.ts +15 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-stream-terminal.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-stream-terminal.js +88 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-stream-terminal.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-stream-wrapper.d.ts +3 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-stream-wrapper.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-stream-wrapper.js +233 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-stream-wrapper.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-text-projection.d.ts +23 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-text-projection.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-text-projection.js +77 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-text-projection.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/stream-message-metadata.d.ts +5 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/stream-message-metadata.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/stream-message-metadata.js +63 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/stream-message-metadata.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/stream-thinking-projection.d.ts +13 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/stream-thinking-projection.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/stream-thinking-projection.js +52 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/stream-thinking-projection.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/stream-wrapper-shared.d.ts +41 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/stream-wrapper-shared.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/stream-wrapper-shared.js +209 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/stream-wrapper-shared.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/stream-wrapper.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/stream-wrapper.js +70 -346
- package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/stream-wrapper.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/types.d.ts +18 -23
- package/node_modules/@earendil-works/pi-ai/dist/types.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/types.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/retry.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js +5 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/stop-details.d.ts +4 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/stop-details.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/stop-details.js +6 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/stop-details.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/package.json +1 -1
- package/node_modules/@earendil-works/pi-pty/package.json +1 -1
- package/node_modules/@earendil-works/pi-tui/package.json +1 -1
- package/package.json +6 -6
|
@@ -16,7 +16,8 @@ import { randomUUID } from "node:crypto";
|
|
|
16
16
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
17
17
|
import { basename, dirname } from "node:path";
|
|
18
18
|
import { prepareAgentToolCall } from "@earendil-works/pi-agent-core";
|
|
19
|
-
import { cleanupSessionResources, isContextOverflow, isRetryableAssistantError, modelsAreEqual, resetApiProviders, streamSimple, } from "@earendil-works/pi-ai/compat";
|
|
19
|
+
import { cleanupSessionResources, isClassifierRefusal, isContextOverflow, isRetryableAssistantError, modelsAreEqual, resetApiProviders, streamSimple, } from "@earendil-works/pi-ai/compat";
|
|
20
|
+
import { getAgentDir } from "../config.js";
|
|
20
21
|
import { getThemeByName, theme } from "../modes/interactive/theme/theme.js";
|
|
21
22
|
import { stripFrontmatter } from "../utils/frontmatter.js";
|
|
22
23
|
import { resolvePath } from "../utils/paths.js";
|
|
@@ -34,6 +35,10 @@ import { filterContextExcludedMessages } from "./messages.js";
|
|
|
34
35
|
import { ModelRegistry } from "./model-registry.js";
|
|
35
36
|
import { getModelNarrowingPatterns, resolveModelScope } from "./model-resolver.js";
|
|
36
37
|
import { expandPromptTemplate } from "./prompt-templates.js";
|
|
38
|
+
import { RetryFallbackController } from "./retry-fallback/controller.js";
|
|
39
|
+
import { SelectorCooldowns } from "./retry-fallback/cooldown.js";
|
|
40
|
+
import { createFallbackLogger } from "./retry-fallback/log.js";
|
|
41
|
+
import { validateFallbackChains } from "./retry-fallback/validate.js";
|
|
37
42
|
import { buildSessionContext, CURRENT_SESSION_VERSION, getLatestCompactionEntry, } from "./session-manager.js";
|
|
38
43
|
import { generateSessionTitle, shouldSkipSessionTitle } from "./session-title-generator.js";
|
|
39
44
|
import { SessionWorkBarrier } from "./session-work-barrier.js";
|
|
@@ -65,13 +70,39 @@ function withoutDeletedHeaders(headers) {
|
|
|
65
70
|
? Object.fromEntries(Object.entries(headers).filter((entry) => entry[1] !== null))
|
|
66
71
|
: undefined;
|
|
67
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* Human-readable rejection message paired with a `CompactionRejectionCause`.
|
|
75
|
+
*
|
|
76
|
+
* Kept exhaustive over the union so the compiler flags any new cause that would
|
|
77
|
+
* otherwise reintroduce silent failures at the `compaction_end` UI seam.
|
|
78
|
+
*/
|
|
79
|
+
function describeCompactionRejection(cause) {
|
|
80
|
+
switch (cause) {
|
|
81
|
+
case "would-overflow":
|
|
82
|
+
return "Compaction rejected: the produced summary would still overflow the model context window. Reduce context (e.g. /new, drop attachments) or switch to a larger-context model.";
|
|
83
|
+
case "cancelled-by-extension":
|
|
84
|
+
return "Compaction rejected: cancelled by an extension.";
|
|
85
|
+
case "circuit-breaker":
|
|
86
|
+
return "Compaction rejected: the compaction circuit breaker is open after repeated failures. Wait for the cooldown and retry.";
|
|
87
|
+
case "per-turn-cap":
|
|
88
|
+
return "Compaction rejected: per-turn compaction cap reached for this turn.";
|
|
89
|
+
}
|
|
90
|
+
}
|
|
68
91
|
class CompactionRejectedError extends Error {
|
|
69
92
|
constructor(rejectionCause) {
|
|
70
|
-
super(rejectionCause === "cancelled-by-extension"
|
|
93
|
+
super(rejectionCause === "cancelled-by-extension"
|
|
94
|
+
? "Compaction cancelled"
|
|
95
|
+
: describeCompactionRejection(rejectionCause));
|
|
71
96
|
this.name = "CompactionRejectedError";
|
|
72
97
|
this.rejectionCause = rejectionCause;
|
|
73
98
|
}
|
|
74
99
|
}
|
|
100
|
+
class RequiredCompactionError extends Error {
|
|
101
|
+
constructor() {
|
|
102
|
+
super("Context remains above the compaction threshold because compaction did not complete");
|
|
103
|
+
this.name = "RequiredCompactionError";
|
|
104
|
+
}
|
|
105
|
+
}
|
|
75
106
|
class MissingModelAccessError extends Error {
|
|
76
107
|
constructor() {
|
|
77
108
|
super("AgentSession requires modelRuntime or modelRegistry");
|
|
@@ -127,6 +158,7 @@ export class AgentSession {
|
|
|
127
158
|
this._retryPromise = undefined;
|
|
128
159
|
this._retryResolve = undefined;
|
|
129
160
|
this._userAbortPromise = undefined;
|
|
161
|
+
this._suppressQueuedContinuationAfterUserAbort = false;
|
|
130
162
|
// Bash execution state
|
|
131
163
|
this._bashAbortController = undefined;
|
|
132
164
|
this._pendingBashMessages = [];
|
|
@@ -158,6 +190,11 @@ export class AgentSession {
|
|
|
158
190
|
this.agent = config.agent;
|
|
159
191
|
this.sessionManager = config.sessionManager;
|
|
160
192
|
this.settingsManager = config.settingsManager;
|
|
193
|
+
const noModelFallback = config.resourceLoader.getExtensions().runtime.flagValues.get("no-model-fallback") === true ||
|
|
194
|
+
process.env.SENPI_NO_FALLBACK === "1";
|
|
195
|
+
if (noModelFallback) {
|
|
196
|
+
this.settingsManager.applyOverrides({ retry: { modelFallback: false } });
|
|
197
|
+
}
|
|
161
198
|
this._scopedModels = config.scopedModels ?? [];
|
|
162
199
|
this._favoriteModels = config.favoriteModels ?? [];
|
|
163
200
|
this._resourceLoader = config.resourceLoader;
|
|
@@ -169,6 +206,30 @@ export class AgentSession {
|
|
|
169
206
|
}
|
|
170
207
|
this._modelRuntime = modelRuntime;
|
|
171
208
|
this._modelRegistry = config.modelRegistry ?? new ModelRegistry(modelRuntime);
|
|
209
|
+
const fallbackLogger = createFallbackLogger(config.agentDir ?? getAgentDir());
|
|
210
|
+
this._fallbackValidationWarnings = validateFallbackChains(this.settingsManager.getRawFallbackChains(), this._modelRegistry);
|
|
211
|
+
for (const warning of this._fallbackValidationWarnings) {
|
|
212
|
+
fallbackLogger.warn("validation_warning", { warning });
|
|
213
|
+
}
|
|
214
|
+
this._retryFallback = new RetryFallbackController({
|
|
215
|
+
getSettings: () => this.settingsManager.getRetryFallbackSettings(),
|
|
216
|
+
registry: this._modelRegistry,
|
|
217
|
+
cooldowns: new SelectorCooldowns(config.fallbackNow ?? (() => Date.now())),
|
|
218
|
+
logger: fallbackLogger,
|
|
219
|
+
switchModel: async (model, thinking, reason) => {
|
|
220
|
+
await this._switchActiveModel(model, {
|
|
221
|
+
persistDefault: false,
|
|
222
|
+
appendSessionEntry: true,
|
|
223
|
+
entryReason: reason,
|
|
224
|
+
emitModelSelect: reason === "fallback-revert",
|
|
225
|
+
invalidateCompaction: false,
|
|
226
|
+
ephemeralThinkingLevel: thinking,
|
|
227
|
+
});
|
|
228
|
+
},
|
|
229
|
+
emit: (event) => this._emit(event),
|
|
230
|
+
getCurrentSelector: () => (this.model ? { model: this.model, thinkingLevel: this.thinkingLevel } : undefined),
|
|
231
|
+
isAuthAvailable: (provider) => this._modelRuntime.hasConfiguredAuth(provider),
|
|
232
|
+
});
|
|
172
233
|
this._extensionRunnerRef = config.extensionRunnerRef;
|
|
173
234
|
this._initialActiveToolNames = config.initialActiveToolNames;
|
|
174
235
|
this._allowedToolNames = config.allowedToolNames ? new Set(config.allowedToolNames) : undefined;
|
|
@@ -309,8 +370,27 @@ export class AgentSession {
|
|
|
309
370
|
? async (_turn, signal) => await this.agent.prepareNextTurn?.(signal)
|
|
310
371
|
: undefined);
|
|
311
372
|
this.agent.prepareNextTurnWithContext = async (turn, signal) => {
|
|
312
|
-
|
|
313
|
-
|
|
373
|
+
let messages = turn.context.messages;
|
|
374
|
+
if (turn.toolResults.length > 0) {
|
|
375
|
+
await this._agentEventQueue;
|
|
376
|
+
const compacted = await this._checkCompaction(turn.message, true, "threshold");
|
|
377
|
+
if (compacted) {
|
|
378
|
+
messages = this.agent.state.messages.slice();
|
|
379
|
+
}
|
|
380
|
+
else {
|
|
381
|
+
const settings = this.settingsManager.getCompactionSettings();
|
|
382
|
+
const contextTokens = estimateContextTokens(filterContextExcludedMessages(this.sessionManager.buildSessionContext().messages)).tokens;
|
|
383
|
+
if (settings.enabled && this.model && shouldCompact(contextTokens, this.model.contextWindow, settings)) {
|
|
384
|
+
throw new RequiredCompactionError();
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
const postCompactionTurn = {
|
|
389
|
+
...turn,
|
|
390
|
+
context: { ...turn.context, messages },
|
|
391
|
+
};
|
|
392
|
+
const previousSnapshot = await previousPrepareNextTurnWithContext?.(postCompactionTurn, signal);
|
|
393
|
+
const previousContext = previousSnapshot?.context ?? postCompactionTurn.context;
|
|
314
394
|
return {
|
|
315
395
|
...previousSnapshot,
|
|
316
396
|
context: {
|
|
@@ -418,7 +498,8 @@ export class AgentSession {
|
|
|
418
498
|
return;
|
|
419
499
|
}
|
|
420
500
|
const lastAssistant = this._findLastAssistantInMessages(event.messages);
|
|
421
|
-
if (!lastAssistant ||
|
|
501
|
+
if (!lastAssistant ||
|
|
502
|
+
(!this._isRetryableError(lastAssistant) && !this._isHardErrorFallbackEligible(lastAssistant))) {
|
|
422
503
|
return;
|
|
423
504
|
}
|
|
424
505
|
this._retryPromise = new Promise((resolve) => {
|
|
@@ -468,12 +549,22 @@ export class AgentSession {
|
|
|
468
549
|
return false;
|
|
469
550
|
}
|
|
470
551
|
const lastAssistant = this._lastAssistantMessage ?? this._findLastAssistantInMessages(messages);
|
|
471
|
-
if (!lastAssistant
|
|
552
|
+
if (!lastAssistant) {
|
|
472
553
|
return false;
|
|
473
554
|
}
|
|
474
|
-
|
|
555
|
+
const retryableError = this._isRetryableError(lastAssistant);
|
|
556
|
+
if (!retryableError && this._isHardErrorFallbackEligible(lastAssistant)) {
|
|
557
|
+
return true;
|
|
558
|
+
}
|
|
559
|
+
if (!retryableError) {
|
|
475
560
|
return false;
|
|
476
561
|
}
|
|
562
|
+
if (isClassifierRefusal(lastAssistant)) {
|
|
563
|
+
return this._retryAttempt + 1 <= settings.maxRetries && this._retryFallback.canTryFallback();
|
|
564
|
+
}
|
|
565
|
+
if (this._retryAttempt + 1 > settings.maxRetries) {
|
|
566
|
+
return this._retryFallback.canTryFallback();
|
|
567
|
+
}
|
|
477
568
|
const errorMessage = lastAssistant.errorMessage || "Unknown error";
|
|
478
569
|
const providerDelayMs = this._getProviderRetryDelayMs(errorMessage);
|
|
479
570
|
if (providerDelayMs === undefined) {
|
|
@@ -486,6 +577,7 @@ export class AgentSession {
|
|
|
486
577
|
// This ensures the UI sees the updated queue state
|
|
487
578
|
if (event.type === "message_start" && event.message.role === "user") {
|
|
488
579
|
this._overflowRecoveryAttempted = false;
|
|
580
|
+
this._retryFallback.resetTurn();
|
|
489
581
|
const messageText = this._getUserMessageText(event.message);
|
|
490
582
|
if (messageText) {
|
|
491
583
|
// Check steering queue first
|
|
@@ -534,6 +626,14 @@ export class AgentSession {
|
|
|
534
626
|
// Reset retry counter immediately on successful assistant response
|
|
535
627
|
// This prevents accumulation across multiple LLM calls within a turn
|
|
536
628
|
if (assistantMsg.stopReason !== "error" && this._retryAttempt > 0) {
|
|
629
|
+
const fallback = this._retryFallback.activeState;
|
|
630
|
+
if (fallback) {
|
|
631
|
+
this._emit({
|
|
632
|
+
type: "retry_fallback_succeeded",
|
|
633
|
+
model: this.model ? `${this.model.provider}/${this.model.id}` : "",
|
|
634
|
+
chainKey: fallback.chainKey,
|
|
635
|
+
});
|
|
636
|
+
}
|
|
537
637
|
this._emit({
|
|
538
638
|
type: "auto_retry_end",
|
|
539
639
|
success: true,
|
|
@@ -545,16 +645,27 @@ export class AgentSession {
|
|
|
545
645
|
}
|
|
546
646
|
// Check auto-retry and auto-compaction after agent completes
|
|
547
647
|
let launchedContinuation = false;
|
|
548
|
-
const
|
|
648
|
+
const userAbortSuppressedQueuedContinuation = event.type === "agent_end" && this._suppressQueuedContinuationAfterUserAbort;
|
|
649
|
+
if (userAbortSuppressedQueuedContinuation) {
|
|
650
|
+
this._suppressQueuedContinuationAfterUserAbort = false;
|
|
651
|
+
}
|
|
652
|
+
const allowsQueuedContinuation = event.type === "agent_end" && !userAbortSuppressedQueuedContinuation
|
|
653
|
+
? this._agentEndAllowsQueuedContinuation(event.messages)
|
|
654
|
+
: false;
|
|
549
655
|
if (event.type === "agent_end" && this._lastAssistantMessage) {
|
|
550
656
|
const msg = this._lastAssistantMessage;
|
|
551
657
|
this._lastAssistantMessage = undefined;
|
|
552
|
-
//
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
658
|
+
// Retry transient failures normally and eligible hard errors only through a fallback.
|
|
659
|
+
const retryableError = this._isRetryableError(msg);
|
|
660
|
+
let didRetry = false;
|
|
661
|
+
if (retryableError) {
|
|
662
|
+
didRetry = await this._handleRetryableError(msg);
|
|
663
|
+
}
|
|
664
|
+
else if (this._isHardErrorFallbackEligible(msg)) {
|
|
665
|
+
didRetry = await this._handleRetryableError(msg, { hardErrorFallback: true });
|
|
557
666
|
}
|
|
667
|
+
if (didRetry)
|
|
668
|
+
return; // Retry was initiated, don't proceed to compaction
|
|
558
669
|
this._resolveRetry();
|
|
559
670
|
launchedContinuation = await this._checkCompaction(msg);
|
|
560
671
|
}
|
|
@@ -598,6 +709,10 @@ export class AgentSession {
|
|
|
598
709
|
}
|
|
599
710
|
return undefined;
|
|
600
711
|
}
|
|
712
|
+
_isAssistantFromBeforeLatestCompaction(assistantMessage) {
|
|
713
|
+
const compactionEntry = getLatestCompactionEntry(this.sessionManager.getBranch());
|
|
714
|
+
return compactionEntry !== null && assistantMessage.timestamp <= new Date(compactionEntry.timestamp).getTime();
|
|
715
|
+
}
|
|
601
716
|
_replaceMessageInPlace(target, replacement) {
|
|
602
717
|
// Agent-core stores the finalized message object in its state before emitting message_end.
|
|
603
718
|
// SessionManager persistence happens later in _processAgentEvent() with event.message.
|
|
@@ -1048,11 +1163,22 @@ export class AgentSession {
|
|
|
1048
1163
|
throwIfCancelled();
|
|
1049
1164
|
}
|
|
1050
1165
|
const shouldWaitForSessionWork = options?.source !== "extension";
|
|
1166
|
+
// A steer/followUp submission during an active run can be queued immediately.
|
|
1167
|
+
// Waiting on the session-work barrier here would trap the message inside this
|
|
1168
|
+
// call for the rest of the run whenever a queued continuation (e.g. an active
|
|
1169
|
+
// goal chain) holds the barrier, making typed input invisible until the run
|
|
1170
|
+
// ends or the user aborts.
|
|
1171
|
+
const canQueueWhileStreaming = this.isStreaming && !this.isCompacting && options?.streamingBehavior !== undefined;
|
|
1051
1172
|
if (shouldWaitForSessionWork &&
|
|
1173
|
+
!canQueueWhileStreaming &&
|
|
1052
1174
|
(!this.isStreaming || this.isCompacting || this._sessionWorkBarrier.hasActiveWork)) {
|
|
1053
1175
|
await this._waitForSettledSessionWork();
|
|
1054
1176
|
throwIfCancelled();
|
|
1055
1177
|
}
|
|
1178
|
+
// Turn boundary: restore the primary model if the fallback cooldown expired.
|
|
1179
|
+
if (!this.isStreaming) {
|
|
1180
|
+
await this._maybeRestoreFallbackPrimary();
|
|
1181
|
+
}
|
|
1056
1182
|
const expandPromptTemplates = options?.expandPromptTemplates ?? true;
|
|
1057
1183
|
const preflightResult = options?.preflightResult;
|
|
1058
1184
|
const promptDisposition = options?.promptDisposition;
|
|
@@ -1109,6 +1235,27 @@ export class AgentSession {
|
|
|
1109
1235
|
preflightResult?.(true);
|
|
1110
1236
|
return;
|
|
1111
1237
|
}
|
|
1238
|
+
// The queue-while-streaming bypass above skipped the settled-work wait. If
|
|
1239
|
+
// the run ended while input was being expanded, serialize with remaining
|
|
1240
|
+
// session work before sending a fresh prompt, and re-queue if a scheduled
|
|
1241
|
+
// continuation started a new run in the meantime.
|
|
1242
|
+
if (canQueueWhileStreaming &&
|
|
1243
|
+
shouldWaitForSessionWork &&
|
|
1244
|
+
(this.isCompacting || this._sessionWorkBarrier.hasActiveWork)) {
|
|
1245
|
+
await this._waitForSettledSessionWork();
|
|
1246
|
+
throwIfCancelled();
|
|
1247
|
+
if (this.isStreaming) {
|
|
1248
|
+
if (options?.streamingBehavior === "followUp") {
|
|
1249
|
+
await this._queueFollowUp(expandedText, currentImages);
|
|
1250
|
+
}
|
|
1251
|
+
else {
|
|
1252
|
+
await this._queueSteer(expandedText, currentImages);
|
|
1253
|
+
}
|
|
1254
|
+
promptDisposition?.("queued");
|
|
1255
|
+
preflightResult?.(true);
|
|
1256
|
+
return;
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1112
1259
|
// Flush any pending bash messages before the new prompt
|
|
1113
1260
|
this._flushPendingBashMessages();
|
|
1114
1261
|
// Validate model
|
|
@@ -1130,7 +1277,14 @@ export class AgentSession {
|
|
|
1130
1277
|
// The user's new prompt is sent below, so do not call agent.continue() here.
|
|
1131
1278
|
const lastAssistant = this._findLastAssistantMessage();
|
|
1132
1279
|
if (lastAssistant) {
|
|
1133
|
-
await this._checkCompaction(lastAssistant, false, "pre_prompt");
|
|
1280
|
+
const compacted = await this._checkCompaction(lastAssistant, false, "pre_prompt");
|
|
1281
|
+
if (!compacted && !this._isAssistantFromBeforeLatestCompaction(lastAssistant)) {
|
|
1282
|
+
const settings = this.settingsManager.getCompactionSettings();
|
|
1283
|
+
const contextTokens = estimateContextTokens(filterContextExcludedMessages(this.sessionManager.buildSessionContext().messages)).tokens;
|
|
1284
|
+
if (settings.enabled && this.model && shouldCompact(contextTokens, this.model.contextWindow, settings)) {
|
|
1285
|
+
throw new RequiredCompactionError();
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1134
1288
|
}
|
|
1135
1289
|
// Build messages array (custom message if any, then user message)
|
|
1136
1290
|
messages = [];
|
|
@@ -1525,6 +1679,9 @@ export class AgentSession {
|
|
|
1525
1679
|
await this._userAbortPromise;
|
|
1526
1680
|
return;
|
|
1527
1681
|
}
|
|
1682
|
+
if (this.isStreaming) {
|
|
1683
|
+
this._suppressQueuedContinuationAfterUserAbort = true;
|
|
1684
|
+
}
|
|
1528
1685
|
const abortPromise = (async () => {
|
|
1529
1686
|
this.agent.abort();
|
|
1530
1687
|
await this.waitForIdle();
|
|
@@ -1592,20 +1749,57 @@ export class AgentSession {
|
|
|
1592
1749
|
if (!(await this._modelRuntime.checkAuth(model.provider))) {
|
|
1593
1750
|
throw new Error(`No API key for ${model.provider}/${model.id}`);
|
|
1594
1751
|
}
|
|
1752
|
+
// A manual model change abandons any active fallback window; if a fallback
|
|
1753
|
+
// retry sleep is still pending, cancel it so no surprise continuation fires.
|
|
1754
|
+
const hadActiveFallback = this._retryFallback.activeState !== undefined;
|
|
1755
|
+
this._retryFallback.clearForManualModelChange(model);
|
|
1756
|
+
if (hadActiveFallback && this._retryAbortController) {
|
|
1757
|
+
this.abortRetry();
|
|
1758
|
+
}
|
|
1759
|
+
return await this._switchActiveModel(model, {
|
|
1760
|
+
persistDefault: true,
|
|
1761
|
+
appendSessionEntry: true,
|
|
1762
|
+
emitModelSelect: true,
|
|
1763
|
+
invalidateCompaction: true,
|
|
1764
|
+
});
|
|
1765
|
+
}
|
|
1766
|
+
async _maybeRestoreFallbackPrimary() {
|
|
1767
|
+
try {
|
|
1768
|
+
await this._retryFallback.maybeRestorePrimary(this.settingsManager.getRetryFallbackSettings().revertPolicy);
|
|
1769
|
+
}
|
|
1770
|
+
catch (error) {
|
|
1771
|
+
this._retryFallback.clear();
|
|
1772
|
+
console.error("fallback revert failed; cleared fallback state", error);
|
|
1773
|
+
}
|
|
1774
|
+
}
|
|
1775
|
+
async _switchActiveModel(model, opts) {
|
|
1595
1776
|
const previousModel = this.model;
|
|
1596
|
-
|
|
1597
|
-
if (invalidatesCompaction) {
|
|
1777
|
+
if (opts.invalidateCompaction && this._modelSelectionChangesContext(previousModel, model)) {
|
|
1598
1778
|
this._invalidateCompactionForModelSelection();
|
|
1599
1779
|
}
|
|
1600
|
-
const thinkingLevel = this._getThinkingLevelForModelSwitch();
|
|
1780
|
+
const thinkingLevel = this._getThinkingLevelForModelSwitch(opts.ephemeralThinkingLevel);
|
|
1601
1781
|
this.agent.state.model = model;
|
|
1602
|
-
|
|
1603
|
-
|
|
1782
|
+
if (opts.appendSessionEntry) {
|
|
1783
|
+
this.sessionManager.appendModelChange(model.provider, model.id, opts.entryReason, previousModel?.provider, previousModel?.id);
|
|
1784
|
+
}
|
|
1785
|
+
if (opts.persistDefault) {
|
|
1786
|
+
this.settingsManager.setDefaultModelAndProvider(model.provider, model.id);
|
|
1787
|
+
}
|
|
1604
1788
|
const scopedMatch = this._scopedModels.find((sm) => modelsAreEqual(sm.model, model));
|
|
1605
1789
|
this._currentServiceTier = this._resolveServiceTier(model, scopedMatch?.serviceTier);
|
|
1606
|
-
|
|
1790
|
+
if (opts.ephemeralThinkingLevel !== undefined) {
|
|
1791
|
+
this._applyEphemeralThinkingLevel(thinkingLevel);
|
|
1792
|
+
}
|
|
1793
|
+
else {
|
|
1794
|
+
this.setThinkingLevel(thinkingLevel);
|
|
1795
|
+
}
|
|
1796
|
+
if (!opts.emitModelSelect)
|
|
1797
|
+
return undefined;
|
|
1607
1798
|
return await this._emitModelSelect(model, previousModel, "set");
|
|
1608
1799
|
}
|
|
1800
|
+
_applyEphemeralThinkingLevel(level) {
|
|
1801
|
+
this.agent.state.thinkingLevel = level;
|
|
1802
|
+
}
|
|
1609
1803
|
/**
|
|
1610
1804
|
* Cycle to next/previous model.
|
|
1611
1805
|
* Uses favorite models, constrained by any global model narrowing.
|
|
@@ -1637,6 +1831,7 @@ export class AgentSession {
|
|
|
1637
1831
|
if (invalidatesCompaction) {
|
|
1638
1832
|
this._invalidateCompactionForModelSelection();
|
|
1639
1833
|
}
|
|
1834
|
+
this._retryFallback.clearForManualModelChange(next.model);
|
|
1640
1835
|
const thinkingLevel = this._getThinkingLevelForModelSwitch(next.thinkingLevel);
|
|
1641
1836
|
this.agent.state.model = next.model;
|
|
1642
1837
|
this.sessionManager.appendModelChange(next.model.provider, next.model.id);
|
|
@@ -1668,6 +1863,9 @@ export class AgentSession {
|
|
|
1668
1863
|
// Only persist if actually changing
|
|
1669
1864
|
const previousLevel = this.agent.state.thinkingLevel;
|
|
1670
1865
|
const isChanging = effectiveLevel !== previousLevel;
|
|
1866
|
+
if (isChanging) {
|
|
1867
|
+
this._retryFallback.noteManualThinkingLevel();
|
|
1868
|
+
}
|
|
1671
1869
|
this.agent.state.thinkingLevel = effectiveLevel;
|
|
1672
1870
|
if (isChanging) {
|
|
1673
1871
|
this.sessionManager.appendThinkingLevelChange(effectiveLevel);
|
|
@@ -1919,7 +2117,7 @@ export class AgentSession {
|
|
|
1919
2117
|
signal,
|
|
1920
2118
|
}));
|
|
1921
2119
|
if (extensionResult?.cancel) {
|
|
1922
|
-
return await this._rejectCompaction(request, requestId, "cancelled-by-extension", true);
|
|
2120
|
+
return await this._rejectCompaction(request, requestId, extensionResult.rejectionCause ?? "cancelled-by-extension", true, extensionResult.reason);
|
|
1923
2121
|
}
|
|
1924
2122
|
if (extensionResult?.compaction) {
|
|
1925
2123
|
compactionResult = extensionResult.compaction;
|
|
@@ -1928,7 +2126,7 @@ export class AgentSession {
|
|
|
1928
2126
|
}
|
|
1929
2127
|
if (!compactionResult) {
|
|
1930
2128
|
const { apiKey, headers, extraBody, env } = await this._getCompactionRequestAuth(this.model);
|
|
1931
|
-
compactionResult = await compact(preparation, this.model, apiKey, headers, request.customInstructions, signal, extraBody, this.thinkingLevel, this.agent.streamFn, env);
|
|
2129
|
+
compactionResult = await compact(preparation, this.model, apiKey, headers, request.customInstructions, signal, extraBody, this.thinkingLevel, this.agent.streamFn, env, this.agent.transformContext);
|
|
1932
2130
|
}
|
|
1933
2131
|
}
|
|
1934
2132
|
if (signal.aborted) {
|
|
@@ -1991,11 +2189,22 @@ export class AgentSession {
|
|
|
1991
2189
|
fromHook: fromExtension,
|
|
1992
2190
|
};
|
|
1993
2191
|
const simulatedMessages = buildSessionContext([...pathEntries, simulatedCompactionEntry], simulatedCompactionEntry.id).messages;
|
|
1994
|
-
const contextTokens =
|
|
2192
|
+
const contextTokens = estimateMessagesTokens(filterContextExcludedMessages(simulatedMessages));
|
|
1995
2193
|
const settings = this.settingsManager.getCompactionSettings();
|
|
1996
2194
|
return contextTokens > this.model.contextWindow - settings.reserveTokens;
|
|
1997
2195
|
}
|
|
1998
|
-
async _rejectCompaction(request, requestId, rejectionCause, aborted) {
|
|
2196
|
+
async _rejectCompaction(request, requestId, rejectionCause, aborted, extensionReason) {
|
|
2197
|
+
// Per plan Section 1: rejection must never be silent. The compaction_end event
|
|
2198
|
+
// carries a non-empty human-readable errorMessage (unless the user aborted, where
|
|
2199
|
+
// the aborted branch already renders "Compaction cancelled"). session_compact is
|
|
2200
|
+
// also emitted with accepted:false so the compaction extension's circuit-breaker
|
|
2201
|
+
// bookkeeping stops being dead code; other builtin session_compact handlers guard
|
|
2202
|
+
// on event.accepted.
|
|
2203
|
+
const trimmedExtensionReason = extensionReason?.trim();
|
|
2204
|
+
const detailedMessage = trimmedExtensionReason
|
|
2205
|
+
? `Compaction rejected: ${trimmedExtensionReason}`
|
|
2206
|
+
: describeCompactionRejection(rejectionCause);
|
|
2207
|
+
const errorMessage = aborted && !trimmedExtensionReason ? undefined : detailedMessage;
|
|
1999
2208
|
this._emit({
|
|
2000
2209
|
type: "compaction_end",
|
|
2001
2210
|
reason: request.reason,
|
|
@@ -2005,6 +2214,16 @@ export class AgentSession {
|
|
|
2005
2214
|
requestId,
|
|
2006
2215
|
accepted: false,
|
|
2007
2216
|
rejectionCause,
|
|
2217
|
+
errorMessage,
|
|
2218
|
+
});
|
|
2219
|
+
await this._extensionRunner.emit({
|
|
2220
|
+
type: "session_compact",
|
|
2221
|
+
reason: request.reason,
|
|
2222
|
+
requestId,
|
|
2223
|
+
accepted: false,
|
|
2224
|
+
rejectionCause,
|
|
2225
|
+
fromExtension: false,
|
|
2226
|
+
willRetry: false,
|
|
2008
2227
|
});
|
|
2009
2228
|
return { accepted: false, requestId, rejectionCause };
|
|
2010
2229
|
}
|
|
@@ -2032,7 +2251,7 @@ export class AgentSession {
|
|
|
2032
2251
|
* @param assistantMessage The assistant message to check
|
|
2033
2252
|
* @param skipAbortedCheck If false, include aborted messages (for pre-prompt check). Default: true
|
|
2034
2253
|
*/
|
|
2035
|
-
async _checkCompaction(assistantMessage, skipAbortedCheck = true,
|
|
2254
|
+
async _checkCompaction(assistantMessage, skipAbortedCheck = true, inlineReason) {
|
|
2036
2255
|
const settings = this.settingsManager.getCompactionSettings();
|
|
2037
2256
|
if (!settings.enabled)
|
|
2038
2257
|
return false;
|
|
@@ -2050,8 +2269,7 @@ export class AgentSession {
|
|
|
2050
2269
|
// compaction boundary. This prevents a stale pre-compaction usage/error
|
|
2051
2270
|
// from retriggering compaction on the first prompt after compaction.
|
|
2052
2271
|
const compactionEntry = getLatestCompactionEntry(this.sessionManager.getBranch());
|
|
2053
|
-
|
|
2054
|
-
if (assistantIsFromBeforeCompaction) {
|
|
2272
|
+
if (this._isAssistantFromBeforeLatestCompaction(assistantMessage)) {
|
|
2055
2273
|
return false;
|
|
2056
2274
|
}
|
|
2057
2275
|
// Case 1: Overflow - LLM returned context overflow error.
|
|
@@ -2076,7 +2294,7 @@ export class AgentSession {
|
|
|
2076
2294
|
willRetry: false,
|
|
2077
2295
|
errorMessage,
|
|
2078
2296
|
});
|
|
2079
|
-
if (
|
|
2297
|
+
if (inlineReason === "pre_prompt") {
|
|
2080
2298
|
throw new Error(errorMessage);
|
|
2081
2299
|
}
|
|
2082
2300
|
return false;
|
|
@@ -2089,42 +2307,47 @@ export class AgentSession {
|
|
|
2089
2307
|
this.agent.state.messages = messages.slice(0, -1);
|
|
2090
2308
|
this._incrementMessageRevision();
|
|
2091
2309
|
}
|
|
2092
|
-
if (
|
|
2093
|
-
await this._runPrePromptCompaction(assistantMessage, skipAbortedCheck, "overflow", willRetry);
|
|
2310
|
+
if (inlineReason) {
|
|
2311
|
+
return await this._runPrePromptCompaction(assistantMessage, skipAbortedCheck, "overflow", willRetry);
|
|
2094
2312
|
}
|
|
2095
2313
|
else {
|
|
2096
2314
|
return await this._runAutoCompaction("overflow", willRetry);
|
|
2097
2315
|
}
|
|
2098
|
-
return false;
|
|
2099
2316
|
}
|
|
2100
2317
|
// Case 2: Threshold - context is getting large
|
|
2101
2318
|
// For error messages or all-zero usage messages, estimate from the last valid response.
|
|
2102
2319
|
// This ensures sessions that hit persistent API errors (e.g. 529) or malformed zero-usage
|
|
2103
2320
|
// responses can still compact and do not reset context accounting.
|
|
2104
2321
|
let contextTokens;
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
const estimate = estimateContextTokens(messages);
|
|
2109
|
-
if (estimate.lastUsageIndex === null)
|
|
2110
|
-
return false; // No usage data at all
|
|
2111
|
-
// Verify the usage source is post-compaction. Kept pre-compaction messages
|
|
2112
|
-
// have stale usage reflecting the old (larger) context and would falsely
|
|
2113
|
-
// trigger compaction right after one just finished.
|
|
2114
|
-
const usageMsg = messages[estimate.lastUsageIndex];
|
|
2115
|
-
if (compactionEntry &&
|
|
2116
|
-
usageMsg.role === "assistant" &&
|
|
2117
|
-
usageMsg.timestamp <= new Date(compactionEntry.timestamp).getTime()) {
|
|
2118
|
-
return false;
|
|
2119
|
-
}
|
|
2120
|
-
contextTokens = estimate.tokens;
|
|
2322
|
+
if (inlineReason) {
|
|
2323
|
+
const messages = filterContextExcludedMessages(this.sessionManager.buildSessionContext().messages);
|
|
2324
|
+
contextTokens = estimateContextTokens(messages).tokens;
|
|
2121
2325
|
}
|
|
2122
2326
|
else {
|
|
2123
|
-
|
|
2327
|
+
const directContextTokens = assistantMessage.usage ? calculateContextTokens(assistantMessage.usage) : 0;
|
|
2328
|
+
if (assistantMessage.stopReason !== "error" && directContextTokens !== 0) {
|
|
2329
|
+
contextTokens = directContextTokens;
|
|
2330
|
+
}
|
|
2331
|
+
else {
|
|
2332
|
+
const messages = filterContextExcludedMessages(this.agent.state.messages);
|
|
2333
|
+
const estimate = estimateContextTokens(messages);
|
|
2334
|
+
if (estimate.lastUsageIndex === null)
|
|
2335
|
+
return false; // No usage data at all
|
|
2336
|
+
// Verify the usage source is post-compaction. Kept pre-compaction messages
|
|
2337
|
+
// have stale usage reflecting the old (larger) context and would falsely
|
|
2338
|
+
// trigger compaction right after one just finished.
|
|
2339
|
+
const usageMsg = messages[estimate.lastUsageIndex];
|
|
2340
|
+
if (compactionEntry &&
|
|
2341
|
+
usageMsg.role === "assistant" &&
|
|
2342
|
+
usageMsg.timestamp <= new Date(compactionEntry.timestamp).getTime()) {
|
|
2343
|
+
return false;
|
|
2344
|
+
}
|
|
2345
|
+
contextTokens = estimate.tokens;
|
|
2346
|
+
}
|
|
2124
2347
|
}
|
|
2125
2348
|
if (shouldCompact(contextTokens, contextWindow, settings)) {
|
|
2126
|
-
if (
|
|
2127
|
-
await this._runPrePromptCompaction(assistantMessage, skipAbortedCheck);
|
|
2349
|
+
if (inlineReason) {
|
|
2350
|
+
return await this._runPrePromptCompaction(assistantMessage, skipAbortedCheck, inlineReason);
|
|
2128
2351
|
}
|
|
2129
2352
|
else {
|
|
2130
2353
|
return await this._runAutoCompaction("threshold", false);
|
|
@@ -2145,6 +2368,7 @@ export class AgentSession {
|
|
|
2145
2368
|
if (!execution.accepted && isContextOverflow(lastAssistantMessage, this.model?.contextWindow ?? 0)) {
|
|
2146
2369
|
this._overflowRecoveryAttempted = false;
|
|
2147
2370
|
}
|
|
2371
|
+
return execution.accepted;
|
|
2148
2372
|
}
|
|
2149
2373
|
catch (error) {
|
|
2150
2374
|
if (isContextOverflow(lastAssistantMessage, this.model?.contextWindow ?? 0)) {
|
|
@@ -2160,6 +2384,7 @@ export class AgentSession {
|
|
|
2160
2384
|
willRetry,
|
|
2161
2385
|
errorMessage: aborted ? undefined : `Pre-prompt compaction failed: ${errorMessage}`,
|
|
2162
2386
|
});
|
|
2387
|
+
return false;
|
|
2163
2388
|
}
|
|
2164
2389
|
finally {
|
|
2165
2390
|
this._compactionAbortController = undefined;
|
|
@@ -2477,11 +2702,55 @@ export class AgentSession {
|
|
|
2477
2702
|
void this.abort();
|
|
2478
2703
|
},
|
|
2479
2704
|
hasPendingMessages: () => this.pendingMessageCount > 0,
|
|
2705
|
+
isCompacting: () => this.isCompacting,
|
|
2480
2706
|
shutdown: () => {
|
|
2481
2707
|
this._extensionShutdownHandler?.();
|
|
2482
2708
|
},
|
|
2483
2709
|
getContextUsage: () => this.getContextUsage(),
|
|
2484
2710
|
getCompactionSettings: () => this.settingsManager.getCompactionSettings(),
|
|
2711
|
+
getLookAtSettings: () => {
|
|
2712
|
+
const global = this.settingsManager.getGlobalSettings().lookAt;
|
|
2713
|
+
const project = this.settingsManager.getProjectSettings().lookAt;
|
|
2714
|
+
return {
|
|
2715
|
+
enabled: project?.enabled ?? global?.enabled ?? true,
|
|
2716
|
+
models: project?.models ?? global?.models,
|
|
2717
|
+
};
|
|
2718
|
+
},
|
|
2719
|
+
getImageSettings: () => ({
|
|
2720
|
+
autoResize: this.settingsManager.getImageAutoResize(),
|
|
2721
|
+
blockImages: this.settingsManager.getBlockImages(),
|
|
2722
|
+
}),
|
|
2723
|
+
sessionSettings: {
|
|
2724
|
+
getRetryFallbackSettings: () => this.settingsManager.getRetryFallbackSettings(),
|
|
2725
|
+
setFallbackChain: async (key, entries) => {
|
|
2726
|
+
this.settingsManager.setFallbackChain(key, [...entries]);
|
|
2727
|
+
await this.settingsManager.flush();
|
|
2728
|
+
},
|
|
2729
|
+
removeFallbackChain: async (key) => {
|
|
2730
|
+
this.settingsManager.removeFallbackChain(key);
|
|
2731
|
+
await this.settingsManager.flush();
|
|
2732
|
+
},
|
|
2733
|
+
setModelFallbackEnabled: async (enabled) => {
|
|
2734
|
+
this.settingsManager.setModelFallbackEnabled(enabled);
|
|
2735
|
+
await this.settingsManager.flush();
|
|
2736
|
+
},
|
|
2737
|
+
setFallbackRevertPolicy: async (policy) => {
|
|
2738
|
+
this.settingsManager.setFallbackRevertPolicy(policy);
|
|
2739
|
+
await this.settingsManager.flush();
|
|
2740
|
+
},
|
|
2741
|
+
reload: () => this.settingsManager.reload(),
|
|
2742
|
+
getFallbackStatus: () => {
|
|
2743
|
+
const active = this._retryFallback.activeState;
|
|
2744
|
+
if (!active)
|
|
2745
|
+
return undefined;
|
|
2746
|
+
return {
|
|
2747
|
+
active: true,
|
|
2748
|
+
currentModel: this.model ? `${this.model.provider}/${this.model.id}` : undefined,
|
|
2749
|
+
originalSelector: active.originalSelector,
|
|
2750
|
+
pinned: active.pinned,
|
|
2751
|
+
};
|
|
2752
|
+
},
|
|
2753
|
+
},
|
|
2485
2754
|
compact: (options) => {
|
|
2486
2755
|
void (async () => {
|
|
2487
2756
|
this._disconnectFromAgent();
|
|
@@ -2553,6 +2822,10 @@ export class AgentSession {
|
|
|
2553
2822
|
},
|
|
2554
2823
|
});
|
|
2555
2824
|
}
|
|
2825
|
+
/** Fallback-chain configuration warnings calculated when this session started. */
|
|
2826
|
+
get fallbackValidationWarnings() {
|
|
2827
|
+
return this._fallbackValidationWarnings;
|
|
2828
|
+
}
|
|
2556
2829
|
_refreshToolRegistry(options) {
|
|
2557
2830
|
const previousRegistryNames = new Set(this._toolRegistry.keys());
|
|
2558
2831
|
const previousActiveToolNames = this.getActiveToolNames();
|
|
@@ -2700,16 +2973,25 @@ export class AgentSession {
|
|
|
2700
2973
|
* Context overflow errors are NOT retryable (handled by compaction instead).
|
|
2701
2974
|
*/
|
|
2702
2975
|
_isRetryableError(message) {
|
|
2703
|
-
if (!message.errorMessage)
|
|
2704
|
-
return false;
|
|
2705
2976
|
// Context overflow is handled by compaction, not retry.
|
|
2706
2977
|
if (isContextOverflow(message, this.model?.contextWindow ?? 0))
|
|
2707
2978
|
return false;
|
|
2979
|
+
if (isClassifierRefusal(message))
|
|
2980
|
+
return true;
|
|
2981
|
+
if (!message.errorMessage)
|
|
2982
|
+
return false;
|
|
2708
2983
|
if (message.stopReason === "aborted") {
|
|
2709
2984
|
return /timed? out|timeout/i.test(message.errorMessage);
|
|
2710
2985
|
}
|
|
2711
2986
|
return isRetryableAssistantError(message);
|
|
2712
2987
|
}
|
|
2988
|
+
_isHardErrorFallbackEligible(message) {
|
|
2989
|
+
return (message.stopReason === "error" &&
|
|
2990
|
+
!isContextOverflow(message, this.model?.contextWindow ?? 0) &&
|
|
2991
|
+
!isClassifierRefusal(message) &&
|
|
2992
|
+
!message.content.some((content) => content.type === "toolCall") &&
|
|
2993
|
+
this._retryFallback.canTryFallback());
|
|
2994
|
+
}
|
|
2713
2995
|
_getProviderRetryDelayMs(errorMessage) {
|
|
2714
2996
|
const retryAfterMsMatch = errorMessage.match(/\bretry[-_ ]?after[-_ ]?ms\s*[:=]\s*(\d+(?:\.\d+)?)/i);
|
|
2715
2997
|
if (retryAfterMsMatch) {
|
|
@@ -2742,7 +3024,7 @@ export class AgentSession {
|
|
|
2742
3024
|
* Handle retryable errors with exponential backoff.
|
|
2743
3025
|
* @returns true if retry was initiated, false if max retries exceeded or disabled
|
|
2744
3026
|
*/
|
|
2745
|
-
async _handleRetryableError(message) {
|
|
3027
|
+
async _handleRetryableError(message, options = {}) {
|
|
2746
3028
|
const settings = this.settingsManager.getRetrySettings();
|
|
2747
3029
|
if (!settings.enabled) {
|
|
2748
3030
|
this._resolveRetry();
|
|
@@ -2755,21 +3037,71 @@ export class AgentSession {
|
|
|
2755
3037
|
this._retryResolve = resolve;
|
|
2756
3038
|
});
|
|
2757
3039
|
}
|
|
2758
|
-
this._retryAttempt++;
|
|
2759
|
-
if (this._retryAttempt > settings.maxRetries) {
|
|
2760
|
-
// Max retries exceeded, emit final failure and reset
|
|
2761
|
-
this._emit({
|
|
2762
|
-
type: "auto_retry_end",
|
|
2763
|
-
success: false,
|
|
2764
|
-
attempt: this._retryAttempt - 1,
|
|
2765
|
-
finalError: message.errorMessage,
|
|
2766
|
-
});
|
|
2767
|
-
this._retryAttempt = 0;
|
|
2768
|
-
this._resolveRetry(); // Resolve so waitForRetry() completes
|
|
2769
|
-
return false;
|
|
2770
|
-
}
|
|
2771
3040
|
const errorMessage = message.errorMessage || "Unknown error";
|
|
2772
|
-
const
|
|
3041
|
+
const isRefusal = isClassifierRefusal(message);
|
|
3042
|
+
const hardErrorFallback = options.hardErrorFallback === true;
|
|
3043
|
+
let switchedFallback = false;
|
|
3044
|
+
if (hardErrorFallback) {
|
|
3045
|
+
// A non-retryable provider failure must never replay on the same model.
|
|
3046
|
+
switchedFallback = await this._retryFallback.tryFallback("hard-error", { errorMessage });
|
|
3047
|
+
if (!switchedFallback) {
|
|
3048
|
+
this._resolveRetry();
|
|
3049
|
+
return false;
|
|
3050
|
+
}
|
|
3051
|
+
// The fallback starts fresh; the failed model's transient attempts do not carry over.
|
|
3052
|
+
this._retryAttempt = 1;
|
|
3053
|
+
}
|
|
3054
|
+
else if (isRefusal) {
|
|
3055
|
+
// Refusals are only retried through a new chain candidate. They never use
|
|
3056
|
+
// same-model retries or the transient over-budget fallback escape hatch.
|
|
3057
|
+
if (this._retryAttempt + 1 > settings.maxRetries) {
|
|
3058
|
+
this._resolveRetry();
|
|
3059
|
+
return false;
|
|
3060
|
+
}
|
|
3061
|
+
switchedFallback = await this._retryFallback.tryFallback("refusal", {});
|
|
3062
|
+
if (!switchedFallback) {
|
|
3063
|
+
const exhaustedChainKey = this._retryFallback.exhaustedChainKey;
|
|
3064
|
+
if (exhaustedChainKey) {
|
|
3065
|
+
this._emit({ type: "retry_fallback_exhausted", chainKey: exhaustedChainKey, lastError: errorMessage });
|
|
3066
|
+
}
|
|
3067
|
+
this._resolveRetry();
|
|
3068
|
+
return false;
|
|
3069
|
+
}
|
|
3070
|
+
this._retryAttempt++;
|
|
3071
|
+
}
|
|
3072
|
+
else {
|
|
3073
|
+
this._retryAttempt++;
|
|
3074
|
+
if (this._retryAttempt > settings.maxRetries) {
|
|
3075
|
+
switchedFallback = await this._retryFallback.tryFallback("transient", {
|
|
3076
|
+
errorMessage,
|
|
3077
|
+
retryAfterMs: this._getProviderRetryDelayMs(errorMessage),
|
|
3078
|
+
});
|
|
3079
|
+
if (switchedFallback) {
|
|
3080
|
+
// The new model receives a fresh retry budget; the failed model does not.
|
|
3081
|
+
this._retryAttempt = 1;
|
|
3082
|
+
}
|
|
3083
|
+
else {
|
|
3084
|
+
const exhaustedChainKey = this._retryFallback.exhaustedChainKey;
|
|
3085
|
+
if (exhaustedChainKey) {
|
|
3086
|
+
this._emit({
|
|
3087
|
+
type: "retry_fallback_exhausted",
|
|
3088
|
+
chainKey: exhaustedChainKey,
|
|
3089
|
+
lastError: errorMessage,
|
|
3090
|
+
});
|
|
3091
|
+
}
|
|
3092
|
+
this._emit({
|
|
3093
|
+
type: "auto_retry_end",
|
|
3094
|
+
success: false,
|
|
3095
|
+
attempt: this._retryAttempt - 1,
|
|
3096
|
+
finalError: message.errorMessage,
|
|
3097
|
+
});
|
|
3098
|
+
this._retryAttempt = 0;
|
|
3099
|
+
this._resolveRetry();
|
|
3100
|
+
return false;
|
|
3101
|
+
}
|
|
3102
|
+
}
|
|
3103
|
+
}
|
|
3104
|
+
const providerDelayMs = isRefusal || hardErrorFallback ? undefined : this._getProviderRetryDelayMs(errorMessage);
|
|
2773
3105
|
const maxRetryDelayMs = this.settingsManager.getProviderRetrySettings().maxRetryDelayMs;
|
|
2774
3106
|
if (providerDelayMs !== undefined && providerDelayMs > maxRetryDelayMs) {
|
|
2775
3107
|
this._emit({
|
|
@@ -2782,7 +3114,13 @@ export class AgentSession {
|
|
|
2782
3114
|
this._resolveRetry();
|
|
2783
3115
|
return false;
|
|
2784
3116
|
}
|
|
2785
|
-
|
|
3117
|
+
if (!switchedFallback) {
|
|
3118
|
+
switchedFallback = await this._retryFallback.tryFallback("transient", {
|
|
3119
|
+
errorMessage,
|
|
3120
|
+
retryAfterMs: providerDelayMs,
|
|
3121
|
+
});
|
|
3122
|
+
}
|
|
3123
|
+
const delayMs = switchedFallback ? 0 : (providerDelayMs ?? settings.baseDelayMs * 2 ** (this._retryAttempt - 1));
|
|
2786
3124
|
// Prepare before auto_retry_start so an immediate Esc can cancel the retry sleep.
|
|
2787
3125
|
this._retryAbortController = new AbortController();
|
|
2788
3126
|
this._emit({
|
|
@@ -2818,6 +3156,9 @@ export class AgentSession {
|
|
|
2818
3156
|
return false;
|
|
2819
3157
|
}
|
|
2820
3158
|
this._retryAbortController = undefined;
|
|
3159
|
+
// Turn boundary: a suppression that expired during the backoff sleep lets
|
|
3160
|
+
// the retry continue on the restored primary instead of the fallback model.
|
|
3161
|
+
await this._maybeRestoreFallbackPrimary();
|
|
2821
3162
|
// Retry via continue() - use setTimeout to break out of event handler chain
|
|
2822
3163
|
setTimeout(() => {
|
|
2823
3164
|
this.agent.continue().catch(() => {
|