@sammorrowdrums/mcpi 0.70.8 → 0.85.0-bootstrap.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1621 -0
- package/LICENSE +21 -0
- package/README.md +196 -141
- package/dist/bun/cli.d.ts.map +1 -1
- package/dist/bun/cli.js +4 -0
- package/dist/bun/cli.js.map +1 -1
- package/dist/bun/register-bedrock.d.ts.map +1 -1
- package/dist/bun/register-bedrock.js +1 -1
- package/dist/bun/register-bedrock.js.map +1 -1
- package/dist/bun/restore-sandbox-env.d.ts +17 -0
- package/dist/bun/restore-sandbox-env.d.ts.map +1 -0
- package/dist/bun/restore-sandbox-env.js +36 -0
- package/dist/bun/restore-sandbox-env.js.map +1 -0
- package/dist/cli/args.d.ts +9 -2
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +116 -16
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/auth-check.d.ts +19 -0
- package/dist/cli/auth-check.d.ts.map +1 -0
- package/dist/cli/auth-check.js +50 -0
- package/dist/cli/auth-check.js.map +1 -0
- package/dist/cli/auth-command.d.ts +24 -0
- package/dist/cli/auth-command.d.ts.map +1 -0
- package/dist/cli/auth-command.js +103 -0
- package/dist/cli/auth-command.js.map +1 -0
- package/dist/cli/config-selector.d.ts +6 -4
- package/dist/cli/config-selector.d.ts.map +1 -1
- package/dist/cli/config-selector.js +4 -4
- package/dist/cli/config-selector.js.map +1 -1
- package/dist/cli/credential-print.d.ts +13 -0
- package/dist/cli/credential-print.d.ts.map +1 -0
- package/dist/cli/credential-print.js +76 -0
- package/dist/cli/credential-print.js.map +1 -0
- package/dist/cli/experimental/auth.d.ts +16 -0
- package/dist/cli/experimental/auth.d.ts.map +1 -0
- package/dist/cli/experimental/auth.js +13 -0
- package/dist/cli/experimental/auth.js.map +1 -0
- package/dist/cli/experimental/cli.d.ts +6 -0
- package/dist/cli/experimental/cli.d.ts.map +1 -0
- package/dist/cli/experimental/cli.js +5 -0
- package/dist/cli/experimental/cli.js.map +1 -0
- package/dist/cli/experimental/command-options.d.ts +17 -0
- package/dist/cli/experimental/command-options.d.ts.map +1 -0
- package/dist/cli/experimental/command-options.js +35 -0
- package/dist/cli/experimental/command-options.js.map +1 -0
- package/dist/cli/experimental/command.d.ts +63 -0
- package/dist/cli/experimental/command.d.ts.map +1 -0
- package/dist/cli/experimental/command.js +130 -0
- package/dist/cli/experimental/command.js.map +1 -0
- package/dist/cli/experimental/commands/client.d.ts +13 -0
- package/dist/cli/experimental/commands/client.d.ts.map +1 -0
- package/dist/cli/experimental/commands/client.js +25 -0
- package/dist/cli/experimental/commands/client.js.map +1 -0
- package/dist/cli/experimental/commands/mcpi.d.ts +15 -0
- package/dist/cli/experimental/commands/mcpi.d.ts.map +1 -0
- package/dist/cli/experimental/commands/mcpi.js +28 -0
- package/dist/cli/experimental/commands/mcpi.js.map +1 -0
- package/dist/cli/experimental/commands/server.d.ts +13 -0
- package/dist/cli/experimental/commands/server.d.ts.map +1 -0
- package/dist/cli/experimental/commands/server.js +25 -0
- package/dist/cli/experimental/commands/server.js.map +1 -0
- package/dist/cli/experimental/transport-address.d.ts +10 -0
- package/dist/cli/experimental/transport-address.d.ts.map +1 -0
- package/dist/cli/experimental/transport-address.js +38 -0
- package/dist/cli/experimental/transport-address.js.map +1 -0
- package/dist/cli/file-processor.d.ts.map +1 -1
- package/dist/cli/file-processor.js +13 -26
- package/dist/cli/file-processor.js.map +1 -1
- package/dist/cli/initial-message.d.ts +1 -1
- package/dist/cli/initial-message.d.ts.map +1 -1
- package/dist/cli/initial-message.js.map +1 -1
- package/dist/cli/list-models.d.ts +2 -2
- package/dist/cli/list-models.d.ts.map +1 -1
- package/dist/cli/list-models.js +4 -4
- package/dist/cli/list-models.js.map +1 -1
- package/dist/cli/project-trust.d.ts +10 -0
- package/dist/cli/project-trust.d.ts.map +1 -0
- package/dist/cli/project-trust.js +48 -0
- package/dist/cli/project-trust.js.map +1 -0
- package/dist/cli/session-picker.d.ts +3 -2
- package/dist/cli/session-picker.d.ts.map +1 -1
- package/dist/cli/session-picker.js +5 -4
- package/dist/cli/session-picker.js.map +1 -1
- package/dist/cli/startup-ui.d.ts +20 -0
- package/dist/cli/startup-ui.d.ts.map +1 -0
- package/dist/cli/startup-ui.js +184 -0
- package/dist/cli/startup-ui.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +6 -3
- package/dist/cli.js.map +1 -1
- package/dist/client/index.d.ts +3 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +3 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/remote-session.d.ts +53 -0
- package/dist/client/remote-session.d.ts.map +1 -0
- package/dist/client/remote-session.js +340 -0
- package/dist/client/remote-session.js.map +1 -0
- package/dist/client/transcript.d.ts +12 -0
- package/dist/client/transcript.d.ts.map +1 -0
- package/dist/client/transcript.js +98 -0
- package/dist/client/transcript.js.map +1 -0
- package/dist/config.d.ts +34 -12
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +312 -61
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts +11 -9
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +16 -7
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +13 -12
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +34 -14
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +110 -53
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +662 -488
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-guidance.d.ts.map +1 -1
- package/dist/core/auth-guidance.js.map +1 -1
- package/dist/core/auth-storage.d.ts +35 -104
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +272 -286
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/bash-executor.d.ts +1 -1
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +11 -8
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/cache-stats.d.ts +49 -0
- package/dist/core/cache-stats.d.ts.map +1 -0
- package/dist/core/cache-stats.js +101 -0
- package/dist/core/cache-stats.js.map +1 -0
- package/dist/core/compaction/branch-summarization.d.ts +16 -6
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +13 -10
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +25 -9
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +163 -133
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/compaction/index.d.ts +3 -3
- package/dist/core/compaction/index.d.ts.map +1 -1
- package/dist/core/compaction/index.js.map +1 -1
- package/dist/core/compaction/utils.d.ts +3 -3
- package/dist/core/compaction/utils.d.ts.map +1 -1
- package/dist/core/compaction/utils.js +7 -18
- package/dist/core/compaction/utils.js.map +1 -1
- package/dist/core/defaults.d.ts +1 -1
- package/dist/core/defaults.d.ts.map +1 -1
- package/dist/core/defaults.js.map +1 -1
- package/dist/core/env-overlay.d.ts +21 -0
- package/dist/core/env-overlay.d.ts.map +1 -0
- package/dist/core/env-overlay.js +25 -0
- package/dist/core/env-overlay.js.map +1 -0
- package/dist/core/exec.d.ts +8 -1
- package/dist/core/exec.d.ts.map +1 -1
- package/dist/core/exec.js +7 -1
- package/dist/core/exec.js.map +1 -1
- package/dist/core/experimental.d.ts +6 -0
- package/dist/core/experimental.d.ts.map +1 -0
- package/dist/core/experimental.js +8 -0
- package/dist/core/experimental.js.map +1 -0
- package/dist/core/export-html/ansi-to-html.d.ts.map +1 -1
- package/dist/core/export-html/ansi-to-html.js +1 -1
- package/dist/core/export-html/ansi-to-html.js.map +1 -1
- package/dist/core/export-html/index.d.ts +2 -2
- package/dist/core/export-html/index.d.ts.map +1 -1
- package/dist/core/export-html/index.js +8 -6
- package/dist/core/export-html/index.js.map +1 -1
- package/dist/core/export-html/template.css +53 -4
- package/dist/core/export-html/template.js +129 -35
- package/dist/core/export-html/tool-renderer.d.ts +2 -8
- package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
- package/dist/core/export-html/tool-renderer.js +15 -2
- package/dist/core/export-html/tool-renderer.js.map +1 -1
- package/dist/core/export-html/vendor/marked.min.js +75 -3
- package/dist/core/extensions/index.d.ts +8 -8
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader.d.ts +5 -7
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +161 -79
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +32 -12
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +194 -3
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +217 -59
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/extensions/wrapper.d.ts +3 -3
- package/dist/core/extensions/wrapper.d.ts.map +1 -1
- package/dist/core/extensions/wrapper.js +22 -3
- package/dist/core/extensions/wrapper.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +12 -0
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +30 -2
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/http-dispatcher.d.ts +22 -0
- package/dist/core/http-dispatcher.d.ts.map +1 -0
- package/dist/core/http-dispatcher.js +96 -0
- package/dist/core/http-dispatcher.js.map +1 -0
- package/dist/core/index.d.ts +9 -8
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/keybindings.d.ts +79 -10
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +11 -10
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/messages.d.ts +2 -2
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js.map +1 -1
- package/dist/core/model-config.d.ts +571 -0
- package/dist/core/model-config.d.ts.map +1 -0
- package/dist/core/model-config.js +254 -0
- package/dist/core/model-config.js.map +1 -0
- package/dist/core/model-registry.d.ts +23 -110
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +65 -616
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts +20 -7
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +139 -43
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/model-runtime.d.ts +100 -0
- package/dist/core/model-runtime.d.ts.map +1 -0
- package/dist/core/model-runtime.js +602 -0
- package/dist/core/model-runtime.js.map +1 -0
- package/dist/core/models-store.d.ts +22 -0
- package/dist/core/models-store.d.ts.map +1 -0
- package/dist/core/models-store.js +113 -0
- package/dist/core/models-store.js.map +1 -0
- package/dist/core/output-guard.d.ts +1 -0
- package/dist/core/output-guard.d.ts.map +1 -1
- package/dist/core/output-guard.js +52 -22
- package/dist/core/output-guard.js.map +1 -1
- package/dist/core/package-manager.d.ts +21 -4
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +428 -191
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/pi-manifest.d.ts +8 -0
- package/dist/core/pi-manifest.d.ts.map +1 -0
- package/dist/core/pi-manifest.js +25 -0
- package/dist/core/pi-manifest.js.map +1 -0
- package/dist/core/project-trust.d.ts +15 -0
- package/dist/core/project-trust.d.ts.map +1 -0
- package/dist/core/project-trust.js +59 -0
- package/dist/core/project-trust.js.map +1 -0
- package/dist/core/prompt-templates.d.ts +4 -2
- package/dist/core/prompt-templates.d.ts.map +1 -1
- package/dist/core/prompt-templates.js +36 -50
- package/dist/core/prompt-templates.js.map +1 -1
- package/dist/core/provider-attribution.d.ts +4 -0
- package/dist/core/provider-attribution.d.ts.map +1 -0
- package/dist/core/provider-attribution.js +72 -0
- package/dist/core/provider-attribution.js.map +1 -0
- package/dist/core/provider-composer.d.ts +58 -0
- package/dist/core/provider-composer.d.ts.map +1 -0
- package/dist/core/provider-composer.js +396 -0
- package/dist/core/provider-composer.js.map +1 -0
- package/dist/core/radius.d.ts +2 -0
- package/dist/core/radius.d.ts.map +1 -0
- package/dist/core/radius.js +2 -0
- package/dist/core/radius.js.map +1 -0
- package/dist/core/remote-catalog-provider.d.ts +17 -0
- package/dist/core/remote-catalog-provider.d.ts.map +1 -0
- package/dist/core/remote-catalog-provider.js +137 -0
- package/dist/core/remote-catalog-provider.js.map +1 -0
- package/dist/core/resolve-config-value.d.ts +13 -6
- package/dist/core/resolve-config-value.d.ts.map +1 -1
- package/dist/core/resolve-config-value.js +143 -22
- package/dist/core/resolve-config-value.js.map +1 -1
- package/dist/core/resource-loader.d.ts +40 -12
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +236 -87
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/runtime-credentials.d.ts +15 -0
- package/dist/core/runtime-credentials.d.ts.map +1 -0
- package/dist/core/runtime-credentials.js +39 -0
- package/dist/core/runtime-credentials.js.map +1 -0
- package/dist/core/sdk.d.ts +26 -25
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +56 -49
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts +42 -19
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +454 -223
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +77 -8
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +255 -67
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills.d.ts +2 -2
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +12 -34
- package/dist/core/skills.js.map +1 -1
- package/dist/core/slash-commands.d.ts +2 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +4 -3
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/source-info.d.ts +1 -1
- package/dist/core/source-info.d.ts.map +1 -1
- package/dist/core/source-info.js.map +1 -1
- package/dist/core/system-prompt.d.ts +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +15 -25
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/telemetry.d.ts +7 -1
- package/dist/core/telemetry.d.ts.map +1 -1
- package/dist/core/telemetry.js +7 -1
- package/dist/core/telemetry.js.map +1 -1
- package/dist/core/timings.d.ts +5 -3
- package/dist/core/timings.d.ts.map +1 -1
- package/dist/core/timings.js +26 -16
- package/dist/core/timings.js.map +1 -1
- package/dist/core/tools/bash.d.ts +11 -5
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +224 -185
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit-diff.d.ts +26 -5
- package/dist/core/tools/edit-diff.d.ts.map +1 -1
- package/dist/core/tools/edit-diff.js +110 -23
- package/dist/core/tools/edit-diff.js.map +1 -1
- package/dist/core/tools/edit.d.ts +11 -5
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +67 -100
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
- package/dist/core/tools/file-mutation-queue.js +27 -12
- package/dist/core/tools/file-mutation-queue.js.map +1 -1
- package/dist/core/tools/find.d.ts +10 -3
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +41 -37
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts +7 -3
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +12 -8
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/index.d.ts +18 -18
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/ls.d.ts +7 -3
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js +17 -15
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/output-accumulator.d.ts +52 -0
- package/dist/core/tools/output-accumulator.d.ts.map +1 -0
- package/dist/core/tools/output-accumulator.js +184 -0
- package/dist/core/tools/output-accumulator.js.map +1 -0
- package/dist/core/tools/path-utils.d.ts +2 -0
- package/dist/core/tools/path-utils.d.ts.map +1 -1
- package/dist/core/tools/path-utils.js +39 -21
- package/dist/core/tools/path-utils.js.map +1 -1
- package/dist/core/tools/read.d.ts +7 -3
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +101 -51
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/render-utils.d.ts +5 -2
- package/dist/core/tools/render-utils.d.ts.map +1 -1
- package/dist/core/tools/render-utils.js +18 -2
- package/dist/core/tools/render-utils.js.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.d.ts +2 -2
- package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.js +3 -3
- package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
- package/dist/core/tools/truncate.d.ts.map +1 -1
- package/dist/core/tools/truncate.js +12 -2
- package/dist/core/tools/truncate.js.map +1 -1
- package/dist/core/tools/write.d.ts +6 -2
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +35 -45
- package/dist/core/tools/write.js.map +1 -1
- package/dist/core/trust-manager.d.ts +36 -0
- package/dist/core/trust-manager.d.ts.map +1 -0
- package/dist/core/trust-manager.js +202 -0
- package/dist/core/trust-manager.js.map +1 -0
- package/dist/core/usage-totals.d.ts +19 -0
- package/dist/core/usage-totals.d.ts.map +1 -0
- package/dist/core/usage-totals.js +52 -0
- package/dist/core/usage-totals.js.map +1 -0
- package/dist/extensions/index.d.ts +3 -0
- package/dist/extensions/index.d.ts.map +1 -0
- package/dist/extensions/index.js +3 -0
- package/dist/extensions/index.js.map +1 -0
- package/dist/extensions/llama/client.d.ts +61 -0
- package/dist/extensions/llama/client.d.ts.map +1 -0
- package/dist/extensions/llama/client.js +302 -0
- package/dist/extensions/llama/client.js.map +1 -0
- package/dist/extensions/llama/huggingface.d.ts +23 -0
- package/dist/extensions/llama/huggingface.d.ts.map +1 -0
- package/dist/extensions/llama/huggingface.js +141 -0
- package/dist/extensions/llama/huggingface.js.map +1 -0
- package/dist/extensions/llama/index.d.ts +3 -0
- package/dist/extensions/llama/index.d.ts.map +1 -0
- package/dist/extensions/llama/index.js +217 -0
- package/dist/extensions/llama/index.js.map +1 -0
- package/dist/extensions/llama/provider.d.ts +10 -0
- package/dist/extensions/llama/provider.d.ts.map +1 -0
- package/dist/extensions/llama/provider.js +121 -0
- package/dist/extensions/llama/provider.js.map +1 -0
- package/dist/extensions/llama/ui.d.ts +42 -0
- package/dist/extensions/llama/ui.d.ts.map +1 -0
- package/dist/extensions/llama/ui.js +416 -0
- package/dist/extensions/llama/ui.js.map +1 -0
- package/dist/index.d.ts +34 -27
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -5
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts +2 -2
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +311 -101
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts +5 -5
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +10 -10
- package/dist/migrations.js.map +1 -1
- package/dist/modes/index.d.ts +6 -5
- package/dist/modes/index.d.ts.map +1 -1
- package/dist/modes/index.js.map +1 -1
- package/dist/modes/interactive/components/armin.d.ts +1 -1
- package/dist/modes/interactive/components/armin.d.ts.map +1 -1
- package/dist/modes/interactive/components/armin.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts +8 -3
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +55 -26
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts +2 -2
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +4 -4
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.d.ts +2 -2
- package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.js +1 -1
- package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts +2 -2
- package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts +2 -2
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/config-selector.d.ts +37 -6
- package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/config-selector.js +318 -34
- package/dist/modes/interactive/components/config-selector.js.map +1 -1
- package/dist/modes/interactive/components/countdown-timer.d.ts +3 -3
- package/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -1
- package/dist/modes/interactive/components/countdown-timer.js +2 -2
- package/dist/modes/interactive/components/countdown-timer.js.map +1 -1
- package/dist/modes/interactive/components/custom-editor.d.ts +2 -2
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-editor.js +9 -2
- package/dist/modes/interactive/components/custom-editor.js.map +1 -1
- package/dist/modes/interactive/components/custom-entry.d.ts +19 -0
- package/dist/modes/interactive/components/custom-entry.d.ts.map +1 -0
- package/dist/modes/interactive/components/custom-entry.js +52 -0
- package/dist/modes/interactive/components/custom-entry.js.map +1 -0
- package/dist/modes/interactive/components/custom-message.d.ts +6 -4
- package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-message.js +11 -3
- package/dist/modes/interactive/components/custom-message.js.map +1 -1
- package/dist/modes/interactive/components/daxnuts.d.ts +1 -1
- package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -1
- package/dist/modes/interactive/components/daxnuts.js.map +1 -1
- package/dist/modes/interactive/components/diff.d.ts.map +1 -1
- package/dist/modes/interactive/components/diff.js.map +1 -1
- package/dist/modes/interactive/components/dynamic-border.d.ts +1 -1
- package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
- package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
- package/dist/modes/interactive/components/extension-editor.d.ts +5 -4
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-editor.js +19 -32
- package/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/dist/modes/interactive/components/extension-input.d.ts +1 -1
- package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-input.js +1 -1
- package/dist/modes/interactive/components/extension-input.js.map +1 -1
- package/dist/modes/interactive/components/extension-selector.d.ts +3 -1
- package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-selector.js +7 -2
- package/dist/modes/interactive/components/extension-selector.js.map +1 -1
- package/dist/modes/interactive/components/first-time-setup.d.ts +25 -0
- package/dist/modes/interactive/components/first-time-setup.d.ts.map +1 -0
- package/dist/modes/interactive/components/first-time-setup.js +103 -0
- package/dist/modes/interactive/components/first-time-setup.js.map +1 -0
- package/dist/modes/interactive/components/footer.d.ts +9 -4
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +52 -31
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/index.d.ts +33 -31
- package/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/dist/modes/interactive/components/index.js +2 -0
- package/dist/modes/interactive/components/index.js.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.d.ts +6 -1
- package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.js +20 -6
- package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
- package/dist/modes/interactive/components/login-dialog.d.ts +12 -6
- package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/dist/modes/interactive/components/login-dialog.js +46 -17
- package/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/dist/modes/interactive/components/markdown-transform.d.ts +3 -0
- package/dist/modes/interactive/components/markdown-transform.d.ts.map +1 -0
- package/dist/modes/interactive/components/markdown-transform.js +19 -0
- package/dist/modes/interactive/components/markdown-transform.js.map +1 -0
- package/dist/modes/interactive/components/mermaid.d.ts +11 -0
- package/dist/modes/interactive/components/mermaid.d.ts.map +1 -0
- package/dist/modes/interactive/components/mermaid.js +75 -0
- package/dist/modes/interactive/components/mermaid.js.map +1 -0
- package/dist/modes/interactive/components/model-selector.d.ts +13 -6
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +92 -44
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.d.ts +7 -4
- package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.js +32 -28
- package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts +5 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +52 -14
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/components/session-selector-search.d.ts +1 -1
- package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector-search.js +1 -1
- package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts +4 -5
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +18 -16
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +23 -2
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +322 -22
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/show-images-selector.d.ts +1 -1
- package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/show-images-selector.js +1 -1
- package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.d.ts +2 -2
- package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.js +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
- package/dist/modes/interactive/components/status-indicator.d.ts +28 -0
- package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -0
- package/dist/modes/interactive/components/status-indicator.js +60 -0
- package/dist/modes/interactive/components/status-indicator.js.map +1 -0
- package/dist/modes/interactive/components/theme-selector.d.ts +1 -1
- package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/theme-selector.js +1 -1
- package/dist/modes/interactive/components/theme-selector.js.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.d.ts +2 -2
- package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.js +3 -2
- package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +2 -2
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +33 -2
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector.d.ts +7 -2
- package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector.js +179 -26
- package/dist/modes/interactive/components/tree-selector.js.map +1 -1
- package/dist/modes/interactive/components/trust-selector.d.ts +23 -0
- package/dist/modes/interactive/components/trust-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/trust-selector.js +91 -0
- package/dist/modes/interactive/components/trust-selector.js.map +1 -0
- package/dist/modes/interactive/components/user-message-selector.d.ts +1 -1
- package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message-selector.js +1 -1
- package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message.d.ts +9 -3
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message.js +26 -6
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -1
- package/dist/modes/interactive/components/visual-truncate.js +1 -1
- package/dist/modes/interactive/components/visual-truncate.js.map +1 -1
- package/dist/modes/interactive/external-editor.d.ts +12 -0
- package/dist/modes/interactive/external-editor.d.ts.map +1 -0
- package/dist/modes/interactive/external-editor.js +37 -0
- package/dist/modes/interactive/external-editor.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts +104 -26
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +1565 -692
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/model-catalog-refresh.d.ts +7 -0
- package/dist/modes/interactive/model-catalog-refresh.d.ts.map +1 -0
- package/dist/modes/interactive/model-catalog-refresh.js +34 -0
- package/dist/modes/interactive/model-catalog-refresh.js.map +1 -0
- package/dist/modes/interactive/model-search.d.ts +12 -0
- package/dist/modes/interactive/model-search.d.ts.map +1 -0
- package/dist/modes/interactive/model-search.js +15 -0
- package/dist/modes/interactive/model-search.js.map +1 -0
- package/dist/modes/interactive/theme/dark.json +10 -5
- package/dist/modes/interactive/theme/light.json +10 -5
- package/dist/modes/interactive/theme/theme-controller.d.ts +40 -0
- package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -0
- package/dist/modes/interactive/theme/theme-controller.js +125 -0
- package/dist/modes/interactive/theme/theme-controller.js.map +1 -0
- package/dist/modes/interactive/theme/theme-schema.json +22 -5
- package/dist/modes/interactive/theme/theme.d.ts +48 -7
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +194 -76
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/json-event.d.ts +31 -0
- package/dist/modes/json-event.d.ts.map +1 -0
- package/dist/modes/json-event.js +15 -0
- package/dist/modes/json-event.js.map +1 -0
- package/dist/modes/print-mode.d.ts +3 -3
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +16 -5
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +33 -10
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +89 -11
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts +2 -2
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +69 -9
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +43 -5
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/package-manager-cli.d.ts +6 -2
- package/dist/package-manager-cli.d.ts.map +1 -1
- package/dist/package-manager-cli.js +527 -25
- package/dist/package-manager-cli.js.map +1 -1
- package/dist/path-migration.d.ts +13 -0
- package/dist/path-migration.d.ts.map +1 -0
- package/dist/path-migration.js +52 -0
- package/dist/path-migration.js.map +1 -0
- package/dist/rpc-entry.d.ts +3 -0
- package/dist/rpc-entry.d.ts.map +1 -0
- package/dist/rpc-entry.js +11 -0
- package/dist/rpc-entry.js.map +1 -0
- package/dist/server/create-harness.d.ts +26 -0
- package/dist/server/create-harness.d.ts.map +1 -0
- package/dist/server/create-harness.js +106 -0
- package/dist/server/create-harness.js.map +1 -0
- package/dist/utils/abort.d.ts +5 -0
- package/dist/utils/abort.d.ts.map +1 -0
- package/dist/utils/abort.js +48 -0
- package/dist/utils/abort.js.map +1 -0
- package/dist/utils/ansi.d.ts +2 -0
- package/dist/utils/ansi.d.ts.map +1 -0
- package/dist/utils/ansi.js +52 -0
- package/dist/utils/ansi.js.map +1 -0
- package/dist/utils/changelog.d.ts +2 -1
- package/dist/utils/changelog.d.ts.map +1 -1
- package/dist/utils/changelog.js +85 -0
- package/dist/utils/changelog.js.map +1 -1
- package/dist/utils/child-process.d.ts +12 -5
- package/dist/utils/child-process.d.ts.map +1 -1
- package/dist/utils/child-process.js +33 -5
- package/dist/utils/child-process.js.map +1 -1
- package/dist/utils/clipboard-image.d.ts.map +1 -1
- package/dist/utils/clipboard-image.js +4 -4
- package/dist/utils/clipboard-image.js.map +1 -1
- package/dist/utils/clipboard-native.d.ts +4 -1
- package/dist/utils/clipboard-native.d.ts.map +1 -1
- package/dist/utils/clipboard-native.js +14 -8
- package/dist/utils/clipboard-native.js.map +1 -1
- package/dist/utils/clipboard.d.ts +2 -0
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js +129 -46
- package/dist/utils/clipboard.js.map +1 -1
- package/dist/utils/deprecation.d.ts +4 -0
- package/dist/utils/deprecation.d.ts.map +1 -0
- package/dist/utils/deprecation.js +13 -0
- package/dist/utils/deprecation.js.map +1 -0
- package/dist/utils/exif-orientation.d.ts +1 -1
- package/dist/utils/exif-orientation.d.ts.map +1 -1
- package/dist/utils/exif-orientation.js.map +1 -1
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js +54 -22
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/html.d.ts +7 -0
- package/dist/utils/html.d.ts.map +1 -0
- package/dist/utils/html.js +40 -0
- package/dist/utils/html.js.map +1 -0
- package/dist/utils/image-convert.d.ts +1 -0
- package/dist/utils/image-convert.d.ts.map +1 -1
- package/dist/utils/image-convert.js +21 -15
- package/dist/utils/image-convert.js.map +1 -1
- package/dist/utils/image-process.d.ts +18 -0
- package/dist/utils/image-process.d.ts.map +1 -0
- package/dist/utils/image-process.js +83 -0
- package/dist/utils/image-process.js.map +1 -0
- package/dist/utils/image-resize-core.d.ts +30 -0
- package/dist/utils/image-resize-core.d.ts.map +1 -0
- package/dist/utils/image-resize-core.js +124 -0
- package/dist/utils/image-resize-core.js.map +1 -0
- package/dist/utils/image-resize-worker.d.ts +2 -0
- package/dist/utils/image-resize-worker.d.ts.map +1 -0
- package/dist/utils/image-resize-worker.js +31 -0
- package/dist/utils/image-resize-worker.js.map +1 -0
- package/dist/utils/image-resize.d.ts +7 -27
- package/dist/utils/image-resize.d.ts.map +1 -1
- package/dist/utils/image-resize.js +75 -115
- package/dist/utils/image-resize.js.map +1 -1
- package/dist/utils/json.d.ts +3 -0
- package/dist/utils/json.d.ts.map +1 -0
- package/dist/utils/json.js +7 -0
- package/dist/utils/json.js.map +1 -0
- package/dist/utils/management-http.d.ts +23 -0
- package/dist/utils/management-http.d.ts.map +1 -0
- package/dist/utils/management-http.js +50 -0
- package/dist/utils/management-http.js.map +1 -0
- package/dist/utils/mime.d.ts +1 -0
- package/dist/utils/mime.d.ts.map +1 -1
- package/dist/utils/mime.js +100 -16
- package/dist/utils/mime.js.map +1 -1
- package/dist/utils/open-browser.d.ts +9 -0
- package/dist/utils/open-browser.d.ts.map +1 -0
- package/dist/utils/open-browser.js +22 -0
- package/dist/utils/open-browser.js.map +1 -0
- package/dist/utils/paths.d.ts +28 -1
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +97 -2
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/pi-user-agent.d.ts +2 -0
- package/dist/utils/pi-user-agent.d.ts.map +1 -0
- package/dist/utils/pi-user-agent.js +5 -0
- package/dist/utils/pi-user-agent.js.map +1 -0
- package/dist/utils/shell.d.ts +1 -0
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/shell.js +18 -6
- package/dist/utils/shell.js.map +1 -1
- package/dist/utils/syntax-highlight.d.ts +12 -0
- package/dist/utils/syntax-highlight.d.ts.map +1 -0
- package/dist/utils/syntax-highlight.js +118 -0
- package/dist/utils/syntax-highlight.js.map +1 -0
- package/dist/utils/tool-result-images.d.ts +19 -0
- package/dist/utils/tool-result-images.d.ts.map +1 -0
- package/dist/utils/tool-result-images.js +45 -0
- package/dist/utils/tool-result-images.js.map +1 -0
- package/dist/utils/tools-manager.d.ts +10 -1
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +105 -36
- package/dist/utils/tools-manager.js.map +1 -1
- package/dist/utils/version-check.d.ts +19 -0
- package/dist/utils/version-check.d.ts.map +1 -0
- package/dist/utils/version-check.js +85 -0
- package/dist/utils/version-check.js.map +1 -0
- package/dist/utils/windows-self-update.d.ts +3 -0
- package/dist/utils/windows-self-update.d.ts.map +1 -0
- package/dist/utils/windows-self-update.js +77 -0
- package/dist/utils/windows-self-update.js.map +1 -0
- package/docs/compaction.md +39 -32
- package/docs/containerization.md +113 -0
- package/docs/custom-provider.md +212 -75
- package/docs/development.md +9 -9
- package/docs/docs.json +156 -0
- package/docs/environment-variables.md +186 -0
- package/docs/extensions.md +652 -140
- package/docs/index.md +81 -0
- package/docs/json.md +26 -15
- package/docs/keybindings.md +60 -21
- package/docs/llama-cpp.md +99 -0
- package/docs/models.md +168 -34
- package/docs/packages.md +46 -36
- package/docs/prompt-templates.md +13 -5
- package/docs/providers.md +147 -26
- package/docs/quickstart.md +167 -0
- package/docs/rpc.md +218 -36
- package/docs/sdk.md +190 -125
- package/docs/security.md +59 -0
- package/docs/{session.md → session-format.md} +48 -22
- package/docs/sessions.md +145 -0
- package/docs/settings.md +130 -25
- package/docs/shell-aliases.md +2 -2
- package/docs/skills.md +13 -14
- package/docs/terminal-setup.md +73 -16
- package/docs/termux.md +10 -10
- package/docs/themes.md +41 -16
- package/docs/tmux.md +6 -4
- package/docs/tui.md +85 -61
- package/docs/usage.md +302 -0
- package/docs/windows.md +2 -2
- package/examples/README.md +1 -1
- package/examples/extensions/README.md +12 -9
- package/examples/extensions/bash-spawn-hook.ts +2 -2
- package/examples/extensions/border-status-editor.ts +145 -0
- package/examples/extensions/built-in-tool-renderer.ts +2 -2
- package/examples/extensions/claude-rules.ts +1 -1
- package/examples/extensions/commands.ts +1 -1
- package/examples/extensions/custom-compaction.ts +6 -16
- package/examples/extensions/custom-footer.ts +1 -1
- package/examples/extensions/custom-header.ts +7 -7
- package/examples/extensions/custom-provider-anthropic/index.ts +15 -8
- package/examples/extensions/custom-provider-anthropic/package-lock.json +4 -4
- package/examples/extensions/custom-provider-anthropic/package.json +3 -3
- package/examples/extensions/custom-provider-gitlab-duo/index.ts +65 -9
- package/examples/extensions/custom-provider-gitlab-duo/package.json +2 -2
- package/examples/extensions/custom-provider-gitlab-duo/test.ts +2 -2
- package/examples/extensions/doom-overlay/README.md +1 -1
- package/examples/extensions/doom-overlay/doom-component.ts +4 -4
- package/examples/extensions/doom-overlay/doom-keys.ts +1 -1
- package/examples/extensions/doom-overlay/index.ts +5 -5
- package/examples/extensions/doom-overlay/wad-finder.ts +7 -3
- package/examples/extensions/dynamic-resources/dynamic.json +1 -1
- package/examples/extensions/entry-renderer.ts +41 -0
- package/examples/extensions/git-merge-and-resolve.ts +115 -0
- package/examples/extensions/github-issue-autocomplete.ts +2 -2
- package/examples/extensions/gondolin/index.ts +531 -0
- package/examples/extensions/gondolin/package-lock.json +185 -0
- package/examples/extensions/gondolin/package.json +19 -0
- package/examples/extensions/handoff.ts +50 -14
- package/examples/extensions/hidden-thinking-label.ts +1 -1
- package/examples/extensions/inline-bash.ts +2 -2
- package/examples/extensions/input-transform-streaming.ts +39 -0
- package/examples/extensions/input-transform.ts +2 -2
- package/examples/extensions/interactive-shell.ts +2 -2
- package/examples/extensions/kimi-deferred-tools.ts +61 -0
- package/examples/extensions/mac-system-theme.ts +2 -2
- package/examples/extensions/message-renderer.ts +3 -3
- package/examples/extensions/minimal-mode.ts +2 -2
- package/examples/extensions/modal-editor.ts +2 -2
- package/examples/extensions/model-status.ts +1 -1
- package/examples/extensions/notify.ts +3 -3
- package/examples/extensions/overlay-qa-tests.ts +242 -140
- package/examples/extensions/overlay-test.ts +9 -6
- package/examples/extensions/pirate.ts +1 -1
- package/examples/extensions/plan-mode/README.md +3 -2
- package/examples/extensions/plan-mode/index.ts +90 -40
- package/examples/extensions/preset.ts +16 -10
- package/examples/extensions/project-trust.ts +64 -0
- package/examples/extensions/prompt-customizer.ts +1 -1
- package/examples/extensions/provider-payload.ts +5 -5
- package/examples/extensions/qna.ts +4 -8
- package/examples/extensions/question.ts +41 -19
- package/examples/extensions/questionnaire.ts +50 -29
- package/examples/extensions/rainbow-editor.ts +1 -1
- package/examples/extensions/reload-runtime.ts +2 -2
- package/examples/extensions/rpc-demo.ts +1 -1
- package/examples/extensions/sandbox/index.ts +9 -9
- package/examples/extensions/sandbox/package-lock.json +7 -7
- package/examples/extensions/sandbox/package.json +3 -3
- package/examples/extensions/shutdown-command.ts +5 -5
- package/examples/extensions/snake.ts +2 -2
- package/examples/extensions/space-invaders.ts +2 -2
- package/examples/extensions/ssh.ts +2 -2
- package/examples/extensions/structured-output.ts +1 -1
- package/examples/extensions/subagent/README.md +18 -13
- package/examples/extensions/subagent/agents.ts +42 -11
- package/examples/extensions/subagent/index.ts +76 -30
- package/examples/extensions/summarize.ts +12 -19
- package/examples/extensions/tic-tac-toe.ts +2 -2
- package/examples/extensions/titlebar-spinner.ts +3 -3
- package/examples/extensions/todo.ts +2 -2
- package/examples/extensions/tool-override.ts +1 -1
- package/examples/extensions/tools.ts +7 -2
- package/examples/extensions/truncated-tool.ts +2 -2
- package/examples/extensions/with-deps/package-lock.json +4 -4
- package/examples/extensions/with-deps/package.json +4 -4
- package/examples/extensions/working-indicator.ts +4 -4
- package/examples/extensions/working-message-test.ts +1 -1
- package/examples/rpc-extension-ui.ts +11 -2
- package/examples/sdk/01-minimal.ts +15 -11
- package/examples/sdk/02-custom-model.ts +18 -18
- package/examples/sdk/03-custom-prompt.ts +25 -17
- package/examples/sdk/04-skills.ts +3 -3
- package/examples/sdk/05-tools.ts +8 -4
- package/examples/sdk/06-extensions.ts +13 -9
- package/examples/sdk/07-context-files.ts +2 -2
- package/examples/sdk/08-prompt-templates.ts +3 -3
- package/examples/sdk/09-api-keys-and-oauth.ts +19 -33
- package/examples/sdk/10-settings.ts +4 -4
- package/examples/sdk/11-sessions.ts +4 -0
- package/examples/sdk/12-full-control.ts +22 -21
- package/examples/sdk/README.md +23 -30
- package/npm-shrinkwrap.json +1818 -0
- package/package.json +117 -99
- package/dist/modes/interactive/assets/clankolas.png +0 -0
- package/dist/modes/interactive/components/auth-selector-status.d.ts +0 -20
- package/dist/modes/interactive/components/auth-selector-status.d.ts.map +0 -1
- package/dist/modes/interactive/components/auth-selector-status.js +0 -23
- package/dist/modes/interactive/components/auth-selector-status.js.map +0 -1
- package/dist/modes/interactive/components/earendil-announcement.d.ts +0 -5
- package/dist/modes/interactive/components/earendil-announcement.d.ts.map +0 -1
- package/dist/modes/interactive/components/earendil-announcement.js +0 -40
- package/dist/modes/interactive/components/earendil-announcement.js.map +0 -1
- package/docs/images/exy.png +0 -0
- package/docs/tree.md +0 -233
- package/examples/extensions/antigravity-image-gen.ts +0 -418
- package/examples/extensions/custom-provider-qwen-cli/index.ts +0 -345
- package/examples/extensions/custom-provider-qwen-cli/package.json +0 -16
|
@@ -13,19 +13,24 @@
|
|
|
13
13
|
* Modes use this class and add their own I/O layer on top.
|
|
14
14
|
*/
|
|
15
15
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
16
|
-
import { basename, dirname
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
16
|
+
import { basename, dirname } from "node:path";
|
|
17
|
+
import { contentText } from "@sammorrowdrums/mcpi-ai";
|
|
18
|
+
import { clampThinkingLevel, cleanupSessionResources, getSupportedThinkingLevels, isContextOverflow, isRecoverableLength, isRetryableAssistantError, modelsAreEqual, resetApiProviders, streamSimple, } from "@sammorrowdrums/mcpi-ai/compat";
|
|
19
|
+
import { getThemeByName, theme } from "../modes/interactive/theme/theme.js";
|
|
19
20
|
import { stripFrontmatter } from "../utils/frontmatter.js";
|
|
21
|
+
import { resolvePath } from "../utils/paths.js";
|
|
20
22
|
import { sleep } from "../utils/sleep.js";
|
|
23
|
+
import { normalizeToolResultImages } from "../utils/tool-result-images.js";
|
|
21
24
|
import { formatNoApiKeyFoundMessage, formatNoModelSelectedMessage } from "./auth-guidance.js";
|
|
22
25
|
import { executeBashWithOperations } from "./bash-executor.js";
|
|
23
|
-
import { calculateContextTokens, collectEntriesForBranchSummary, compact, estimateContextTokens, generateBranchSummary, prepareCompaction, shouldCompact, } from "./compaction/index.js";
|
|
26
|
+
import { calculateContextTokens, collectEntriesForBranchSummary, compact, estimateContextTokens, estimateTokens, generateBranchSummary, prepareCompaction, shouldCompact, } from "./compaction/index.js";
|
|
24
27
|
import { DEFAULT_THINKING_LEVEL } from "./defaults.js";
|
|
28
|
+
import { applyEnvOverlay } from "./env-overlay.js";
|
|
25
29
|
import { exportSessionToHtml } from "./export-html/index.js";
|
|
26
30
|
import { createToolHtmlRenderer } from "./export-html/tool-renderer.js";
|
|
27
31
|
import { ExtensionRunner, wrapRegisteredTools, } from "./extensions/index.js";
|
|
28
32
|
import { emitSessionShutdownEvent } from "./extensions/runner.js";
|
|
33
|
+
import { ModelRegistry } from "./model-registry.js";
|
|
29
34
|
import { expandPromptTemplate } from "./prompt-templates.js";
|
|
30
35
|
import { CURRENT_SESSION_VERSION, getLatestCompactionEntry } from "./session-manager.js";
|
|
31
36
|
import { createSyntheticSourceInfo } from "./source-info.js";
|
|
@@ -33,6 +38,7 @@ import { buildSystemPrompt } from "./system-prompt.js";
|
|
|
33
38
|
import { createLocalBashOperations } from "./tools/bash.js";
|
|
34
39
|
import { createAllToolDefinitions } from "./tools/index.js";
|
|
35
40
|
import { createToolDefinitionFromAgentTool } from "./tools/tool-definition-wrapper.js";
|
|
41
|
+
import { addUsageToTotals, createUsageTotals } from "./usage-totals.js";
|
|
36
42
|
/**
|
|
37
43
|
* Parse a skill block from message text.
|
|
38
44
|
* Returns null if the text doesn't contain a skill block.
|
|
@@ -49,12 +55,25 @@ export function parseSkillBlock(text) {
|
|
|
49
55
|
};
|
|
50
56
|
}
|
|
51
57
|
// ============================================================================
|
|
58
|
+
// Types
|
|
59
|
+
// ============================================================================
|
|
60
|
+
function withoutDeletedHeaders(headers) {
|
|
61
|
+
return headers
|
|
62
|
+
? Object.fromEntries(Object.entries(headers).filter((entry) => entry[1] !== null))
|
|
63
|
+
: undefined;
|
|
64
|
+
}
|
|
65
|
+
function estimateMessagesTokens(messages) {
|
|
66
|
+
let tokens = 0;
|
|
67
|
+
for (const message of messages) {
|
|
68
|
+
tokens += estimateTokens(message);
|
|
69
|
+
}
|
|
70
|
+
return tokens;
|
|
71
|
+
}
|
|
72
|
+
// ============================================================================
|
|
52
73
|
// Constants
|
|
53
74
|
// ============================================================================
|
|
54
75
|
/** Standard thinking levels */
|
|
55
76
|
const THINKING_LEVELS = ["off", "minimal", "low", "medium", "high"];
|
|
56
|
-
/** Thinking levels including xhigh (for supported models) */
|
|
57
|
-
const THINKING_LEVELS_WITH_XHIGH = ["off", "minimal", "low", "medium", "high", "xhigh"];
|
|
58
77
|
// ============================================================================
|
|
59
78
|
// AgentSession Class
|
|
60
79
|
// ============================================================================
|
|
@@ -66,7 +85,9 @@ export class AgentSession {
|
|
|
66
85
|
// Event subscription state
|
|
67
86
|
_unsubscribeAgent;
|
|
68
87
|
_eventListeners = [];
|
|
69
|
-
|
|
88
|
+
_isAgentRunActive = false;
|
|
89
|
+
_idleWaitPromise;
|
|
90
|
+
_resolveIdleWait;
|
|
70
91
|
/** Tracks pending steering messages for UI display. Removed when delivered. */
|
|
71
92
|
_steeringMessages = [];
|
|
72
93
|
/** Tracks pending follow-up messages for UI display. Removed when delivered. */
|
|
@@ -82,10 +103,8 @@ export class AgentSession {
|
|
|
82
103
|
// Retry state
|
|
83
104
|
_retryAbortController = undefined;
|
|
84
105
|
_retryAttempt = 0;
|
|
85
|
-
_retryPromise = undefined;
|
|
86
|
-
_retryResolve = undefined;
|
|
87
106
|
// Bash execution state
|
|
88
|
-
|
|
107
|
+
_bashAbortControllers = new Set();
|
|
89
108
|
_pendingBashMessages = [];
|
|
90
109
|
// Extension system
|
|
91
110
|
_extensionRunner;
|
|
@@ -97,15 +116,17 @@ export class AgentSession {
|
|
|
97
116
|
_extensionRunnerRef;
|
|
98
117
|
_initialActiveToolNames;
|
|
99
118
|
_allowedToolNames;
|
|
119
|
+
_excludedToolNames;
|
|
100
120
|
_baseToolsOverride;
|
|
101
121
|
_sessionStartEvent;
|
|
102
122
|
_extensionUIContext;
|
|
123
|
+
_extensionMode = "print";
|
|
103
124
|
_extensionCommandContextActions;
|
|
125
|
+
_extensionAbortHandler;
|
|
104
126
|
_extensionShutdownHandler;
|
|
105
127
|
_extensionErrorListener;
|
|
106
128
|
_extensionErrorUnsubscriber;
|
|
107
|
-
|
|
108
|
-
_modelRegistry;
|
|
129
|
+
_modelRuntime;
|
|
109
130
|
// Tool registry for extension getTools/setTools
|
|
110
131
|
_toolRegistry = new Map();
|
|
111
132
|
_toolDefinitions = new Map();
|
|
@@ -114,6 +135,7 @@ export class AgentSession {
|
|
|
114
135
|
// Base system prompt (without extension appends) - used to apply fresh appends each turn
|
|
115
136
|
_baseSystemPrompt = "";
|
|
116
137
|
_baseSystemPromptOptions;
|
|
138
|
+
_systemPromptOverride;
|
|
117
139
|
constructor(config) {
|
|
118
140
|
this.agent = config.agent;
|
|
119
141
|
this.sessionManager = config.sessionManager;
|
|
@@ -122,37 +144,48 @@ export class AgentSession {
|
|
|
122
144
|
this._resourceLoader = config.resourceLoader;
|
|
123
145
|
this._customTools = config.customTools ?? [];
|
|
124
146
|
this._cwd = config.cwd;
|
|
125
|
-
this.
|
|
147
|
+
this._modelRuntime = config.modelRuntime;
|
|
126
148
|
this._extensionRunnerRef = config.extensionRunnerRef;
|
|
127
149
|
this._initialActiveToolNames = config.initialActiveToolNames;
|
|
128
150
|
this._allowedToolNames = config.allowedToolNames ? new Set(config.allowedToolNames) : undefined;
|
|
151
|
+
this._excludedToolNames = config.excludedToolNames ? new Set(config.excludedToolNames) : undefined;
|
|
129
152
|
this._baseToolsOverride = config.baseToolsOverride;
|
|
130
153
|
this._sessionStartEvent = config.sessionStartEvent ?? { type: "session_start", reason: "startup" };
|
|
131
154
|
// Always subscribe to agent events for internal handling
|
|
132
155
|
// (session persistence, extensions, auto-compaction, retry logic)
|
|
133
156
|
this._unsubscribeAgent = this.agent.subscribe(this._handleAgentEvent);
|
|
134
157
|
this._installAgentToolHooks();
|
|
158
|
+
this._installAgentNextTurnRefresh();
|
|
135
159
|
this._buildRuntime({
|
|
136
160
|
activeToolNames: this._initialActiveToolNames,
|
|
137
161
|
includeAllExtensionTools: true,
|
|
138
162
|
});
|
|
139
163
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
return this._modelRegistry;
|
|
164
|
+
get modelRuntime() {
|
|
165
|
+
return this._modelRuntime;
|
|
143
166
|
}
|
|
144
167
|
async _getRequiredRequestAuth(model) {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
168
|
+
let result;
|
|
169
|
+
try {
|
|
170
|
+
result = await this._modelRuntime.getAuth(model);
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
const cause = error instanceof Error ? error.cause : undefined;
|
|
174
|
+
if (cause instanceof Error && cause.message === "authHeader requires a resolved API key") {
|
|
148
175
|
throw new Error(formatNoApiKeyFoundMessage(model.provider));
|
|
149
176
|
}
|
|
150
|
-
throw
|
|
177
|
+
throw error;
|
|
151
178
|
}
|
|
152
|
-
if (result.apiKey) {
|
|
153
|
-
|
|
179
|
+
if (result && (result.auth.apiKey || result.auth.headers)) {
|
|
180
|
+
const requestModel = result.auth.baseUrl ? { ...model, baseUrl: result.auth.baseUrl } : model;
|
|
181
|
+
return {
|
|
182
|
+
model: requestModel,
|
|
183
|
+
apiKey: result.auth.apiKey,
|
|
184
|
+
headers: withoutDeletedHeaders(result.auth.headers),
|
|
185
|
+
env: result.env,
|
|
186
|
+
};
|
|
154
187
|
}
|
|
155
|
-
const isOAuth = this.
|
|
188
|
+
const isOAuth = this._modelRuntime.isUsingOAuth(model.provider);
|
|
156
189
|
if (isOAuth) {
|
|
157
190
|
throw new Error(`Authentication failed for "${model.provider}". ` +
|
|
158
191
|
`Credentials may have expired or network is unavailable. ` +
|
|
@@ -160,6 +193,26 @@ export class AgentSession {
|
|
|
160
193
|
}
|
|
161
194
|
throw new Error(formatNoApiKeyFoundMessage(model.provider));
|
|
162
195
|
}
|
|
196
|
+
async _getSummarizationRequestAuth(model) {
|
|
197
|
+
if (this.agent.streamFunction === streamSimple) {
|
|
198
|
+
return this._getRequiredRequestAuth(model);
|
|
199
|
+
}
|
|
200
|
+
try {
|
|
201
|
+
const result = await this._modelRuntime.getAuth(model);
|
|
202
|
+
if (!result)
|
|
203
|
+
return { model };
|
|
204
|
+
const requestModel = result.auth.baseUrl ? { ...model, baseUrl: result.auth.baseUrl } : model;
|
|
205
|
+
return {
|
|
206
|
+
model: requestModel,
|
|
207
|
+
apiKey: result.auth.apiKey,
|
|
208
|
+
headers: withoutDeletedHeaders(result.auth.headers),
|
|
209
|
+
env: result.env,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
return { model };
|
|
214
|
+
}
|
|
215
|
+
}
|
|
163
216
|
/**
|
|
164
217
|
* Install tool hooks once on the Agent instance.
|
|
165
218
|
*
|
|
@@ -169,14 +222,11 @@ export class AgentSession {
|
|
|
169
222
|
* happens here instead of in wrappers.
|
|
170
223
|
*/
|
|
171
224
|
_installAgentToolHooks() {
|
|
172
|
-
// Resolve deferred tools from the registry when not in context tools array
|
|
173
|
-
this.agent.resolveTool = (name) => this._toolRegistry.get(name);
|
|
174
225
|
this.agent.beforeToolCall = async ({ toolCall, args }) => {
|
|
175
226
|
const runner = this._extensionRunner;
|
|
176
227
|
if (!runner.hasHandlers("tool_call")) {
|
|
177
228
|
return undefined;
|
|
178
229
|
}
|
|
179
|
-
await this._agentEventQueue;
|
|
180
230
|
try {
|
|
181
231
|
return await runner.emitToolCall({
|
|
182
232
|
type: "tool_call",
|
|
@@ -194,25 +244,51 @@ export class AgentSession {
|
|
|
194
244
|
};
|
|
195
245
|
this.agent.afterToolCall = async ({ toolCall, args, result, isError }) => {
|
|
196
246
|
const runner = this._extensionRunner;
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
247
|
+
const hookResult = runner.hasHandlers("tool_result")
|
|
248
|
+
? await runner.emitToolResult({
|
|
249
|
+
type: "tool_result",
|
|
250
|
+
toolName: toolCall.name,
|
|
251
|
+
toolCallId: toolCall.id,
|
|
252
|
+
input: args,
|
|
253
|
+
content: result.content,
|
|
254
|
+
details: result.details,
|
|
255
|
+
isError,
|
|
256
|
+
usage: result.usage,
|
|
257
|
+
})
|
|
258
|
+
: undefined;
|
|
259
|
+
const content = hookResult?.content ?? result.content ?? [];
|
|
260
|
+
// Runs after the extension hook so images injected or replaced by extensions are normalized too.
|
|
261
|
+
const normalizedContent = await normalizeToolResultImages(content, {
|
|
262
|
+
autoResizeImages: this.settingsManager.getImageAutoResize(),
|
|
208
263
|
});
|
|
209
|
-
if (!hookResult) {
|
|
264
|
+
if (!hookResult && normalizedContent === content) {
|
|
210
265
|
return undefined;
|
|
211
266
|
}
|
|
212
267
|
return {
|
|
213
|
-
content:
|
|
214
|
-
details: hookResult
|
|
215
|
-
isError: hookResult
|
|
268
|
+
content: normalizedContent,
|
|
269
|
+
details: hookResult?.details,
|
|
270
|
+
isError: hookResult?.isError ?? isError,
|
|
271
|
+
usage: hookResult?.usage,
|
|
272
|
+
};
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
_installAgentNextTurnRefresh() {
|
|
276
|
+
const previousPrepareNextTurnWithContext = this.agent.prepareNextTurnWithContext ??
|
|
277
|
+
(this.agent.prepareNextTurn
|
|
278
|
+
? async (_turn, signal) => await this.agent.prepareNextTurn?.(signal)
|
|
279
|
+
: undefined);
|
|
280
|
+
this.agent.prepareNextTurnWithContext = async (turn, signal) => {
|
|
281
|
+
const previousSnapshot = await previousPrepareNextTurnWithContext?.(turn, signal);
|
|
282
|
+
const previousContext = previousSnapshot?.context ?? turn.context;
|
|
283
|
+
return {
|
|
284
|
+
...previousSnapshot,
|
|
285
|
+
context: {
|
|
286
|
+
...previousContext,
|
|
287
|
+
systemPrompt: this._systemPromptOverride ?? this._baseSystemPrompt,
|
|
288
|
+
tools: this.agent.state.tools.slice(),
|
|
289
|
+
},
|
|
290
|
+
model: this.agent.state.model,
|
|
291
|
+
thinkingLevel: this.agent.state.thinkingLevel,
|
|
216
292
|
};
|
|
217
293
|
};
|
|
218
294
|
}
|
|
@@ -232,51 +308,42 @@ export class AgentSession {
|
|
|
232
308
|
followUp: [...this._followUpMessages],
|
|
233
309
|
});
|
|
234
310
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
// Agent.emit() calls this handler synchronously, and prompt() calls waitForRetry()
|
|
241
|
-
// as soon as agent.prompt() resolves. If _retryPromise is created only inside
|
|
242
|
-
// _processAgentEvent, slow earlier queued events can delay agent_end processing
|
|
243
|
-
// and waitForRetry() can miss the in-flight retry.
|
|
244
|
-
this._createRetryPromiseForAgentEnd(event);
|
|
245
|
-
this._agentEventQueue = this._agentEventQueue.then(() => this._processAgentEvent(event), () => this._processAgentEvent(event));
|
|
246
|
-
// Keep queue alive if an event handler fails
|
|
247
|
-
this._agentEventQueue.catch(() => { });
|
|
248
|
-
};
|
|
249
|
-
_createRetryPromiseForAgentEnd(event) {
|
|
250
|
-
if (event.type !== "agent_end" || this._retryPromise) {
|
|
251
|
-
return;
|
|
252
|
-
}
|
|
253
|
-
const settings = this.settingsManager.getRetrySettings();
|
|
254
|
-
if (!settings.enabled) {
|
|
255
|
-
return;
|
|
311
|
+
_getIdleWaitPromise() {
|
|
312
|
+
if (!this._idleWaitPromise) {
|
|
313
|
+
this._idleWaitPromise = new Promise((resolve) => {
|
|
314
|
+
this._resolveIdleWait = resolve;
|
|
315
|
+
});
|
|
256
316
|
}
|
|
257
|
-
|
|
258
|
-
|
|
317
|
+
return this._idleWaitPromise;
|
|
318
|
+
}
|
|
319
|
+
_resolveIdleWaitIfIdle() {
|
|
320
|
+
if (this._isAgentRunActive || !this._resolveIdleWait) {
|
|
259
321
|
return;
|
|
260
322
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
323
|
+
const resolve = this._resolveIdleWait;
|
|
324
|
+
this._idleWaitPromise = undefined;
|
|
325
|
+
this._resolveIdleWait = undefined;
|
|
326
|
+
resolve();
|
|
264
327
|
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
328
|
+
async _emitAgentSettled() {
|
|
329
|
+
this._isAgentRunActive = false;
|
|
330
|
+
try {
|
|
331
|
+
await this._extensionRunner.emit({ type: "agent_settled" });
|
|
332
|
+
this._emit({ type: "agent_settled" });
|
|
333
|
+
}
|
|
334
|
+
finally {
|
|
335
|
+
this._resolveIdleWaitIfIdle();
|
|
271
336
|
}
|
|
272
|
-
return undefined;
|
|
273
337
|
}
|
|
274
|
-
|
|
338
|
+
// Track last assistant message for auto-compaction check
|
|
339
|
+
_lastAssistantMessage = undefined;
|
|
340
|
+
/** Internal handler for agent events - shared by subscribe and reconnect */
|
|
341
|
+
_handleAgentEvent = async (event) => {
|
|
275
342
|
// When a user message starts, check if it's from either queue and remove it BEFORE emitting
|
|
276
343
|
// This ensures the UI sees the updated queue state
|
|
277
344
|
if (event.type === "message_start" && event.message.role === "user") {
|
|
278
345
|
this._overflowRecoveryAttempted = false;
|
|
279
|
-
const messageText =
|
|
346
|
+
const messageText = contentText(event.message.content, "");
|
|
280
347
|
if (messageText) {
|
|
281
348
|
// Check steering queue first
|
|
282
349
|
const steeringIndex = this._steeringMessages.indexOf(messageText);
|
|
@@ -297,7 +364,7 @@ export class AgentSession {
|
|
|
297
364
|
// Emit to extensions first
|
|
298
365
|
await this._emitExtensionEvent(event);
|
|
299
366
|
// Notify all listeners
|
|
300
|
-
this._emit(event);
|
|
367
|
+
this._emit(event.type === "agent_end" ? { ...event, willRetry: this._willRetryAfterAgentEnd(event) } : event);
|
|
301
368
|
// Handle session persistence
|
|
302
369
|
if (event.type === "message_end") {
|
|
303
370
|
// Check if this is a custom message from extensions
|
|
@@ -316,7 +383,7 @@ export class AgentSession {
|
|
|
316
383
|
if (event.message.role === "assistant") {
|
|
317
384
|
this._lastAssistantMessage = event.message;
|
|
318
385
|
const assistantMsg = event.message;
|
|
319
|
-
if (assistantMsg.stopReason !== "error") {
|
|
386
|
+
if (assistantMsg.stopReason !== "error" && assistantMsg.stopReason !== "length") {
|
|
320
387
|
this._overflowRecoveryAttempted = false;
|
|
321
388
|
}
|
|
322
389
|
// Reset retry counter immediately on successful assistant response
|
|
@@ -331,37 +398,19 @@ export class AgentSession {
|
|
|
331
398
|
}
|
|
332
399
|
}
|
|
333
400
|
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
if (this._isRetryableError(msg)) {
|
|
340
|
-
const didRetry = await this._handleRetryableError(msg);
|
|
341
|
-
if (didRetry)
|
|
342
|
-
return; // Retry was initiated, don't proceed to compaction
|
|
343
|
-
}
|
|
344
|
-
this._resolveRetry();
|
|
345
|
-
await this._checkCompaction(msg);
|
|
401
|
+
};
|
|
402
|
+
_willRetryAfterAgentEnd(event) {
|
|
403
|
+
const settings = this.settingsManager.getRetrySettings();
|
|
404
|
+
if (!settings.enabled || this._retryAttempt >= settings.maxRetries) {
|
|
405
|
+
return false;
|
|
346
406
|
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
this._retryResolve = undefined;
|
|
353
|
-
this._retryPromise = undefined;
|
|
407
|
+
for (let i = event.messages.length - 1; i >= 0; i--) {
|
|
408
|
+
const message = event.messages[i];
|
|
409
|
+
if (message.role === "assistant") {
|
|
410
|
+
return this._isRetryableError(message);
|
|
411
|
+
}
|
|
354
412
|
}
|
|
355
|
-
|
|
356
|
-
/** Extract text content from a message */
|
|
357
|
-
_getUserMessageText(message) {
|
|
358
|
-
if (message.role !== "user")
|
|
359
|
-
return "";
|
|
360
|
-
const content = message.content;
|
|
361
|
-
if (typeof content === "string")
|
|
362
|
-
return content;
|
|
363
|
-
const textBlocks = content.filter((c) => c.type === "text");
|
|
364
|
-
return textBlocks.map((c) => c.text).join("");
|
|
413
|
+
return false;
|
|
365
414
|
}
|
|
366
415
|
/** Find the last assistant message in agent state (including aborted ones) */
|
|
367
416
|
_findLastAssistantMessage() {
|
|
@@ -374,6 +423,20 @@ export class AgentSession {
|
|
|
374
423
|
}
|
|
375
424
|
return undefined;
|
|
376
425
|
}
|
|
426
|
+
_replaceMessageInPlace(target, replacement) {
|
|
427
|
+
// Agent-core stores the finalized message object in its state before emitting message_end.
|
|
428
|
+
// SessionManager persistence happens later in _handleAgentEvent() with event.message.
|
|
429
|
+
// Mutating this object in place keeps agent state, later turn/agent events, listeners,
|
|
430
|
+
// and the eventual SessionManager.appendMessage(event.message) persistence in sync.
|
|
431
|
+
if (target === replacement) {
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
const targetRecord = target;
|
|
435
|
+
for (const key of Object.keys(targetRecord)) {
|
|
436
|
+
delete targetRecord[key];
|
|
437
|
+
}
|
|
438
|
+
Object.assign(targetRecord, replacement);
|
|
439
|
+
}
|
|
377
440
|
/** Emit extension events based on agent events */
|
|
378
441
|
async _emitExtensionEvent(event) {
|
|
379
442
|
if (event.type === "agent_start") {
|
|
@@ -421,7 +484,19 @@ export class AgentSession {
|
|
|
421
484
|
type: "message_end",
|
|
422
485
|
message: event.message,
|
|
423
486
|
};
|
|
424
|
-
await this._extensionRunner.
|
|
487
|
+
const replacement = await this._extensionRunner.emitMessageEnd(extensionEvent);
|
|
488
|
+
if (replacement) {
|
|
489
|
+
// Untyped extension handlers can return messages with null/missing content;
|
|
490
|
+
// normalize so it never enters agent state or session history.
|
|
491
|
+
const normalized = (replacement.role === "user" ||
|
|
492
|
+
replacement.role === "assistant" ||
|
|
493
|
+
replacement.role === "toolResult" ||
|
|
494
|
+
replacement.role === "custom") &&
|
|
495
|
+
replacement.content == null
|
|
496
|
+
? { ...replacement, content: [] }
|
|
497
|
+
: replacement;
|
|
498
|
+
this._replaceMessageInPlace(event.message, normalized);
|
|
499
|
+
}
|
|
425
500
|
}
|
|
426
501
|
else if (event.type === "tool_execution_start") {
|
|
427
502
|
const extensionEvent = {
|
|
@@ -468,34 +543,32 @@ export class AgentSession {
|
|
|
468
543
|
}
|
|
469
544
|
};
|
|
470
545
|
}
|
|
471
|
-
/**
|
|
472
|
-
* Temporarily disconnect from agent events.
|
|
473
|
-
* User listeners are preserved and will receive events again after resubscribe().
|
|
474
|
-
* Used internally during operations that need to pause event processing.
|
|
475
|
-
*/
|
|
546
|
+
/** Disconnect from agent events during disposal. */
|
|
476
547
|
_disconnectFromAgent() {
|
|
477
548
|
if (this._unsubscribeAgent) {
|
|
478
549
|
this._unsubscribeAgent();
|
|
479
550
|
this._unsubscribeAgent = undefined;
|
|
480
551
|
}
|
|
481
552
|
}
|
|
482
|
-
/**
|
|
483
|
-
* Reconnect to agent events after _disconnectFromAgent().
|
|
484
|
-
* Preserves all existing listeners.
|
|
485
|
-
*/
|
|
486
|
-
_reconnectToAgent() {
|
|
487
|
-
if (this._unsubscribeAgent)
|
|
488
|
-
return; // Already connected
|
|
489
|
-
this._unsubscribeAgent = this.agent.subscribe(this._handleAgentEvent);
|
|
490
|
-
}
|
|
491
553
|
/**
|
|
492
554
|
* Remove all listeners and disconnect from agent.
|
|
493
555
|
* Call this when completely done with the session.
|
|
494
556
|
*/
|
|
495
557
|
dispose() {
|
|
558
|
+
try {
|
|
559
|
+
this.abortRetry();
|
|
560
|
+
this.abortCompaction();
|
|
561
|
+
this.abortBranchSummary();
|
|
562
|
+
this.abortBash();
|
|
563
|
+
this.agent.abort();
|
|
564
|
+
}
|
|
565
|
+
catch {
|
|
566
|
+
// Dispose must succeed even if an abort hook throws.
|
|
567
|
+
}
|
|
496
568
|
this._extensionRunner.invalidate("This extension ctx is stale after session replacement or reload. Do not use a captured pi or command ctx after ctx.newSession(), ctx.fork(), ctx.switchSession(), or ctx.reload(). For newSession, fork, and switchSession, move post-replacement work into withSession and use the ctx passed to withSession. For reload, do not use the old ctx after await ctx.reload().");
|
|
497
569
|
this._disconnectFromAgent();
|
|
498
570
|
this._eventListeners = [];
|
|
571
|
+
cleanupSessionResources(this.sessionId);
|
|
499
572
|
}
|
|
500
573
|
// =========================================================================
|
|
501
574
|
// Read-only State Access
|
|
@@ -512,9 +585,13 @@ export class AgentSession {
|
|
|
512
585
|
get thinkingLevel() {
|
|
513
586
|
return this.agent.state.thinkingLevel;
|
|
514
587
|
}
|
|
515
|
-
/** Whether
|
|
588
|
+
/** Whether the session is currently processing an agent run or post-run continuation. */
|
|
516
589
|
get isStreaming() {
|
|
517
|
-
return this.
|
|
590
|
+
return this._isAgentRunActive;
|
|
591
|
+
}
|
|
592
|
+
/** Whether the session has no active agent run, retry, auto-compaction, or queued continuation. */
|
|
593
|
+
get isIdle() {
|
|
594
|
+
return !this._isAgentRunActive;
|
|
518
595
|
}
|
|
519
596
|
/** Current effective system prompt (includes any per-turn extension modifications) */
|
|
520
597
|
get systemPrompt() {
|
|
@@ -532,13 +609,14 @@ export class AgentSession {
|
|
|
532
609
|
return this.agent.state.tools.map((t) => t.name);
|
|
533
610
|
}
|
|
534
611
|
/**
|
|
535
|
-
* Get all configured tools with name, description, parameter schema, and source metadata.
|
|
612
|
+
* Get all configured tools with name, description, parameter schema, prompt guidelines, and source metadata.
|
|
536
613
|
*/
|
|
537
614
|
getAllTools() {
|
|
538
615
|
return Array.from(this._toolDefinitions.values()).map(({ definition, sourceInfo }) => ({
|
|
539
616
|
name: definition.name,
|
|
540
617
|
description: definition.description,
|
|
541
618
|
parameters: definition.parameters,
|
|
619
|
+
promptGuidelines: definition.promptGuidelines,
|
|
542
620
|
sourceInfo,
|
|
543
621
|
}));
|
|
544
622
|
}
|
|
@@ -553,22 +631,18 @@ export class AgentSession {
|
|
|
553
631
|
*/
|
|
554
632
|
setActiveToolsByName(toolNames) {
|
|
555
633
|
const tools = [];
|
|
556
|
-
const
|
|
634
|
+
const validToolNames = [];
|
|
557
635
|
for (const name of toolNames) {
|
|
558
636
|
const tool = this._toolRegistry.get(name);
|
|
559
637
|
if (tool) {
|
|
560
638
|
tools.push(tool);
|
|
561
|
-
|
|
562
|
-
promptToolNames.push(name);
|
|
563
|
-
}
|
|
639
|
+
validToolNames.push(name);
|
|
564
640
|
}
|
|
565
641
|
}
|
|
566
642
|
this.agent.state.tools = tools;
|
|
567
|
-
// Rebuild base system prompt
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
this._baseSystemPrompt = this._rebuildSystemPrompt(promptToolNames);
|
|
571
|
-
this.agent.state.systemPrompt = this._baseSystemPrompt;
|
|
643
|
+
// Rebuild base system prompt with new tool set
|
|
644
|
+
this._baseSystemPrompt = this._rebuildSystemPrompt(validToolNames);
|
|
645
|
+
this.agent.state.systemPrompt = this._systemPromptOverride ?? this._baseSystemPrompt;
|
|
572
646
|
}
|
|
573
647
|
/** Whether compaction or branch summarization is currently running */
|
|
574
648
|
get isCompacting() {
|
|
@@ -668,6 +742,45 @@ export class AgentSession {
|
|
|
668
742
|
// =========================================================================
|
|
669
743
|
// Prompting
|
|
670
744
|
// =========================================================================
|
|
745
|
+
async _runAgentPrompt(messages) {
|
|
746
|
+
this._isAgentRunActive = true;
|
|
747
|
+
try {
|
|
748
|
+
await this.agent.prompt(messages);
|
|
749
|
+
while (await this._handlePostAgentRun()) {
|
|
750
|
+
await this.agent.continue();
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
finally {
|
|
754
|
+
this._systemPromptOverride = undefined;
|
|
755
|
+
this._flushPendingBashMessages();
|
|
756
|
+
await this._emitAgentSettled();
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
async _handlePostAgentRun() {
|
|
760
|
+
const msg = this._lastAssistantMessage;
|
|
761
|
+
this._lastAssistantMessage = undefined;
|
|
762
|
+
if (!msg) {
|
|
763
|
+
return false;
|
|
764
|
+
}
|
|
765
|
+
if (this._isRetryableError(msg) && (await this._prepareRetry(msg))) {
|
|
766
|
+
return true;
|
|
767
|
+
}
|
|
768
|
+
if (msg.stopReason === "error" && this._retryAttempt > 0) {
|
|
769
|
+
this._emit({
|
|
770
|
+
type: "auto_retry_end",
|
|
771
|
+
success: false,
|
|
772
|
+
attempt: this._retryAttempt,
|
|
773
|
+
finalError: msg.errorMessage,
|
|
774
|
+
});
|
|
775
|
+
this._retryAttempt = 0;
|
|
776
|
+
}
|
|
777
|
+
if (await this._checkCompaction(msg)) {
|
|
778
|
+
return true;
|
|
779
|
+
}
|
|
780
|
+
// The agent loop drains both queues before emitting agent_end. Any messages
|
|
781
|
+
// here were queued by agent_end extension handlers and need a continuation.
|
|
782
|
+
return this.agent.hasQueuedMessages();
|
|
783
|
+
}
|
|
671
784
|
/**
|
|
672
785
|
* Send a prompt to the agent.
|
|
673
786
|
* - Handles extension commands (registered via pi.registerCommand) immediately, even during streaming
|
|
@@ -692,11 +805,14 @@ export class AgentSession {
|
|
|
692
805
|
return;
|
|
693
806
|
}
|
|
694
807
|
}
|
|
808
|
+
if (this._compactionAbortController !== undefined) {
|
|
809
|
+
throw new Error("Cannot submit a prompt while compaction is in progress. Wait for compaction to finish and retry.");
|
|
810
|
+
}
|
|
695
811
|
// Emit input event for extension interception (before skill/template expansion)
|
|
696
812
|
let currentText = text;
|
|
697
813
|
let currentImages = options?.images;
|
|
698
814
|
if (this._extensionRunner.hasHandlers("input")) {
|
|
699
|
-
const inputResult = await this._extensionRunner.emitInput(currentText, currentImages, options?.source ?? "interactive");
|
|
815
|
+
const inputResult = await this._extensionRunner.emitInput(currentText, currentImages, options?.source ?? "interactive", this.isStreaming ? options?.streamingBehavior : undefined);
|
|
700
816
|
if (inputResult.action === "handled") {
|
|
701
817
|
preflightResult?.(true);
|
|
702
818
|
return;
|
|
@@ -732,8 +848,10 @@ export class AgentSession {
|
|
|
732
848
|
if (!this.model) {
|
|
733
849
|
throw new Error(formatNoModelSelectedMessage());
|
|
734
850
|
}
|
|
735
|
-
|
|
736
|
-
|
|
851
|
+
const hasConfiguredAuth = this._modelRuntime.hasConfiguredAuth(this.model.provider) ||
|
|
852
|
+
(await this._modelRuntime.checkAuth(this.model.provider)) !== undefined;
|
|
853
|
+
if (!hasConfiguredAuth) {
|
|
854
|
+
const isOAuth = this._modelRuntime.isUsingOAuth(this.model.provider);
|
|
737
855
|
if (isOAuth) {
|
|
738
856
|
throw new Error(`Authentication failed for "${this.model.provider}". ` +
|
|
739
857
|
`Credentials may have expired or network is unavailable. ` +
|
|
@@ -741,7 +859,8 @@ export class AgentSession {
|
|
|
741
859
|
}
|
|
742
860
|
throw new Error(formatNoApiKeyFoundMessage(this.model.provider));
|
|
743
861
|
}
|
|
744
|
-
// Check if we need to compact before sending (catches aborted responses)
|
|
862
|
+
// Check if we need to compact before sending (catches aborted responses).
|
|
863
|
+
// The user's new prompt is sent below, so do not call agent.continue() here.
|
|
745
864
|
const lastAssistant = this._findLastAssistantMessage();
|
|
746
865
|
if (lastAssistant) {
|
|
747
866
|
await this._checkCompaction(lastAssistant, false);
|
|
@@ -771,7 +890,8 @@ export class AgentSession {
|
|
|
771
890
|
messages.push({
|
|
772
891
|
role: "custom",
|
|
773
892
|
customType: msg.customType,
|
|
774
|
-
content
|
|
893
|
+
// Untyped extensions can pass null/missing content; normalize at ingestion.
|
|
894
|
+
content: msg.content ?? [],
|
|
775
895
|
display: msg.display,
|
|
776
896
|
details: msg.details,
|
|
777
897
|
timestamp: Date.now(),
|
|
@@ -779,11 +899,13 @@ export class AgentSession {
|
|
|
779
899
|
}
|
|
780
900
|
}
|
|
781
901
|
// Apply extension-modified system prompt, or reset to base
|
|
782
|
-
if (result?.systemPrompt) {
|
|
902
|
+
if (result?.systemPrompt !== undefined) {
|
|
903
|
+
this._systemPromptOverride = result.systemPrompt;
|
|
783
904
|
this.agent.state.systemPrompt = result.systemPrompt;
|
|
784
905
|
}
|
|
785
906
|
else {
|
|
786
907
|
// Ensure we're using the base prompt (in case previous turn had modifications)
|
|
908
|
+
this._systemPromptOverride = undefined;
|
|
787
909
|
this.agent.state.systemPrompt = this._baseSystemPrompt;
|
|
788
910
|
}
|
|
789
911
|
}
|
|
@@ -795,8 +917,7 @@ export class AgentSession {
|
|
|
795
917
|
return;
|
|
796
918
|
}
|
|
797
919
|
preflightResult?.(true);
|
|
798
|
-
await this.
|
|
799
|
-
await this.waitForRetry();
|
|
920
|
+
await this._runAgentPrompt(messages);
|
|
800
921
|
}
|
|
801
922
|
/**
|
|
802
923
|
* Try to execute an extension command. Returns true if command was found and executed.
|
|
@@ -949,7 +1070,8 @@ export class AgentSession {
|
|
|
949
1070
|
const appMessage = {
|
|
950
1071
|
role: "custom",
|
|
951
1072
|
customType: message.customType,
|
|
952
|
-
content
|
|
1073
|
+
// Untyped extensions can pass null/missing content; normalize at ingestion.
|
|
1074
|
+
content: message.content ?? [],
|
|
953
1075
|
display: message.display,
|
|
954
1076
|
details: message.details,
|
|
955
1077
|
timestamp: Date.now(),
|
|
@@ -957,7 +1079,7 @@ export class AgentSession {
|
|
|
957
1079
|
if (options?.deliverAs === "nextTurn") {
|
|
958
1080
|
this._pendingNextTurnMessages.push(appMessage);
|
|
959
1081
|
}
|
|
960
|
-
else if (this.isStreaming) {
|
|
1082
|
+
else if (this.isStreaming && options?.triggerTurn !== false) {
|
|
961
1083
|
if (options?.deliverAs === "followUp") {
|
|
962
1084
|
this.agent.followUp(appMessage);
|
|
963
1085
|
}
|
|
@@ -966,7 +1088,7 @@ export class AgentSession {
|
|
|
966
1088
|
}
|
|
967
1089
|
}
|
|
968
1090
|
else if (options?.triggerTurn) {
|
|
969
|
-
await this.
|
|
1091
|
+
await this._runAgentPrompt(appMessage);
|
|
970
1092
|
}
|
|
971
1093
|
else {
|
|
972
1094
|
this.agent.state.messages.push(appMessage);
|
|
@@ -981,6 +1103,7 @@ export class AgentSession {
|
|
|
981
1103
|
*
|
|
982
1104
|
* @param content User message content (string or content array)
|
|
983
1105
|
* @param options.deliverAs Delivery mode when streaming: "steer" or "followUp"
|
|
1106
|
+
* @param options.expandPromptTemplates Whether to dispatch extension commands and expand skill commands and prompt templates. Default: false.
|
|
984
1107
|
*/
|
|
985
1108
|
async sendUserMessage(content, options) {
|
|
986
1109
|
// Normalize content to text string + optional images
|
|
@@ -1004,9 +1127,8 @@ export class AgentSession {
|
|
|
1004
1127
|
if (images.length === 0)
|
|
1005
1128
|
images = undefined;
|
|
1006
1129
|
}
|
|
1007
|
-
// Use prompt() with expandPromptTemplates: false to skip command handling and template expansion
|
|
1008
1130
|
await this.prompt(text, {
|
|
1009
|
-
expandPromptTemplates: false,
|
|
1131
|
+
expandPromptTemplates: options?.expandPromptTemplates ?? false,
|
|
1010
1132
|
streamingBehavior: options?.deliverAs,
|
|
1011
1133
|
images,
|
|
1012
1134
|
source: "extension",
|
|
@@ -1047,7 +1169,13 @@ export class AgentSession {
|
|
|
1047
1169
|
async abort() {
|
|
1048
1170
|
this.abortRetry();
|
|
1049
1171
|
this.agent.abort();
|
|
1050
|
-
await this.
|
|
1172
|
+
await this.waitForIdle();
|
|
1173
|
+
}
|
|
1174
|
+
async waitForIdle() {
|
|
1175
|
+
if (this.isIdle) {
|
|
1176
|
+
return;
|
|
1177
|
+
}
|
|
1178
|
+
await this._getIdleWaitPromise();
|
|
1051
1179
|
}
|
|
1052
1180
|
// =========================================================================
|
|
1053
1181
|
// Model Management
|
|
@@ -1068,7 +1196,7 @@ export class AgentSession {
|
|
|
1068
1196
|
* @throws Error if no auth is configured for the model
|
|
1069
1197
|
*/
|
|
1070
1198
|
async setModel(model) {
|
|
1071
|
-
if (!this.
|
|
1199
|
+
if (!(await this._modelRuntime.checkAuth(model.provider))) {
|
|
1072
1200
|
throw new Error(`No API key for ${model.provider}/${model.id}`);
|
|
1073
1201
|
}
|
|
1074
1202
|
const previousModel = this.model;
|
|
@@ -1093,7 +1221,8 @@ export class AgentSession {
|
|
|
1093
1221
|
return this._cycleAvailableModel(direction);
|
|
1094
1222
|
}
|
|
1095
1223
|
async _cycleScopedModel(direction) {
|
|
1096
|
-
const
|
|
1224
|
+
const availableIds = new Set(this._modelRuntime.getAvailableSnapshot().map((model) => `${model.provider}\0${model.id}`));
|
|
1225
|
+
const scopedModels = this._scopedModels.filter((scoped) => availableIds.has(`${scoped.model.provider}\0${scoped.model.id}`));
|
|
1097
1226
|
if (scopedModels.length <= 1)
|
|
1098
1227
|
return undefined;
|
|
1099
1228
|
const currentModel = this.model;
|
|
@@ -1117,7 +1246,7 @@ export class AgentSession {
|
|
|
1117
1246
|
return { model: next.model, thinkingLevel: this.thinkingLevel, isScoped: true };
|
|
1118
1247
|
}
|
|
1119
1248
|
async _cycleAvailableModel(direction) {
|
|
1120
|
-
const availableModels =
|
|
1249
|
+
const availableModels = this._modelRuntime.getAvailableSnapshot();
|
|
1121
1250
|
if (availableModels.length <= 1)
|
|
1122
1251
|
return undefined;
|
|
1123
1252
|
const currentModel = this.model;
|
|
@@ -1148,13 +1277,20 @@ export class AgentSession {
|
|
|
1148
1277
|
const availableLevels = this.getAvailableThinkingLevels();
|
|
1149
1278
|
const effectiveLevel = availableLevels.includes(level) ? level : this._clampThinkingLevel(level, availableLevels);
|
|
1150
1279
|
// Only persist if actually changing
|
|
1151
|
-
const
|
|
1280
|
+
const previousLevel = this.agent.state.thinkingLevel;
|
|
1281
|
+
const isChanging = effectiveLevel !== previousLevel;
|
|
1152
1282
|
this.agent.state.thinkingLevel = effectiveLevel;
|
|
1153
1283
|
if (isChanging) {
|
|
1154
1284
|
this.sessionManager.appendThinkingLevelChange(effectiveLevel);
|
|
1155
1285
|
if (this.supportsThinking() || effectiveLevel !== "off") {
|
|
1156
1286
|
this.settingsManager.setDefaultThinkingLevel(effectiveLevel);
|
|
1157
1287
|
}
|
|
1288
|
+
this._emit({ type: "thinking_level_changed", level: effectiveLevel });
|
|
1289
|
+
void this._extensionRunner.emit({
|
|
1290
|
+
type: "thinking_level_select",
|
|
1291
|
+
level: effectiveLevel,
|
|
1292
|
+
previousLevel,
|
|
1293
|
+
});
|
|
1158
1294
|
}
|
|
1159
1295
|
}
|
|
1160
1296
|
/**
|
|
@@ -1176,15 +1312,9 @@ export class AgentSession {
|
|
|
1176
1312
|
* The provider will clamp to what the specific model supports internally.
|
|
1177
1313
|
*/
|
|
1178
1314
|
getAvailableThinkingLevels() {
|
|
1179
|
-
if (!this.
|
|
1180
|
-
return
|
|
1181
|
-
return this.
|
|
1182
|
-
}
|
|
1183
|
-
/**
|
|
1184
|
-
* Check if current model supports xhigh thinking level.
|
|
1185
|
-
*/
|
|
1186
|
-
supportsXhighThinking() {
|
|
1187
|
-
return this.model ? supportsXhigh(this.model) : false;
|
|
1315
|
+
if (!this.model)
|
|
1316
|
+
return THINKING_LEVELS;
|
|
1317
|
+
return getSupportedThinkingLevels(this.model);
|
|
1188
1318
|
}
|
|
1189
1319
|
/**
|
|
1190
1320
|
* Check if current model supports thinking/reasoning.
|
|
@@ -1201,28 +1331,16 @@ export class AgentSession {
|
|
|
1201
1331
|
}
|
|
1202
1332
|
return this.thinkingLevel;
|
|
1203
1333
|
}
|
|
1204
|
-
_clampThinkingLevel(level,
|
|
1205
|
-
|
|
1206
|
-
const available = new Set(availableLevels);
|
|
1207
|
-
const requestedIndex = ordered.indexOf(level);
|
|
1208
|
-
if (requestedIndex === -1) {
|
|
1209
|
-
return availableLevels[0] ?? "off";
|
|
1210
|
-
}
|
|
1211
|
-
for (let i = requestedIndex; i < ordered.length; i++) {
|
|
1212
|
-
const candidate = ordered[i];
|
|
1213
|
-
if (available.has(candidate))
|
|
1214
|
-
return candidate;
|
|
1215
|
-
}
|
|
1216
|
-
for (let i = requestedIndex - 1; i >= 0; i--) {
|
|
1217
|
-
const candidate = ordered[i];
|
|
1218
|
-
if (available.has(candidate))
|
|
1219
|
-
return candidate;
|
|
1220
|
-
}
|
|
1221
|
-
return availableLevels[0] ?? "off";
|
|
1334
|
+
_clampThinkingLevel(level, _availableLevels) {
|
|
1335
|
+
return this.model ? clampThinkingLevel(this.model, level) : "off";
|
|
1222
1336
|
}
|
|
1223
1337
|
// =========================================================================
|
|
1224
1338
|
// Queue Mode Management
|
|
1225
1339
|
// =========================================================================
|
|
1340
|
+
syncQueueModesFromSettings() {
|
|
1341
|
+
this.agent.steeringMode = this.settingsManager.getSteeringMode();
|
|
1342
|
+
this.agent.followUpMode = this.settingsManager.getFollowUpMode();
|
|
1343
|
+
}
|
|
1226
1344
|
/**
|
|
1227
1345
|
* Set steering message mode.
|
|
1228
1346
|
* Saves to settings.
|
|
@@ -1248,7 +1366,6 @@ export class AgentSession {
|
|
|
1248
1366
|
* @param customInstructions Optional instructions for the compaction summary
|
|
1249
1367
|
*/
|
|
1250
1368
|
async compact(customInstructions) {
|
|
1251
|
-
this._disconnectFromAgent();
|
|
1252
1369
|
await this.abort();
|
|
1253
1370
|
this._compactionAbortController = new AbortController();
|
|
1254
1371
|
this._emit({ type: "compaction_start", reason: "manual" });
|
|
@@ -1256,7 +1373,7 @@ export class AgentSession {
|
|
|
1256
1373
|
if (!this.model) {
|
|
1257
1374
|
throw new Error(formatNoModelSelectedMessage());
|
|
1258
1375
|
}
|
|
1259
|
-
const { apiKey, headers } = await this.
|
|
1376
|
+
const { model: requestModel, apiKey, headers, env } = await this._getSummarizationRequestAuth(this.model);
|
|
1260
1377
|
const pathEntries = this.sessionManager.getBranch();
|
|
1261
1378
|
const settings = this.settingsManager.getCompactionSettings();
|
|
1262
1379
|
const preparation = prepareCompaction(pathEntries, settings);
|
|
@@ -1276,6 +1393,8 @@ export class AgentSession {
|
|
|
1276
1393
|
preparation,
|
|
1277
1394
|
branchEntries: pathEntries,
|
|
1278
1395
|
customInstructions,
|
|
1396
|
+
reason: "manual",
|
|
1397
|
+
willRetry: false,
|
|
1279
1398
|
signal: this._compactionAbortController.signal,
|
|
1280
1399
|
}));
|
|
1281
1400
|
if (result?.cancel) {
|
|
@@ -1289,29 +1408,33 @@ export class AgentSession {
|
|
|
1289
1408
|
let summary;
|
|
1290
1409
|
let firstKeptEntryId;
|
|
1291
1410
|
let tokensBefore;
|
|
1411
|
+
let usage;
|
|
1292
1412
|
let details;
|
|
1293
1413
|
if (extensionCompaction) {
|
|
1294
1414
|
// Extension provided compaction content
|
|
1295
1415
|
summary = extensionCompaction.summary;
|
|
1296
1416
|
firstKeptEntryId = extensionCompaction.firstKeptEntryId;
|
|
1297
1417
|
tokensBefore = extensionCompaction.tokensBefore;
|
|
1418
|
+
usage = extensionCompaction.usage;
|
|
1298
1419
|
details = extensionCompaction.details;
|
|
1299
1420
|
}
|
|
1300
1421
|
else {
|
|
1301
1422
|
// Generate compaction result
|
|
1302
|
-
const result = await compact(preparation,
|
|
1423
|
+
const result = await compact(preparation, requestModel, apiKey, headers, customInstructions, this._compactionAbortController.signal, this.thinkingLevel, this.agent.streamFunction, env, this.settingsManager.getRetrySettings(), this._summarizationRetryCallbacks({ source: "compaction", reason: "manual" }));
|
|
1303
1424
|
summary = result.summary;
|
|
1304
1425
|
firstKeptEntryId = result.firstKeptEntryId;
|
|
1305
1426
|
tokensBefore = result.tokensBefore;
|
|
1427
|
+
usage = result.usage;
|
|
1306
1428
|
details = result.details;
|
|
1307
1429
|
}
|
|
1308
1430
|
if (this._compactionAbortController.signal.aborted) {
|
|
1309
1431
|
throw new Error("Compaction cancelled");
|
|
1310
1432
|
}
|
|
1311
|
-
this.sessionManager.appendCompaction(summary, firstKeptEntryId, tokensBefore, details, fromExtension);
|
|
1433
|
+
this.sessionManager.appendCompaction(summary, firstKeptEntryId, tokensBefore, details, fromExtension, usage);
|
|
1312
1434
|
const newEntries = this.sessionManager.getEntries();
|
|
1313
1435
|
const sessionContext = this.sessionManager.buildSessionContext();
|
|
1314
1436
|
this.agent.state.messages = sessionContext.messages;
|
|
1437
|
+
const estimatedTokensAfter = estimateMessagesTokens(sessionContext.messages);
|
|
1315
1438
|
// Get the saved compaction entry for the extension event
|
|
1316
1439
|
const savedCompactionEntry = newEntries.find((e) => e.type === "compaction" && e.summary === summary);
|
|
1317
1440
|
if (this._extensionRunner && savedCompactionEntry) {
|
|
@@ -1319,14 +1442,20 @@ export class AgentSession {
|
|
|
1319
1442
|
type: "session_compact",
|
|
1320
1443
|
compactionEntry: savedCompactionEntry,
|
|
1321
1444
|
fromExtension,
|
|
1445
|
+
reason: "manual",
|
|
1446
|
+
willRetry: false,
|
|
1322
1447
|
});
|
|
1323
1448
|
}
|
|
1324
1449
|
const compactionResult = {
|
|
1325
1450
|
summary,
|
|
1326
1451
|
firstKeptEntryId,
|
|
1327
1452
|
tokensBefore,
|
|
1453
|
+
estimatedTokensAfter,
|
|
1454
|
+
usage,
|
|
1328
1455
|
details,
|
|
1329
1456
|
};
|
|
1457
|
+
// compaction_end listeners may submit queued prompts, so expose idle state before notifying them.
|
|
1458
|
+
this._compactionAbortController = undefined;
|
|
1330
1459
|
this._emit({
|
|
1331
1460
|
type: "compaction_end",
|
|
1332
1461
|
reason: "manual",
|
|
@@ -1339,6 +1468,7 @@ export class AgentSession {
|
|
|
1339
1468
|
catch (error) {
|
|
1340
1469
|
const message = error instanceof Error ? error.message : String(error);
|
|
1341
1470
|
const aborted = message === "Compaction cancelled" || (error instanceof Error && error.name === "AbortError");
|
|
1471
|
+
this._compactionAbortController = undefined;
|
|
1342
1472
|
this._emit({
|
|
1343
1473
|
type: "compaction_end",
|
|
1344
1474
|
reason: "manual",
|
|
@@ -1351,7 +1481,6 @@ export class AgentSession {
|
|
|
1351
1481
|
}
|
|
1352
1482
|
finally {
|
|
1353
1483
|
this._compactionAbortController = undefined;
|
|
1354
|
-
this._reconnectToAgent();
|
|
1355
1484
|
}
|
|
1356
1485
|
}
|
|
1357
1486
|
/**
|
|
@@ -1372,7 +1501,8 @@ export class AgentSession {
|
|
|
1372
1501
|
* Called after agent_end and before prompt submission.
|
|
1373
1502
|
*
|
|
1374
1503
|
* Two cases:
|
|
1375
|
-
* 1.
|
|
1504
|
+
* 1. Recoverable failure: LLM returned context overflow or stopped below its desired output limit;
|
|
1505
|
+
* remove the assistant message, compact, and auto-retry once
|
|
1376
1506
|
* 2. Threshold: Context over threshold, compact, NO auto-retry (user continues manually)
|
|
1377
1507
|
*
|
|
1378
1508
|
* @param assistantMessage The assistant message to check
|
|
@@ -1381,10 +1511,10 @@ export class AgentSession {
|
|
|
1381
1511
|
async _checkCompaction(assistantMessage, skipAbortedCheck = true) {
|
|
1382
1512
|
const settings = this.settingsManager.getCompactionSettings();
|
|
1383
1513
|
if (!settings.enabled)
|
|
1384
|
-
return;
|
|
1514
|
+
return false;
|
|
1385
1515
|
// Skip if message was aborted (user cancelled) - unless skipAbortedCheck is false
|
|
1386
1516
|
if (skipAbortedCheck && assistantMessage.stopReason === "aborted")
|
|
1387
|
-
return;
|
|
1517
|
+
return false;
|
|
1388
1518
|
const contextWindow = this.model?.contextWindow ?? 0;
|
|
1389
1519
|
// Skip overflow check if the message came from a different model.
|
|
1390
1520
|
// This handles the case where user switched from a smaller-context model (e.g. opus)
|
|
@@ -1397,10 +1527,19 @@ export class AgentSession {
|
|
|
1397
1527
|
const compactionEntry = getLatestCompactionEntry(this.sessionManager.getBranch());
|
|
1398
1528
|
const assistantIsFromBeforeCompaction = compactionEntry !== null && assistantMessage.timestamp <= new Date(compactionEntry.timestamp).getTime();
|
|
1399
1529
|
if (assistantIsFromBeforeCompaction) {
|
|
1400
|
-
return;
|
|
1530
|
+
return false;
|
|
1401
1531
|
}
|
|
1402
|
-
// Case 1:
|
|
1403
|
-
|
|
1532
|
+
// Case 1: Recoverable failure. Explicit/silent context overflow still uses context metadata.
|
|
1533
|
+
// A length stop is recoverable when output ended below the model's original desired limit,
|
|
1534
|
+
// independent of the configured context size or any context-clamped provider request limit.
|
|
1535
|
+
// A successful response over the configured window should compact but must not retry: the
|
|
1536
|
+
// assistant answer already completed and agent.continue() cannot continue from an assistant.
|
|
1537
|
+
const recoverableLength = sameModel && isRecoverableLength(assistantMessage, this.model?.maxTokens ?? 0);
|
|
1538
|
+
if (sameModel && (isContextOverflow(assistantMessage, contextWindow) || recoverableLength)) {
|
|
1539
|
+
const willRetry = assistantMessage.stopReason !== "stop";
|
|
1540
|
+
if (!willRetry) {
|
|
1541
|
+
return await this._runAutoCompaction("overflow", false);
|
|
1542
|
+
}
|
|
1404
1543
|
if (this._overflowRecoveryAttempted) {
|
|
1405
1544
|
this._emit({
|
|
1406
1545
|
type: "compaction_end",
|
|
@@ -1410,27 +1549,28 @@ export class AgentSession {
|
|
|
1410
1549
|
willRetry: false,
|
|
1411
1550
|
errorMessage: "Context overflow recovery failed after one compact-and-retry attempt. Try reducing context or switching to a larger-context model.",
|
|
1412
1551
|
});
|
|
1413
|
-
return;
|
|
1552
|
+
return false;
|
|
1414
1553
|
}
|
|
1415
1554
|
this._overflowRecoveryAttempted = true;
|
|
1416
|
-
// Remove the
|
|
1417
|
-
// but
|
|
1555
|
+
// Remove the failed or truncated message from agent state. It remains in session history,
|
|
1556
|
+
// but must not be included in the compact-and-retry context.
|
|
1418
1557
|
const messages = this.agent.state.messages;
|
|
1419
1558
|
if (messages.length > 0 && messages[messages.length - 1].role === "assistant") {
|
|
1420
1559
|
this.agent.state.messages = messages.slice(0, -1);
|
|
1421
1560
|
}
|
|
1422
|
-
await this._runAutoCompaction("overflow",
|
|
1423
|
-
return;
|
|
1561
|
+
return await this._runAutoCompaction("overflow", willRetry);
|
|
1424
1562
|
}
|
|
1425
1563
|
// Case 2: Threshold - context is getting large
|
|
1426
|
-
// For error messages
|
|
1427
|
-
// This ensures sessions that hit persistent API errors (e.g. 529)
|
|
1564
|
+
// For error messages or all-zero usage messages, estimate from the last valid response.
|
|
1565
|
+
// This ensures sessions that hit persistent API errors (e.g. 529) or malformed zero-usage
|
|
1566
|
+
// responses can still compact and do not reset context accounting.
|
|
1428
1567
|
let contextTokens;
|
|
1429
|
-
|
|
1568
|
+
const directContextTokens = assistantMessage.usage ? calculateContextTokens(assistantMessage.usage) : 0;
|
|
1569
|
+
if (assistantMessage.stopReason === "error" || directContextTokens === 0) {
|
|
1430
1570
|
const messages = this.agent.state.messages;
|
|
1431
1571
|
const estimate = estimateContextTokens(messages);
|
|
1432
1572
|
if (estimate.lastUsageIndex === null)
|
|
1433
|
-
return; // No usage data at all
|
|
1573
|
+
return false; // No usage data at all
|
|
1434
1574
|
// Verify the usage source is post-compaction. Kept pre-compaction messages
|
|
1435
1575
|
// have stale usage reflecting the old (larger) context and would falsely
|
|
1436
1576
|
// trigger compaction right after one just finished.
|
|
@@ -1438,59 +1578,37 @@ export class AgentSession {
|
|
|
1438
1578
|
if (compactionEntry &&
|
|
1439
1579
|
usageMsg.role === "assistant" &&
|
|
1440
1580
|
usageMsg.timestamp <= new Date(compactionEntry.timestamp).getTime()) {
|
|
1441
|
-
return;
|
|
1581
|
+
return false;
|
|
1442
1582
|
}
|
|
1443
1583
|
contextTokens = estimate.tokens;
|
|
1444
1584
|
}
|
|
1445
1585
|
else {
|
|
1446
|
-
contextTokens =
|
|
1586
|
+
contextTokens = directContextTokens;
|
|
1447
1587
|
}
|
|
1448
1588
|
if (shouldCompact(contextTokens, contextWindow, settings)) {
|
|
1449
|
-
await this._runAutoCompaction("threshold", false);
|
|
1589
|
+
return await this._runAutoCompaction("threshold", false);
|
|
1450
1590
|
}
|
|
1591
|
+
return false;
|
|
1451
1592
|
}
|
|
1452
1593
|
/**
|
|
1453
1594
|
* Internal: Run auto-compaction with events.
|
|
1454
1595
|
*/
|
|
1455
1596
|
async _runAutoCompaction(reason, willRetry) {
|
|
1456
1597
|
const settings = this.settingsManager.getCompactionSettings();
|
|
1457
|
-
|
|
1458
|
-
this._autoCompactionAbortController = new AbortController();
|
|
1598
|
+
let started = false;
|
|
1459
1599
|
try {
|
|
1460
1600
|
if (!this.model) {
|
|
1461
|
-
|
|
1462
|
-
type: "compaction_end",
|
|
1463
|
-
reason,
|
|
1464
|
-
result: undefined,
|
|
1465
|
-
aborted: false,
|
|
1466
|
-
willRetry: false,
|
|
1467
|
-
});
|
|
1468
|
-
return;
|
|
1469
|
-
}
|
|
1470
|
-
const authResult = await this._modelRegistry.getApiKeyAndHeaders(this.model);
|
|
1471
|
-
if (!authResult.ok || !authResult.apiKey) {
|
|
1472
|
-
this._emit({
|
|
1473
|
-
type: "compaction_end",
|
|
1474
|
-
reason,
|
|
1475
|
-
result: undefined,
|
|
1476
|
-
aborted: false,
|
|
1477
|
-
willRetry: false,
|
|
1478
|
-
});
|
|
1479
|
-
return;
|
|
1601
|
+
return false;
|
|
1480
1602
|
}
|
|
1481
|
-
const { apiKey, headers } =
|
|
1603
|
+
const { model: requestModel, apiKey, headers, env } = await this._getSummarizationRequestAuth(this.model);
|
|
1482
1604
|
const pathEntries = this.sessionManager.getBranch();
|
|
1483
1605
|
const preparation = prepareCompaction(pathEntries, settings);
|
|
1484
1606
|
if (!preparation) {
|
|
1485
|
-
|
|
1486
|
-
type: "compaction_end",
|
|
1487
|
-
reason,
|
|
1488
|
-
result: undefined,
|
|
1489
|
-
aborted: false,
|
|
1490
|
-
willRetry: false,
|
|
1491
|
-
});
|
|
1492
|
-
return;
|
|
1607
|
+
return false;
|
|
1493
1608
|
}
|
|
1609
|
+
this._emit({ type: "compaction_start", reason });
|
|
1610
|
+
this._autoCompactionAbortController = new AbortController();
|
|
1611
|
+
started = true;
|
|
1494
1612
|
let extensionCompaction;
|
|
1495
1613
|
let fromExtension = false;
|
|
1496
1614
|
if (this._extensionRunner.hasHandlers("session_before_compact")) {
|
|
@@ -1499,6 +1617,8 @@ export class AgentSession {
|
|
|
1499
1617
|
preparation,
|
|
1500
1618
|
branchEntries: pathEntries,
|
|
1501
1619
|
customInstructions: undefined,
|
|
1620
|
+
reason,
|
|
1621
|
+
willRetry,
|
|
1502
1622
|
signal: this._autoCompactionAbortController.signal,
|
|
1503
1623
|
}));
|
|
1504
1624
|
if (extensionResult?.cancel) {
|
|
@@ -1509,7 +1629,7 @@ export class AgentSession {
|
|
|
1509
1629
|
aborted: true,
|
|
1510
1630
|
willRetry: false,
|
|
1511
1631
|
});
|
|
1512
|
-
return;
|
|
1632
|
+
return false;
|
|
1513
1633
|
}
|
|
1514
1634
|
if (extensionResult?.compaction) {
|
|
1515
1635
|
extensionCompaction = extensionResult.compaction;
|
|
@@ -1519,20 +1639,23 @@ export class AgentSession {
|
|
|
1519
1639
|
let summary;
|
|
1520
1640
|
let firstKeptEntryId;
|
|
1521
1641
|
let tokensBefore;
|
|
1642
|
+
let usage;
|
|
1522
1643
|
let details;
|
|
1523
1644
|
if (extensionCompaction) {
|
|
1524
1645
|
// Extension provided compaction content
|
|
1525
1646
|
summary = extensionCompaction.summary;
|
|
1526
1647
|
firstKeptEntryId = extensionCompaction.firstKeptEntryId;
|
|
1527
1648
|
tokensBefore = extensionCompaction.tokensBefore;
|
|
1649
|
+
usage = extensionCompaction.usage;
|
|
1528
1650
|
details = extensionCompaction.details;
|
|
1529
1651
|
}
|
|
1530
1652
|
else {
|
|
1531
1653
|
// Generate compaction result
|
|
1532
|
-
const compactResult = await compact(preparation,
|
|
1654
|
+
const compactResult = await compact(preparation, requestModel, apiKey, headers, undefined, this._autoCompactionAbortController.signal, this.thinkingLevel, this.agent.streamFunction, env, this.settingsManager.getRetrySettings(), this._summarizationRetryCallbacks({ source: "compaction", reason }));
|
|
1533
1655
|
summary = compactResult.summary;
|
|
1534
1656
|
firstKeptEntryId = compactResult.firstKeptEntryId;
|
|
1535
1657
|
tokensBefore = compactResult.tokensBefore;
|
|
1658
|
+
usage = compactResult.usage;
|
|
1536
1659
|
details = compactResult.details;
|
|
1537
1660
|
}
|
|
1538
1661
|
if (this._autoCompactionAbortController.signal.aborted) {
|
|
@@ -1543,12 +1666,13 @@ export class AgentSession {
|
|
|
1543
1666
|
aborted: true,
|
|
1544
1667
|
willRetry: false,
|
|
1545
1668
|
});
|
|
1546
|
-
return;
|
|
1669
|
+
return false;
|
|
1547
1670
|
}
|
|
1548
|
-
this.sessionManager.appendCompaction(summary, firstKeptEntryId, tokensBefore, details, fromExtension);
|
|
1671
|
+
this.sessionManager.appendCompaction(summary, firstKeptEntryId, tokensBefore, details, fromExtension, usage);
|
|
1549
1672
|
const newEntries = this.sessionManager.getEntries();
|
|
1550
1673
|
const sessionContext = this.sessionManager.buildSessionContext();
|
|
1551
1674
|
this.agent.state.messages = sessionContext.messages;
|
|
1675
|
+
const estimatedTokensAfter = estimateMessagesTokens(sessionContext.messages);
|
|
1552
1676
|
// Get the saved compaction entry for the extension event
|
|
1553
1677
|
const savedCompactionEntry = newEntries.find((e) => e.type === "compaction" && e.summary === summary);
|
|
1554
1678
|
if (this._extensionRunner && savedCompactionEntry) {
|
|
@@ -1556,45 +1680,50 @@ export class AgentSession {
|
|
|
1556
1680
|
type: "session_compact",
|
|
1557
1681
|
compactionEntry: savedCompactionEntry,
|
|
1558
1682
|
fromExtension,
|
|
1683
|
+
reason,
|
|
1684
|
+
willRetry,
|
|
1559
1685
|
});
|
|
1560
1686
|
}
|
|
1561
1687
|
const result = {
|
|
1562
1688
|
summary,
|
|
1563
1689
|
firstKeptEntryId,
|
|
1564
1690
|
tokensBefore,
|
|
1691
|
+
estimatedTokensAfter,
|
|
1692
|
+
usage,
|
|
1565
1693
|
details,
|
|
1566
1694
|
};
|
|
1567
1695
|
this._emit({ type: "compaction_end", reason, result, aborted: false, willRetry });
|
|
1568
1696
|
if (willRetry) {
|
|
1569
1697
|
const messages = this.agent.state.messages;
|
|
1570
1698
|
const lastMsg = messages[messages.length - 1];
|
|
1571
|
-
|
|
1699
|
+
// The overflow response was persisted on message_end before _checkCompaction() removed it
|
|
1700
|
+
// from agent state. Rebuilding state from the new compaction can restore that kept entry,
|
|
1701
|
+
// leaving an assistant as the final message. agent.continue() rejects that state, so remove
|
|
1702
|
+
// the retriable error or truncated-length response again before continuing the interrupted turn.
|
|
1703
|
+
if (lastMsg?.role === "assistant" && (lastMsg.stopReason === "error" || lastMsg.stopReason === "length")) {
|
|
1572
1704
|
this.agent.state.messages = messages.slice(0, -1);
|
|
1573
1705
|
}
|
|
1574
|
-
|
|
1575
|
-
this.agent.continue().catch(() => { });
|
|
1576
|
-
}, 100);
|
|
1577
|
-
}
|
|
1578
|
-
else if (this.agent.hasQueuedMessages()) {
|
|
1579
|
-
// Auto-compaction can complete while follow-up/steering/custom messages are waiting.
|
|
1580
|
-
// Kick the loop so queued messages are actually delivered.
|
|
1581
|
-
setTimeout(() => {
|
|
1582
|
-
this.agent.continue().catch(() => { });
|
|
1583
|
-
}, 100);
|
|
1706
|
+
return true;
|
|
1584
1707
|
}
|
|
1708
|
+
// Auto-compaction can complete while follow-up/steering/custom messages are waiting.
|
|
1709
|
+
// Continue once so queued messages are delivered.
|
|
1710
|
+
return this.agent.hasQueuedMessages();
|
|
1585
1711
|
}
|
|
1586
1712
|
catch (error) {
|
|
1587
1713
|
const errorMessage = error instanceof Error ? error.message : "compaction failed";
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1714
|
+
if (started) {
|
|
1715
|
+
this._emit({
|
|
1716
|
+
type: "compaction_end",
|
|
1717
|
+
reason,
|
|
1718
|
+
result: undefined,
|
|
1719
|
+
aborted: false,
|
|
1720
|
+
willRetry: false,
|
|
1721
|
+
errorMessage: reason === "overflow"
|
|
1722
|
+
? `Context overflow recovery failed: ${errorMessage}`
|
|
1723
|
+
: `Auto-compaction failed: ${errorMessage}`,
|
|
1724
|
+
});
|
|
1725
|
+
}
|
|
1726
|
+
return false;
|
|
1598
1727
|
}
|
|
1599
1728
|
finally {
|
|
1600
1729
|
this._autoCompactionAbortController = undefined;
|
|
@@ -1614,9 +1743,15 @@ export class AgentSession {
|
|
|
1614
1743
|
if (bindings.uiContext !== undefined) {
|
|
1615
1744
|
this._extensionUIContext = bindings.uiContext;
|
|
1616
1745
|
}
|
|
1746
|
+
if (bindings.mode !== undefined) {
|
|
1747
|
+
this._extensionMode = bindings.mode;
|
|
1748
|
+
}
|
|
1617
1749
|
if (bindings.commandContextActions !== undefined) {
|
|
1618
1750
|
this._extensionCommandContextActions = bindings.commandContextActions;
|
|
1619
1751
|
}
|
|
1752
|
+
if (bindings.abortHandler !== undefined) {
|
|
1753
|
+
this._extensionAbortHandler = bindings.abortHandler;
|
|
1754
|
+
}
|
|
1620
1755
|
if (bindings.shutdownHandler !== undefined) {
|
|
1621
1756
|
this._extensionShutdownHandler = bindings.shutdownHandler;
|
|
1622
1757
|
}
|
|
@@ -1641,8 +1776,7 @@ export class AgentSession {
|
|
|
1641
1776
|
themePaths: this.buildExtensionResourcePaths(themePaths),
|
|
1642
1777
|
};
|
|
1643
1778
|
this._resourceLoader.extendResources(extensionPaths);
|
|
1644
|
-
|
|
1645
|
-
this._baseSystemPrompt = this._rebuildSystemPrompt(promptToolNames);
|
|
1779
|
+
this._baseSystemPrompt = this._rebuildSystemPrompt(this.getActiveToolNames());
|
|
1646
1780
|
this.agent.state.systemPrompt = this._baseSystemPrompt;
|
|
1647
1781
|
}
|
|
1648
1782
|
buildExtensionResourcePaths(entries) {
|
|
@@ -1669,7 +1803,7 @@ export class AgentSession {
|
|
|
1669
1803
|
return `extension:${name}`;
|
|
1670
1804
|
}
|
|
1671
1805
|
_applyExtensionBindings(runner) {
|
|
1672
|
-
runner.setUIContext(this._extensionUIContext);
|
|
1806
|
+
runner.setUIContext(this._extensionUIContext, this._extensionMode);
|
|
1673
1807
|
runner.bindCommandContext(this._extensionCommandContextActions);
|
|
1674
1808
|
this._extensionErrorUnsubscriber?.();
|
|
1675
1809
|
this._extensionErrorUnsubscriber = this._extensionErrorListener
|
|
@@ -1681,7 +1815,7 @@ export class AgentSession {
|
|
|
1681
1815
|
if (!currentModel) {
|
|
1682
1816
|
return;
|
|
1683
1817
|
}
|
|
1684
|
-
const refreshedModel = this.
|
|
1818
|
+
const refreshedModel = this._modelRuntime.getModel(currentModel.provider, currentModel.id);
|
|
1685
1819
|
if (!refreshedModel || refreshedModel === currentModel) {
|
|
1686
1820
|
return;
|
|
1687
1821
|
}
|
|
@@ -1729,10 +1863,14 @@ export class AgentSession {
|
|
|
1729
1863
|
});
|
|
1730
1864
|
},
|
|
1731
1865
|
appendEntry: (customType, data) => {
|
|
1732
|
-
this.sessionManager.appendCustomEntry(customType, data);
|
|
1866
|
+
const entryId = this.sessionManager.appendCustomEntry(customType, data);
|
|
1867
|
+
const entry = this.sessionManager.getEntry(entryId);
|
|
1868
|
+
if (entry) {
|
|
1869
|
+
this._emit({ type: "entry_appended", entry });
|
|
1870
|
+
}
|
|
1733
1871
|
},
|
|
1734
1872
|
setSessionName: (name) => {
|
|
1735
|
-
this.
|
|
1873
|
+
this.setSessionName(name);
|
|
1736
1874
|
},
|
|
1737
1875
|
getSessionName: () => {
|
|
1738
1876
|
return this.sessionManager.getSessionName();
|
|
@@ -1746,7 +1884,7 @@ export class AgentSession {
|
|
|
1746
1884
|
refreshTools: () => this._refreshToolRegistry(),
|
|
1747
1885
|
getCommands,
|
|
1748
1886
|
setModel: async (model) => {
|
|
1749
|
-
if (!this.
|
|
1887
|
+
if (!this._modelRuntime.hasConfiguredAuth(model.provider))
|
|
1750
1888
|
return false;
|
|
1751
1889
|
await this.setModel(model);
|
|
1752
1890
|
return true;
|
|
@@ -1755,9 +1893,17 @@ export class AgentSession {
|
|
|
1755
1893
|
setThinkingLevel: (level) => this.setThinkingLevel(level),
|
|
1756
1894
|
}, {
|
|
1757
1895
|
getModel: () => this.model,
|
|
1758
|
-
|
|
1896
|
+
getScopedModels: () => this._scopedModels,
|
|
1897
|
+
isIdle: () => this.isIdle,
|
|
1898
|
+
isProjectTrusted: () => this.settingsManager.isProjectTrusted(),
|
|
1759
1899
|
getSignal: () => this.agent.signal,
|
|
1760
|
-
abort: () =>
|
|
1900
|
+
abort: () => {
|
|
1901
|
+
if (this._extensionAbortHandler) {
|
|
1902
|
+
this._extensionAbortHandler();
|
|
1903
|
+
return;
|
|
1904
|
+
}
|
|
1905
|
+
void this.abort();
|
|
1906
|
+
},
|
|
1761
1907
|
hasPendingMessages: () => this.pendingMessageCount > 0,
|
|
1762
1908
|
shutdown: () => {
|
|
1763
1909
|
this._extensionShutdownHandler?.();
|
|
@@ -1776,13 +1922,18 @@ export class AgentSession {
|
|
|
1776
1922
|
})();
|
|
1777
1923
|
},
|
|
1778
1924
|
getSystemPrompt: () => this.systemPrompt,
|
|
1925
|
+
getSystemPromptOptions: () => this._baseSystemPromptOptions,
|
|
1779
1926
|
}, {
|
|
1780
1927
|
registerProvider: (name, config) => {
|
|
1781
|
-
this.
|
|
1928
|
+
this._modelRuntime.registerProvider(name, config);
|
|
1929
|
+
this._refreshCurrentModelFromRegistry();
|
|
1930
|
+
},
|
|
1931
|
+
registerNativeProvider: (provider) => {
|
|
1932
|
+
this._modelRuntime.registerNativeProvider(provider);
|
|
1782
1933
|
this._refreshCurrentModelFromRegistry();
|
|
1783
1934
|
},
|
|
1784
1935
|
unregisterProvider: (name) => {
|
|
1785
|
-
this.
|
|
1936
|
+
this._modelRuntime.unregisterProvider(name);
|
|
1786
1937
|
this._refreshCurrentModelFromRegistry();
|
|
1787
1938
|
},
|
|
1788
1939
|
});
|
|
@@ -1791,7 +1942,8 @@ export class AgentSession {
|
|
|
1791
1942
|
const previousRegistryNames = new Set(this._toolRegistry.keys());
|
|
1792
1943
|
const previousActiveToolNames = this.getActiveToolNames();
|
|
1793
1944
|
const allowedToolNames = this._allowedToolNames;
|
|
1794
|
-
const
|
|
1945
|
+
const excludedToolNames = this._excludedToolNames;
|
|
1946
|
+
const isAllowedTool = (name) => (!allowedToolNames || allowedToolNames.has(name)) && !excludedToolNames?.has(name);
|
|
1795
1947
|
const registeredTools = this._extensionRunner.getAllRegisteredTools();
|
|
1796
1948
|
const allCustomTools = [
|
|
1797
1949
|
...registeredTools,
|
|
@@ -1874,7 +2026,16 @@ export class AgentSession {
|
|
|
1874
2026
|
]))
|
|
1875
2027
|
: createAllToolDefinitions(this._cwd, {
|
|
1876
2028
|
read: { autoResizeImages },
|
|
1877
|
-
bash: {
|
|
2029
|
+
bash: {
|
|
2030
|
+
commandPrefix: shellCommandPrefix,
|
|
2031
|
+
shellPath,
|
|
2032
|
+
// Read the runner at spawn time so extension reload swaps in the new
|
|
2033
|
+
// session environment without rebuilding the tool.
|
|
2034
|
+
spawnHook: (context) => ({
|
|
2035
|
+
...context,
|
|
2036
|
+
env: applyEnvOverlay(context.env, this._extensionRunner.getSessionEnv()),
|
|
2037
|
+
}),
|
|
2038
|
+
},
|
|
1878
2039
|
});
|
|
1879
2040
|
this._baseToolDefinitions = new Map(Object.entries(baseToolDefinitions).map(([name, tool]) => [name, tool]));
|
|
1880
2041
|
const extensionsResult = this._resourceLoader.getExtensions();
|
|
@@ -1883,7 +2044,7 @@ export class AgentSession {
|
|
|
1883
2044
|
extensionsResult.runtime.flagValues.set(name, value);
|
|
1884
2045
|
}
|
|
1885
2046
|
}
|
|
1886
|
-
this._extensionRunner = new ExtensionRunner(extensionsResult.extensions, extensionsResult.runtime, this._cwd, this.sessionManager, this.
|
|
2047
|
+
this._extensionRunner = new ExtensionRunner(extensionsResult.extensions, extensionsResult.runtime, this._cwd, this.sessionManager, new ModelRegistry(this._modelRuntime));
|
|
1887
2048
|
if (this._extensionRunnerRef) {
|
|
1888
2049
|
this._extensionRunnerRef.current = this._extensionRunner;
|
|
1889
2050
|
}
|
|
@@ -1898,10 +2059,13 @@ export class AgentSession {
|
|
|
1898
2059
|
includeAllExtensionTools: options.includeAllExtensionTools,
|
|
1899
2060
|
});
|
|
1900
2061
|
}
|
|
1901
|
-
async reload() {
|
|
1902
|
-
const
|
|
1903
|
-
|
|
2062
|
+
async reload(options) {
|
|
2063
|
+
const oldRunner = this._extensionRunner;
|
|
2064
|
+
const previousFlagValues = oldRunner.getFlagValues();
|
|
2065
|
+
await emitSessionShutdownEvent(oldRunner, { type: "session_shutdown", reason: "reload" });
|
|
2066
|
+
oldRunner.invalidate();
|
|
1904
2067
|
await this.settingsManager.reload();
|
|
2068
|
+
this.syncQueueModesFromSettings();
|
|
1905
2069
|
resetApiProviders();
|
|
1906
2070
|
await this._resourceLoader.reload();
|
|
1907
2071
|
this._buildRuntime({
|
|
@@ -1914,6 +2078,7 @@ export class AgentSession {
|
|
|
1914
2078
|
this._extensionShutdownHandler ||
|
|
1915
2079
|
this._extensionErrorListener;
|
|
1916
2080
|
if (hasBindings) {
|
|
2081
|
+
await options?.beforeSessionStart?.();
|
|
1917
2082
|
await this._extensionRunner.emit({ type: "session_start", reason: "reload" });
|
|
1918
2083
|
await this.extendResourcesFromExtensions("reload");
|
|
1919
2084
|
}
|
|
@@ -1926,44 +2091,52 @@ export class AgentSession {
|
|
|
1926
2091
|
* Context overflow errors are NOT retryable (handled by compaction instead).
|
|
1927
2092
|
*/
|
|
1928
2093
|
_isRetryableError(message) {
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
// Context overflow is handled by compaction, not retry
|
|
1932
|
-
const contextWindow = this.model?.contextWindow ?? 0;
|
|
1933
|
-
if (isContextOverflow(message, contextWindow))
|
|
2094
|
+
// Context overflow is handled by compaction, not retry.
|
|
2095
|
+
if (isContextOverflow(message, this.model?.contextWindow ?? 0))
|
|
1934
2096
|
return false;
|
|
1935
|
-
|
|
1936
|
-
// Match: overloaded_error, provider returned error, rate limit, 429, 500, 502, 503, 504, service unavailable, network/connection errors (including connection lost), fetch failed, request ended without sending chunks, HTTP/2 closed before response, terminated, retry delay exceeded
|
|
1937
|
-
return /overloaded|provider.?returned.?error|rate.?limit|too many requests|429|500|502|503|504|service.?unavailable|server.?error|internal.?error|network.?error|connection.?error|connection.?refused|connection.?lost|other side closed|fetch failed|upstream.?connect|reset before headers|socket hang up|ended without|http2 request did not get a response|timed? out|timeout|terminated|retry delay/i.test(err);
|
|
2097
|
+
return isRetryableAssistantError(message);
|
|
1938
2098
|
}
|
|
1939
2099
|
/**
|
|
1940
|
-
*
|
|
1941
|
-
*
|
|
2100
|
+
* Retry policy + callbacks shared by compaction and branch-summary summarization calls.
|
|
2101
|
+
* Uses the same `settings.retry` budget/backoff as agent-turn retries so a single transient
|
|
2102
|
+
* stream drop no longer fails the whole operation. `source` carries the context
|
|
2103
|
+
* the TUI needs to render the retry and recreate the underlying indicator.
|
|
1942
2104
|
*/
|
|
1943
|
-
|
|
2105
|
+
_summarizationRetryCallbacks(source) {
|
|
2106
|
+
return {
|
|
2107
|
+
onRetryScheduled: (attempt, maxAttempts, delayMs, errorMessage) => {
|
|
2108
|
+
this._emit({
|
|
2109
|
+
type: "summarization_retry_scheduled",
|
|
2110
|
+
attempt,
|
|
2111
|
+
maxAttempts,
|
|
2112
|
+
delayMs,
|
|
2113
|
+
errorMessage,
|
|
2114
|
+
});
|
|
2115
|
+
},
|
|
2116
|
+
onRetryAttemptStart: () => {
|
|
2117
|
+
this._emit({
|
|
2118
|
+
type: "summarization_retry_attempt_start",
|
|
2119
|
+
...source,
|
|
2120
|
+
});
|
|
2121
|
+
},
|
|
2122
|
+
onRetryFinished: () => {
|
|
2123
|
+
this._emit({ type: "summarization_retry_finished" });
|
|
2124
|
+
},
|
|
2125
|
+
};
|
|
2126
|
+
}
|
|
2127
|
+
/**
|
|
2128
|
+
* Prepare a retryable error for continuation with exponential backoff.
|
|
2129
|
+
* @returns true if the caller should continue the agent, false otherwise
|
|
2130
|
+
*/
|
|
2131
|
+
async _prepareRetry(message) {
|
|
1944
2132
|
const settings = this.settingsManager.getRetrySettings();
|
|
1945
2133
|
if (!settings.enabled) {
|
|
1946
|
-
this._resolveRetry();
|
|
1947
2134
|
return false;
|
|
1948
2135
|
}
|
|
1949
|
-
// Retry promise is created synchronously in _handleAgentEvent for agent_end.
|
|
1950
|
-
// Keep a defensive fallback here in case a future refactor bypasses that path.
|
|
1951
|
-
if (!this._retryPromise) {
|
|
1952
|
-
this._retryPromise = new Promise((resolve) => {
|
|
1953
|
-
this._retryResolve = resolve;
|
|
1954
|
-
});
|
|
1955
|
-
}
|
|
1956
2136
|
this._retryAttempt++;
|
|
1957
2137
|
if (this._retryAttempt > settings.maxRetries) {
|
|
1958
|
-
//
|
|
1959
|
-
this.
|
|
1960
|
-
type: "auto_retry_end",
|
|
1961
|
-
success: false,
|
|
1962
|
-
attempt: this._retryAttempt - 1,
|
|
1963
|
-
finalError: message.errorMessage,
|
|
1964
|
-
});
|
|
1965
|
-
this._retryAttempt = 0;
|
|
1966
|
-
this._resolveRetry(); // Resolve so waitForRetry() completes
|
|
2138
|
+
// Preserve the completed attempt count so post-run handling can emit the final failure.
|
|
2139
|
+
this._retryAttempt--;
|
|
1967
2140
|
return false;
|
|
1968
2141
|
}
|
|
1969
2142
|
const delayMs = settings.baseDelayMs * 2 ** (this._retryAttempt - 1);
|
|
@@ -1988,23 +2161,17 @@ export class AgentSession {
|
|
|
1988
2161
|
// Aborted during sleep - emit end event so UI can clean up
|
|
1989
2162
|
const attempt = this._retryAttempt;
|
|
1990
2163
|
this._retryAttempt = 0;
|
|
1991
|
-
this._retryAbortController = undefined;
|
|
1992
2164
|
this._emit({
|
|
1993
2165
|
type: "auto_retry_end",
|
|
1994
2166
|
success: false,
|
|
1995
2167
|
attempt,
|
|
1996
2168
|
finalError: "Retry cancelled",
|
|
1997
2169
|
});
|
|
1998
|
-
this._resolveRetry();
|
|
1999
2170
|
return false;
|
|
2000
2171
|
}
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
this.agent.continue().catch(() => {
|
|
2005
|
-
// Retry failed - will be caught by next agent_end
|
|
2006
|
-
});
|
|
2007
|
-
}, 0);
|
|
2172
|
+
finally {
|
|
2173
|
+
this._retryAbortController = undefined;
|
|
2174
|
+
}
|
|
2008
2175
|
return true;
|
|
2009
2176
|
}
|
|
2010
2177
|
/**
|
|
@@ -2012,23 +2179,10 @@ export class AgentSession {
|
|
|
2012
2179
|
*/
|
|
2013
2180
|
abortRetry() {
|
|
2014
2181
|
this._retryAbortController?.abort();
|
|
2015
|
-
// Note: _retryAttempt is reset in the catch block of _autoRetry
|
|
2016
|
-
this._resolveRetry();
|
|
2017
|
-
}
|
|
2018
|
-
/**
|
|
2019
|
-
* Wait for any in-progress retry to complete.
|
|
2020
|
-
* Returns immediately if no retry is in progress.
|
|
2021
|
-
*/
|
|
2022
|
-
async waitForRetry() {
|
|
2023
|
-
if (!this._retryPromise) {
|
|
2024
|
-
return;
|
|
2025
|
-
}
|
|
2026
|
-
await this._retryPromise;
|
|
2027
|
-
await this.agent.waitForIdle();
|
|
2028
2182
|
}
|
|
2029
2183
|
/** Whether auto-retry is currently in progress */
|
|
2030
2184
|
get isRetrying() {
|
|
2031
|
-
return this.
|
|
2185
|
+
return this._retryAbortController !== undefined;
|
|
2032
2186
|
}
|
|
2033
2187
|
/** Whether auto-retry is enabled */
|
|
2034
2188
|
get autoRetryEnabled() {
|
|
@@ -2049,24 +2203,29 @@ export class AgentSession {
|
|
|
2049
2203
|
* @param command The bash command to execute
|
|
2050
2204
|
* @param onChunk Optional streaming callback for output
|
|
2051
2205
|
* @param options.excludeFromContext If true, command output won't be sent to LLM (!! prefix)
|
|
2206
|
+
* @param options.id Optional identifier included in bash execution update events
|
|
2052
2207
|
* @param options.operations Custom BashOperations for remote execution
|
|
2053
2208
|
*/
|
|
2054
2209
|
async executeBash(command, onChunk, options) {
|
|
2055
|
-
|
|
2210
|
+
const abortController = new AbortController();
|
|
2211
|
+
this._bashAbortControllers.add(abortController);
|
|
2056
2212
|
// Apply command prefix if configured (e.g., "shopt -s expand_aliases" for alias support)
|
|
2057
2213
|
const prefix = this.settingsManager.getShellCommandPrefix();
|
|
2058
2214
|
const shellPath = this.settingsManager.getShellPath();
|
|
2059
2215
|
const resolvedCommand = prefix ? `${prefix}\n${command}` : command;
|
|
2060
2216
|
try {
|
|
2061
2217
|
const result = await executeBashWithOperations(resolvedCommand, this.sessionManager.getCwd(), options?.operations ?? createLocalBashOperations({ shellPath }), {
|
|
2062
|
-
onChunk
|
|
2063
|
-
|
|
2218
|
+
onChunk: (delta) => {
|
|
2219
|
+
onChunk?.(delta);
|
|
2220
|
+
this._emit({ type: "bash_execution_update", id: options?.id, delta });
|
|
2221
|
+
},
|
|
2222
|
+
signal: abortController.signal,
|
|
2064
2223
|
});
|
|
2065
2224
|
this.recordBashResult(command, result, options);
|
|
2066
2225
|
return result;
|
|
2067
2226
|
}
|
|
2068
2227
|
finally {
|
|
2069
|
-
this.
|
|
2228
|
+
this._bashAbortControllers.delete(abortController);
|
|
2070
2229
|
}
|
|
2071
2230
|
}
|
|
2072
2231
|
/**
|
|
@@ -2101,11 +2260,13 @@ export class AgentSession {
|
|
|
2101
2260
|
* Cancel running bash command.
|
|
2102
2261
|
*/
|
|
2103
2262
|
abortBash() {
|
|
2104
|
-
this.
|
|
2263
|
+
for (const abortController of [...this._bashAbortControllers]) {
|
|
2264
|
+
abortController.abort();
|
|
2265
|
+
}
|
|
2105
2266
|
}
|
|
2106
2267
|
/** Whether a bash command is currently running */
|
|
2107
2268
|
get isBashRunning() {
|
|
2108
|
-
return this.
|
|
2269
|
+
return this._bashAbortControllers.size > 0;
|
|
2109
2270
|
}
|
|
2110
2271
|
/** Whether there are pending bash messages waiting to be flushed */
|
|
2111
2272
|
get hasPendingBashMessages() {
|
|
@@ -2134,6 +2295,9 @@ export class AgentSession {
|
|
|
2134
2295
|
*/
|
|
2135
2296
|
setSessionName(name) {
|
|
2136
2297
|
this.sessionManager.appendSessionInfo(name);
|
|
2298
|
+
const event = { type: "session_info_changed", name: this.sessionManager.getSessionName() };
|
|
2299
|
+
this._emit(event);
|
|
2300
|
+
void this._extensionRunner.emit(event);
|
|
2137
2301
|
}
|
|
2138
2302
|
// =========================================================================
|
|
2139
2303
|
// Tree Navigation
|
|
@@ -2150,6 +2314,9 @@ export class AgentSession {
|
|
|
2150
2314
|
* @returns Result with editorText (if user message) and cancelled status
|
|
2151
2315
|
*/
|
|
2152
2316
|
async navigateTree(targetId, options = {}) {
|
|
2317
|
+
if (this.isStreaming) {
|
|
2318
|
+
throw new Error("Wait for the current response to finish before navigating the session tree.");
|
|
2319
|
+
}
|
|
2153
2320
|
const oldLeafId = this.sessionManager.getLeafId();
|
|
2154
2321
|
// No-op if already at target
|
|
2155
2322
|
if (targetId === oldLeafId) {
|
|
@@ -2181,127 +2348,131 @@ export class AgentSession {
|
|
|
2181
2348
|
};
|
|
2182
2349
|
// Set up abort controller for summarization
|
|
2183
2350
|
this._branchSummaryAbortController = new AbortController();
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
customInstructions
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
replaceInstructions
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
label
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2351
|
+
try {
|
|
2352
|
+
let extensionSummary;
|
|
2353
|
+
let fromExtension = false;
|
|
2354
|
+
// Emit session_before_tree event
|
|
2355
|
+
if (this._extensionRunner.hasHandlers("session_before_tree")) {
|
|
2356
|
+
const result = (await this._extensionRunner.emit({
|
|
2357
|
+
type: "session_before_tree",
|
|
2358
|
+
preparation,
|
|
2359
|
+
signal: this._branchSummaryAbortController.signal,
|
|
2360
|
+
}));
|
|
2361
|
+
if (result?.cancel) {
|
|
2362
|
+
return { cancelled: true };
|
|
2363
|
+
}
|
|
2364
|
+
if (result?.summary && options.summarize) {
|
|
2365
|
+
extensionSummary = result.summary;
|
|
2366
|
+
fromExtension = true;
|
|
2367
|
+
}
|
|
2368
|
+
// Allow extensions to override instructions and label
|
|
2369
|
+
if (result?.customInstructions !== undefined) {
|
|
2370
|
+
customInstructions = result.customInstructions;
|
|
2371
|
+
}
|
|
2372
|
+
if (result?.replaceInstructions !== undefined) {
|
|
2373
|
+
replaceInstructions = result.replaceInstructions;
|
|
2374
|
+
}
|
|
2375
|
+
if (result?.label !== undefined) {
|
|
2376
|
+
label = result.label;
|
|
2377
|
+
}
|
|
2378
|
+
}
|
|
2379
|
+
// Run default summarizer if needed
|
|
2380
|
+
let summaryText;
|
|
2381
|
+
let summaryDetails;
|
|
2382
|
+
let summaryUsage;
|
|
2383
|
+
if (options.summarize && entriesToSummarize.length > 0 && !extensionSummary) {
|
|
2384
|
+
const model = this.model;
|
|
2385
|
+
const { model: requestModel, apiKey, headers, env } = await this._getSummarizationRequestAuth(model);
|
|
2386
|
+
const branchSummarySettings = this.settingsManager.getBranchSummarySettings();
|
|
2387
|
+
const result = await generateBranchSummary(entriesToSummarize, {
|
|
2388
|
+
model: requestModel,
|
|
2389
|
+
apiKey,
|
|
2390
|
+
headers,
|
|
2391
|
+
env,
|
|
2392
|
+
signal: this._branchSummaryAbortController.signal,
|
|
2393
|
+
customInstructions,
|
|
2394
|
+
replaceInstructions,
|
|
2395
|
+
reserveTokens: branchSummarySettings.reserveTokens,
|
|
2396
|
+
streamFn: this.agent.streamFunction,
|
|
2397
|
+
retry: this.settingsManager.getRetrySettings(),
|
|
2398
|
+
callbacks: this._summarizationRetryCallbacks({ source: "branchSummary" }),
|
|
2399
|
+
});
|
|
2400
|
+
if (result.aborted) {
|
|
2401
|
+
return { cancelled: true, aborted: true };
|
|
2402
|
+
}
|
|
2403
|
+
if (result.error) {
|
|
2404
|
+
throw new Error(result.error);
|
|
2405
|
+
}
|
|
2406
|
+
summaryText = result.summary;
|
|
2407
|
+
summaryUsage = result.usage;
|
|
2408
|
+
summaryDetails = {
|
|
2409
|
+
readFiles: result.readFiles || [],
|
|
2410
|
+
modifiedFiles: result.modifiedFiles || [],
|
|
2411
|
+
};
|
|
2412
|
+
}
|
|
2413
|
+
else if (extensionSummary) {
|
|
2414
|
+
summaryText = extensionSummary.summary;
|
|
2415
|
+
summaryDetails = extensionSummary.details;
|
|
2416
|
+
summaryUsage = extensionSummary.usage;
|
|
2417
|
+
}
|
|
2418
|
+
// Determine the new leaf position based on target type
|
|
2419
|
+
let newLeafId;
|
|
2420
|
+
let editorText;
|
|
2421
|
+
if (targetEntry.type === "message" && targetEntry.message.role === "user") {
|
|
2422
|
+
// User message: leaf = parent (null if root), text goes to editor
|
|
2423
|
+
newLeafId = targetEntry.parentId;
|
|
2424
|
+
editorText = contentText(targetEntry.message.content, "");
|
|
2425
|
+
}
|
|
2426
|
+
else if (targetEntry.type === "custom_message") {
|
|
2427
|
+
// Custom message: leaf = parent (null if root), text goes to editor
|
|
2428
|
+
newLeafId = targetEntry.parentId;
|
|
2429
|
+
editorText = contentText(targetEntry.content, "");
|
|
2230
2430
|
}
|
|
2231
|
-
|
|
2232
|
-
|
|
2431
|
+
else {
|
|
2432
|
+
// Non-user message: leaf = selected node
|
|
2433
|
+
newLeafId = targetId;
|
|
2434
|
+
}
|
|
2435
|
+
// Switch leaf (with or without summary)
|
|
2436
|
+
// Summary is attached at the navigation target position (newLeafId), not the old branch
|
|
2437
|
+
let summaryEntry;
|
|
2438
|
+
if (summaryText) {
|
|
2439
|
+
// Create summary at target position (can be null for root)
|
|
2440
|
+
const summaryId = this.sessionManager.branchWithSummary(newLeafId, summaryText, summaryDetails, fromExtension, summaryUsage);
|
|
2441
|
+
summaryEntry = this.sessionManager.getEntry(summaryId);
|
|
2442
|
+
// Attach label to the summary entry
|
|
2443
|
+
if (label) {
|
|
2444
|
+
this.sessionManager.appendLabelChange(summaryId, label);
|
|
2445
|
+
}
|
|
2233
2446
|
}
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
modifiedFiles: result.modifiedFiles || [],
|
|
2238
|
-
};
|
|
2239
|
-
}
|
|
2240
|
-
else if (extensionSummary) {
|
|
2241
|
-
summaryText = extensionSummary.summary;
|
|
2242
|
-
summaryDetails = extensionSummary.details;
|
|
2243
|
-
}
|
|
2244
|
-
// Determine the new leaf position based on target type
|
|
2245
|
-
let newLeafId;
|
|
2246
|
-
let editorText;
|
|
2247
|
-
if (targetEntry.type === "message" && targetEntry.message.role === "user") {
|
|
2248
|
-
// User message: leaf = parent (null if root), text goes to editor
|
|
2249
|
-
newLeafId = targetEntry.parentId;
|
|
2250
|
-
editorText = this._extractUserMessageText(targetEntry.message.content);
|
|
2251
|
-
}
|
|
2252
|
-
else if (targetEntry.type === "custom_message") {
|
|
2253
|
-
// Custom message: leaf = parent (null if root), text goes to editor
|
|
2254
|
-
newLeafId = targetEntry.parentId;
|
|
2255
|
-
editorText =
|
|
2256
|
-
typeof targetEntry.content === "string"
|
|
2257
|
-
? targetEntry.content
|
|
2258
|
-
: targetEntry.content
|
|
2259
|
-
.filter((c) => c.type === "text")
|
|
2260
|
-
.map((c) => c.text)
|
|
2261
|
-
.join("");
|
|
2262
|
-
}
|
|
2263
|
-
else {
|
|
2264
|
-
// Non-user message: leaf = selected node
|
|
2265
|
-
newLeafId = targetId;
|
|
2266
|
-
}
|
|
2267
|
-
// Switch leaf (with or without summary)
|
|
2268
|
-
// Summary is attached at the navigation target position (newLeafId), not the old branch
|
|
2269
|
-
let summaryEntry;
|
|
2270
|
-
if (summaryText) {
|
|
2271
|
-
// Create summary at target position (can be null for root)
|
|
2272
|
-
const summaryId = this.sessionManager.branchWithSummary(newLeafId, summaryText, summaryDetails, fromExtension);
|
|
2273
|
-
summaryEntry = this.sessionManager.getEntry(summaryId);
|
|
2274
|
-
// Attach label to the summary entry
|
|
2275
|
-
if (label) {
|
|
2276
|
-
this.sessionManager.appendLabelChange(summaryId, label);
|
|
2447
|
+
else if (newLeafId === null) {
|
|
2448
|
+
// No summary, navigating to root - reset leaf
|
|
2449
|
+
this.sessionManager.resetLeaf();
|
|
2277
2450
|
}
|
|
2451
|
+
else {
|
|
2452
|
+
// No summary, navigating to non-root
|
|
2453
|
+
this.sessionManager.branch(newLeafId);
|
|
2454
|
+
}
|
|
2455
|
+
// Attach label to target entry when not summarizing (no summary entry to label)
|
|
2456
|
+
if (label && !summaryText) {
|
|
2457
|
+
this.sessionManager.appendLabelChange(targetId, label);
|
|
2458
|
+
}
|
|
2459
|
+
// Update agent state
|
|
2460
|
+
const sessionContext = this.sessionManager.buildSessionContext();
|
|
2461
|
+
this.agent.state.messages = sessionContext.messages;
|
|
2462
|
+
// Emit session_tree event
|
|
2463
|
+
await this._extensionRunner.emit({
|
|
2464
|
+
type: "session_tree",
|
|
2465
|
+
newLeafId: this.sessionManager.getLeafId(),
|
|
2466
|
+
oldLeafId,
|
|
2467
|
+
summaryEntry,
|
|
2468
|
+
fromExtension: summaryText ? fromExtension : undefined,
|
|
2469
|
+
});
|
|
2470
|
+
// Emit to custom tools
|
|
2471
|
+
return { editorText, cancelled: false, summaryEntry };
|
|
2278
2472
|
}
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
this.sessionManager.resetLeaf();
|
|
2282
|
-
}
|
|
2283
|
-
else {
|
|
2284
|
-
// No summary, navigating to non-root
|
|
2285
|
-
this.sessionManager.branch(newLeafId);
|
|
2286
|
-
}
|
|
2287
|
-
// Attach label to target entry when not summarizing (no summary entry to label)
|
|
2288
|
-
if (label && !summaryText) {
|
|
2289
|
-
this.sessionManager.appendLabelChange(targetId, label);
|
|
2473
|
+
finally {
|
|
2474
|
+
this._branchSummaryAbortController = undefined;
|
|
2290
2475
|
}
|
|
2291
|
-
// Update agent state
|
|
2292
|
-
const sessionContext = this.sessionManager.buildSessionContext();
|
|
2293
|
-
this.agent.state.messages = sessionContext.messages;
|
|
2294
|
-
// Emit session_tree event
|
|
2295
|
-
await this._extensionRunner.emit({
|
|
2296
|
-
type: "session_tree",
|
|
2297
|
-
newLeafId: this.sessionManager.getLeafId(),
|
|
2298
|
-
oldLeafId,
|
|
2299
|
-
summaryEntry,
|
|
2300
|
-
fromExtension: summaryText ? fromExtension : undefined,
|
|
2301
|
-
});
|
|
2302
|
-
// Emit to custom tools
|
|
2303
|
-
this._branchSummaryAbortController = undefined;
|
|
2304
|
-
return { editorText, cancelled: false, summaryEntry };
|
|
2305
2476
|
}
|
|
2306
2477
|
/**
|
|
2307
2478
|
* Get all user messages from session for fork selector.
|
|
@@ -2314,47 +2485,49 @@ export class AgentSession {
|
|
|
2314
2485
|
continue;
|
|
2315
2486
|
if (entry.message.role !== "user")
|
|
2316
2487
|
continue;
|
|
2317
|
-
const text =
|
|
2488
|
+
const text = contentText(entry.message.content, "");
|
|
2318
2489
|
if (text) {
|
|
2319
2490
|
result.push({ entryId: entry.id, text });
|
|
2320
2491
|
}
|
|
2321
2492
|
}
|
|
2322
2493
|
return result;
|
|
2323
2494
|
}
|
|
2324
|
-
_extractUserMessageText(content) {
|
|
2325
|
-
if (typeof content === "string")
|
|
2326
|
-
return content;
|
|
2327
|
-
if (Array.isArray(content)) {
|
|
2328
|
-
return content
|
|
2329
|
-
.filter((c) => c.type === "text")
|
|
2330
|
-
.map((c) => c.text)
|
|
2331
|
-
.join("");
|
|
2332
|
-
}
|
|
2333
|
-
return "";
|
|
2334
|
-
}
|
|
2335
2495
|
/**
|
|
2336
|
-
* Get session statistics.
|
|
2496
|
+
* Get session statistics. Aggregates over ALL session entries (including
|
|
2497
|
+
* history that was compacted away), so token/cost totals reflect what was
|
|
2498
|
+
* actually billed across the session.
|
|
2337
2499
|
*/
|
|
2338
2500
|
getSessionStats() {
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2501
|
+
let userMessages = 0;
|
|
2502
|
+
let assistantMessages = 0;
|
|
2503
|
+
let toolResults = 0;
|
|
2504
|
+
let totalMessages = 0;
|
|
2343
2505
|
let toolCalls = 0;
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2506
|
+
const usageTotals = createUsageTotals();
|
|
2507
|
+
for (const entry of this.sessionManager.getEntries()) {
|
|
2508
|
+
if ((entry.type === "branch_summary" || entry.type === "compaction") && entry.usage) {
|
|
2509
|
+
addUsageToTotals(usageTotals, entry.usage);
|
|
2510
|
+
}
|
|
2511
|
+
if (entry.type !== "message")
|
|
2512
|
+
continue;
|
|
2513
|
+
totalMessages++;
|
|
2514
|
+
const message = entry.message;
|
|
2515
|
+
if (message.role === "user") {
|
|
2516
|
+
userMessages++;
|
|
2517
|
+
}
|
|
2518
|
+
else if (message.role === "toolResult") {
|
|
2519
|
+
toolResults++;
|
|
2520
|
+
if (message.usage) {
|
|
2521
|
+
addUsageToTotals(usageTotals, message.usage);
|
|
2522
|
+
}
|
|
2523
|
+
}
|
|
2524
|
+
else if (message.role === "assistant") {
|
|
2525
|
+
assistantMessages++;
|
|
2351
2526
|
const assistantMsg = message;
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
totalCacheWrite += assistantMsg.usage.cacheWrite;
|
|
2357
|
-
totalCost += assistantMsg.usage.cost.total;
|
|
2527
|
+
if (Array.isArray(assistantMsg.content)) {
|
|
2528
|
+
toolCalls += assistantMsg.content.filter((c) => c.type === "toolCall").length;
|
|
2529
|
+
}
|
|
2530
|
+
addUsageToTotals(usageTotals, assistantMsg.usage);
|
|
2358
2531
|
}
|
|
2359
2532
|
}
|
|
2360
2533
|
return {
|
|
@@ -2364,15 +2537,15 @@ export class AgentSession {
|
|
|
2364
2537
|
assistantMessages,
|
|
2365
2538
|
toolCalls,
|
|
2366
2539
|
toolResults,
|
|
2367
|
-
totalMessages
|
|
2540
|
+
totalMessages,
|
|
2368
2541
|
tokens: {
|
|
2369
|
-
input:
|
|
2370
|
-
output:
|
|
2371
|
-
cacheRead:
|
|
2372
|
-
cacheWrite:
|
|
2373
|
-
total:
|
|
2542
|
+
input: usageTotals.input,
|
|
2543
|
+
output: usageTotals.output,
|
|
2544
|
+
cacheRead: usageTotals.cacheRead,
|
|
2545
|
+
cacheWrite: usageTotals.cacheWrite,
|
|
2546
|
+
total: usageTotals.input + usageTotals.output + usageTotals.cacheRead + usageTotals.cacheWrite,
|
|
2374
2547
|
},
|
|
2375
|
-
cost:
|
|
2548
|
+
cost: usageTotals.cost,
|
|
2376
2549
|
contextUsage: this.getContextUsage(),
|
|
2377
2550
|
};
|
|
2378
2551
|
}
|
|
@@ -2400,8 +2573,8 @@ export class AgentSession {
|
|
|
2400
2573
|
const contextTokens = calculateContextTokens(assistant.usage);
|
|
2401
2574
|
if (contextTokens > 0) {
|
|
2402
2575
|
hasPostCompactionUsage = true;
|
|
2576
|
+
break;
|
|
2403
2577
|
}
|
|
2404
|
-
break;
|
|
2405
2578
|
}
|
|
2406
2579
|
}
|
|
2407
2580
|
}
|
|
@@ -2420,10 +2593,11 @@ export class AgentSession {
|
|
|
2420
2593
|
/**
|
|
2421
2594
|
* Export session to HTML.
|
|
2422
2595
|
* @param outputPath Optional output path (defaults to session directory)
|
|
2596
|
+
* @param options Optional export presentation settings
|
|
2423
2597
|
* @returns Path to exported file
|
|
2424
2598
|
*/
|
|
2425
|
-
async exportToHtml(outputPath) {
|
|
2426
|
-
const themeName = this.settingsManager.getTheme();
|
|
2599
|
+
async exportToHtml(outputPath, options = {}) {
|
|
2600
|
+
const themeName = [options.themeName, this.settingsManager.getTheme()].find((candidate) => candidate !== undefined && getThemeByName(candidate) !== undefined);
|
|
2427
2601
|
// Create tool renderer if we have an extension runner (for custom tool HTML rendering)
|
|
2428
2602
|
const toolRenderer = createToolHtmlRenderer({
|
|
2429
2603
|
getToolDefinition: (name) => this.getToolDefinition(name),
|
|
@@ -2443,7 +2617,7 @@ export class AgentSession {
|
|
|
2443
2617
|
* @returns The resolved output file path.
|
|
2444
2618
|
*/
|
|
2445
2619
|
exportToJsonl(outputPath) {
|
|
2446
|
-
const filePath =
|
|
2620
|
+
const filePath = resolvePath(outputPath ?? `session-${new Date().toISOString().replace(/[:.]/g, "-")}.jsonl`, process.cwd());
|
|
2447
2621
|
const dir = dirname(filePath);
|
|
2448
2622
|
if (!existsSync(dir)) {
|
|
2449
2623
|
mkdirSync(dir, { recursive: true });
|