@oh-my-pi/pi-coding-agent 15.12.3 → 15.13.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 +347 -7
- package/dist/cli.js +1615 -1231
- package/dist/types/async/job-manager.d.ts +15 -0
- package/dist/types/autolearn/controller.d.ts +25 -0
- package/dist/types/autolearn/managed-skills.d.ts +45 -0
- package/dist/types/autoresearch/state.d.ts +1 -1
- package/dist/types/autoresearch/tools/init-experiment.d.ts +1 -1
- package/dist/types/autoresearch/tools/log-experiment.d.ts +1 -1
- package/dist/types/autoresearch/tools/run-experiment.d.ts +1 -1
- package/dist/types/autoresearch/tools/update-notes.d.ts +1 -1
- package/dist/types/autoresearch/types.d.ts +1 -1
- package/dist/types/cli/args.d.ts +19 -2
- package/dist/types/cli/models-cli.d.ts +49 -0
- package/dist/types/cli/session-picker.d.ts +1 -1
- package/dist/types/cli/setup-cli.d.ts +1 -1
- package/dist/types/cli/setup-model-picker.d.ts +14 -0
- package/dist/types/collab/protocol.d.ts +1 -1
- package/dist/types/commands/launch.d.ts +0 -3
- package/dist/types/commands/models.d.ts +33 -0
- package/dist/types/commands/say.d.ts +24 -0
- package/dist/types/commands/token.d.ts +25 -0
- package/dist/types/commit/agentic/tools/analyze-file.d.ts +1 -1
- package/dist/types/commit/agentic/tools/git-file-diff.d.ts +1 -1
- package/dist/types/commit/agentic/tools/git-hunk.d.ts +1 -1
- package/dist/types/commit/agentic/tools/git-overview.d.ts +1 -1
- package/dist/types/commit/agentic/tools/propose-changelog.d.ts +1 -1
- package/dist/types/commit/agentic/tools/propose-commit.d.ts +1 -1
- package/dist/types/commit/agentic/tools/recent-commits.d.ts +1 -1
- package/dist/types/commit/agentic/tools/schemas.d.ts +1 -1
- package/dist/types/commit/agentic/tools/split-commit.d.ts +1 -1
- package/dist/types/commit/changelog/generate.d.ts +1 -1
- package/dist/types/commit/shared-llm.d.ts +1 -1
- package/dist/types/config/keybindings.d.ts +3 -3
- package/dist/types/config/model-registry.d.ts +17 -0
- package/dist/types/config/models-config-schema.d.ts +13 -1
- package/dist/types/config/models-config.d.ts +8 -2
- package/dist/types/config/settings-schema.d.ts +281 -58
- package/dist/types/edit/hashline/params.d.ts +1 -1
- package/dist/types/edit/modes/apply-patch.d.ts +1 -1
- package/dist/types/edit/modes/patch.d.ts +1 -1
- package/dist/types/edit/modes/replace.d.ts +1 -1
- package/dist/types/export/html/index.d.ts +2 -1
- package/dist/types/extensibility/custom-commands/types.d.ts +2 -2
- package/dist/types/extensibility/custom-tools/types.d.ts +2 -2
- package/dist/types/extensibility/extensions/model-api.d.ts +17 -0
- package/dist/types/extensibility/extensions/runner.d.ts +3 -1
- package/dist/types/extensibility/extensions/types.d.ts +49 -3
- package/dist/types/extensibility/hooks/index.d.ts +2 -1
- package/dist/types/extensibility/hooks/types.d.ts +2 -2
- package/dist/types/extensibility/plugins/legacy-pi-compat.d.ts +9 -0
- package/dist/types/extensibility/plugins/loader.d.ts +11 -0
- package/dist/types/extensibility/shared-events.d.ts +1 -1
- package/dist/types/extensibility/skills.d.ts +10 -0
- package/dist/types/goals/guided-setup.d.ts +18 -0
- package/dist/types/goals/state.d.ts +1 -1
- package/dist/types/goals/tools/goal-tool.d.ts +1 -1
- package/dist/types/hindsight/transcript.d.ts +1 -1
- package/dist/types/index.d.ts +5 -0
- package/dist/types/internal-urls/local-protocol.d.ts +4 -2
- package/dist/types/lsp/types.d.ts +1 -1
- package/dist/types/main.d.ts +4 -3
- package/dist/types/mcp/manager.d.ts +8 -0
- package/dist/types/mcp/startup-events.d.ts +11 -0
- package/dist/types/memories/index.d.ts +7 -0
- package/dist/types/memory-backend/local-backend.d.ts +4 -3
- package/dist/types/mnemopi/config.d.ts +28 -0
- package/dist/types/modes/acp/acp-agent.d.ts +1 -2
- package/dist/types/modes/components/agent-hub.d.ts +6 -0
- package/dist/types/modes/components/assistant-message.d.ts +1 -2
- package/dist/types/modes/components/compaction-summary-message.d.ts +15 -1
- package/dist/types/modes/components/custom-editor.d.ts +39 -1
- package/dist/types/modes/components/custom-editor.test.d.ts +1 -0
- package/dist/types/modes/components/index.d.ts +1 -0
- package/dist/types/modes/components/logout-account-selector.d.ts +8 -0
- package/dist/types/modes/components/session-selector.d.ts +1 -1
- package/dist/types/modes/components/status-line/component.d.ts +9 -5
- package/dist/types/modes/components/status-line/types.d.ts +2 -1
- package/dist/types/modes/components/tool-execution.d.ts +26 -16
- package/dist/types/modes/components/transcript-container.d.ts +23 -2
- package/dist/types/modes/components/tree-selector.d.ts +1 -1
- package/dist/types/modes/components/usage-row.d.ts +3 -0
- package/dist/types/modes/controllers/command-controller.d.ts +2 -2
- package/dist/types/modes/controllers/event-controller.d.ts +0 -17
- package/dist/types/modes/controllers/input-controller.d.ts +14 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +3 -1
- package/dist/types/modes/gradient-highlight.d.ts +9 -4
- package/dist/types/modes/image-references.d.ts +6 -0
- package/dist/types/modes/interactive-mode.d.ts +27 -6
- package/dist/types/modes/magic-keywords.d.ts +13 -1
- package/dist/types/modes/rpc/rpc-mode.d.ts +35 -1
- package/dist/types/modes/rpc/rpc-types.d.ts +9 -1
- package/dist/types/modes/runtime-init.d.ts +4 -0
- package/dist/types/modes/theme/theme.d.ts +13 -2
- package/dist/types/modes/types.d.ts +8 -7
- package/dist/types/modes/utils/ui-helpers.d.ts +1 -1
- package/dist/types/registry/agent-registry.d.ts +17 -0
- package/dist/types/secrets/obfuscator.d.ts +1 -1
- package/dist/types/session/agent-session.d.ts +28 -35
- package/dist/types/session/agent-storage.d.ts +2 -1
- package/dist/types/session/indexed-session-storage.d.ts +3 -3
- package/dist/types/session/messages.d.ts +8 -10
- package/dist/types/session/session-context.d.ts +39 -0
- package/dist/types/session/session-entries.d.ts +159 -0
- package/dist/types/session/session-listing.d.ts +69 -0
- package/dist/types/session/session-loader.d.ts +16 -0
- package/dist/types/session/session-manager.d.ts +85 -462
- package/dist/types/session/session-migrations.d.ts +12 -0
- package/dist/types/session/session-paths.d.ts +25 -0
- package/dist/types/session/session-persistence.d.ts +8 -0
- package/dist/types/session/session-storage.d.ts +11 -7
- package/dist/types/session/snapcompact-inline.d.ts +12 -1
- package/dist/types/session/snapcompact-savings-journal.d.ts +46 -0
- package/dist/types/session/tool-choice-queue.d.ts +6 -6
- package/dist/types/slash-commands/helpers/logout.d.ts +15 -0
- package/dist/types/stt/asr-client.d.ts +90 -0
- package/dist/types/stt/asr-protocol.d.ts +97 -0
- package/dist/types/stt/asr-worker.d.ts +2 -0
- package/dist/types/stt/downloader.d.ts +38 -0
- package/dist/types/stt/endpointer.d.ts +59 -0
- package/dist/types/stt/index.d.ts +5 -1
- package/dist/types/stt/models.d.ts +120 -0
- package/dist/types/stt/recorder.d.ts +17 -0
- package/dist/types/stt/stt-controller.d.ts +6 -0
- package/dist/types/stt/transcriber.d.ts +5 -7
- package/dist/types/stt/wav.d.ts +29 -0
- package/dist/types/system-prompt.d.ts +4 -0
- package/dist/types/task/executor.d.ts +2 -0
- package/dist/types/task/index.d.ts +9 -1
- package/dist/types/task/types.d.ts +37 -1
- package/dist/types/tools/ask.d.ts +1 -1
- package/dist/types/tools/ast-edit.d.ts +1 -1
- package/dist/types/tools/ast-grep.d.ts +1 -1
- package/dist/types/tools/bash.d.ts +3 -3
- package/dist/types/tools/browser/cmux/cmux-tab.d.ts +202 -0
- package/dist/types/tools/browser/cmux/rpc.d.ts +70 -0
- package/dist/types/tools/browser/cmux/socket-client.d.ts +19 -0
- package/dist/types/tools/browser/registry.d.ts +16 -3
- package/dist/types/tools/browser/render.d.ts +2 -0
- package/dist/types/tools/browser/tab-protocol.d.ts +2 -0
- package/dist/types/tools/browser/tab-supervisor.d.ts +16 -4
- package/dist/types/tools/browser.d.ts +3 -1
- package/dist/types/tools/checkpoint.d.ts +1 -1
- package/dist/types/tools/debug.d.ts +1 -1
- package/dist/types/tools/eval-render.d.ts +1 -1
- package/dist/types/tools/eval.d.ts +1 -1
- package/dist/types/tools/find.d.ts +1 -1
- package/dist/types/tools/gh.d.ts +1 -1
- package/dist/types/tools/image-gen.d.ts +1 -1
- package/dist/types/tools/index.d.ts +14 -2
- package/dist/types/tools/inspect-image.d.ts +1 -1
- package/dist/types/tools/irc.d.ts +2 -1
- package/dist/types/tools/job.d.ts +1 -1
- package/dist/types/tools/learn.d.ts +51 -0
- package/dist/types/tools/manage-skill.d.ts +40 -0
- package/dist/types/tools/memory-edit.d.ts +1 -1
- package/dist/types/tools/memory-recall.d.ts +1 -1
- package/dist/types/tools/memory-reflect.d.ts +1 -1
- package/dist/types/tools/memory-retain.d.ts +1 -1
- package/dist/types/tools/plan-mode-guard.d.ts +10 -0
- package/dist/types/tools/read.d.ts +1 -1
- package/dist/types/tools/render-mermaid.d.ts +1 -1
- package/dist/types/tools/renderers.d.ts +7 -11
- package/dist/types/tools/resolve.d.ts +1 -1
- package/dist/types/tools/review.d.ts +1 -1
- package/dist/types/tools/search-tool-bm25.d.ts +1 -1
- package/dist/types/tools/search.d.ts +1 -1
- package/dist/types/tools/ssh.d.ts +2 -2
- package/dist/types/tools/todo.d.ts +2 -2
- package/dist/types/tools/tts.d.ts +26 -1
- package/dist/types/tools/write.d.ts +2 -2
- package/dist/types/tts/downloader.d.ts +20 -0
- package/dist/types/tts/index.d.ts +8 -0
- package/dist/types/tts/models.d.ts +82 -0
- package/dist/types/tts/player.d.ts +32 -0
- package/dist/types/tts/runtime.d.ts +6 -0
- package/dist/types/tts/streaming-player.d.ts +41 -0
- package/dist/types/tts/tts-client.d.ts +93 -0
- package/dist/types/tts/tts-protocol.d.ts +95 -0
- package/dist/types/tts/tts-worker.d.ts +2 -0
- package/dist/types/tts/vocalizer.d.ts +41 -0
- package/dist/types/tts/wav.d.ts +8 -0
- package/dist/types/utils/clipboard.d.ts +4 -3
- package/dist/types/utils/image-loading.d.ts +18 -1
- package/dist/types/utils/thinking-display.d.ts +17 -0
- package/dist/types/utils/tool-choice.d.ts +8 -0
- package/dist/types/utils/tools-manager.d.ts +2 -1
- package/dist/types/utils/tools-manager.test.d.ts +1 -0
- package/dist/types/web/scrapers/github.d.ts +1 -1
- package/dist/types/web/search/index.d.ts +1 -1
- package/package.json +17 -16
- package/src/async/job-manager.ts +49 -0
- package/src/autolearn/controller.ts +139 -0
- package/src/autolearn/managed-skills.ts +257 -0
- package/src/autoresearch/state.ts +1 -1
- package/src/autoresearch/storage.ts +2 -1
- package/src/autoresearch/tools/init-experiment.ts +1 -1
- package/src/autoresearch/tools/log-experiment.ts +1 -1
- package/src/autoresearch/tools/run-experiment.ts +1 -1
- package/src/autoresearch/tools/update-notes.ts +1 -1
- package/src/autoresearch/types.ts +1 -1
- package/src/cli/args.ts +56 -10
- package/src/cli/auth-gateway-cli.ts +1 -1
- package/src/cli/bench-cli.ts +1 -1
- package/src/cli/dry-balance-cli.ts +1 -1
- package/src/cli/models-cli.ts +427 -0
- package/src/cli/session-picker.ts +2 -1
- package/src/cli/setup-cli.ts +148 -47
- package/src/cli/setup-model-picker.ts +43 -0
- package/src/cli-commands.ts +3 -0
- package/src/cli.ts +45 -13
- package/src/collab/host.ts +10 -13
- package/src/collab/protocol.ts +1 -1
- package/src/commands/launch.ts +0 -3
- package/src/commands/models.ts +61 -0
- package/src/commands/say.ts +102 -0
- package/src/commands/setup.ts +1 -1
- package/src/commands/token.ts +89 -0
- package/src/commit/agentic/tools/analyze-file.ts +4 -1
- package/src/commit/agentic/tools/git-file-diff.ts +1 -1
- package/src/commit/agentic/tools/git-hunk.ts +1 -1
- package/src/commit/agentic/tools/git-overview.ts +1 -1
- package/src/commit/agentic/tools/propose-changelog.ts +1 -1
- package/src/commit/agentic/tools/propose-commit.ts +1 -1
- package/src/commit/agentic/tools/recent-commits.ts +1 -1
- package/src/commit/agentic/tools/schemas.ts +1 -1
- package/src/commit/agentic/tools/split-commit.ts +1 -1
- package/src/commit/analysis/summary.ts +1 -1
- package/src/commit/changelog/generate.ts +1 -1
- package/src/commit/shared-llm.ts +1 -1
- package/src/config/keybindings.ts +2 -2
- package/src/config/model-discovery.ts +11 -5
- package/src/config/model-registry.ts +79 -21
- package/src/config/model-resolver.ts +2 -2
- package/src/config/models-config-schema.ts +5 -2
- package/src/config/models-config.ts +2 -1
- package/src/config/settings-schema.ts +266 -32
- package/src/config/settings.ts +10 -0
- package/src/discovery/builtin.ts +23 -1
- package/src/discovery/claude-plugins.ts +44 -5
- package/src/discovery/helpers.ts +41 -1
- package/src/edit/hashline/params.ts +1 -1
- package/src/edit/modes/apply-patch.ts +1 -1
- package/src/edit/modes/patch.ts +1 -1
- package/src/edit/modes/replace.ts +1 -1
- package/src/eval/__tests__/budget-bridge.test.ts +1 -1
- package/src/eval/agent-bridge.ts +1 -1
- package/src/eval/completion-bridge.ts +1 -1
- package/src/eval/js/shared/prelude.txt +69 -17
- package/src/export/html/index.ts +3 -6
- package/src/export/html/template.js +24 -2
- package/src/export/html/tool-views.generated.js +2 -2
- package/src/extensibility/custom-commands/loader.ts +1 -1
- package/src/extensibility/custom-commands/types.ts +2 -2
- package/src/extensibility/custom-tools/loader.ts +1 -1
- package/src/extensibility/custom-tools/types.ts +2 -2
- package/src/extensibility/extensions/loader.ts +2 -2
- package/src/extensibility/extensions/model-api.ts +41 -0
- package/src/extensibility/extensions/runner.ts +4 -0
- package/src/extensibility/extensions/types.ts +54 -3
- package/src/extensibility/extensions/wrapper.ts +41 -5
- package/src/extensibility/hooks/index.ts +2 -1
- package/src/extensibility/hooks/loader.ts +1 -1
- package/src/extensibility/hooks/types.ts +2 -2
- package/src/extensibility/plugins/legacy-pi-compat.ts +43 -13
- package/src/extensibility/plugins/loader.ts +30 -19
- package/src/extensibility/plugins/manager.ts +221 -90
- package/src/extensibility/shared-events.ts +1 -1
- package/src/extensibility/skills.ts +101 -5
- package/src/goals/guided-setup.ts +133 -0
- package/src/goals/state.ts +1 -1
- package/src/goals/tools/goal-tool.ts +1 -1
- package/src/hindsight/transcript.ts +1 -1
- package/src/index.ts +5 -0
- package/src/internal-urls/docs-index.generated.ts +13 -10
- package/src/internal-urls/history-protocol.ts +1 -1
- package/src/internal-urls/local-protocol.ts +29 -7
- package/src/lsp/types.ts +1 -1
- package/src/main.ts +27 -32
- package/src/mcp/config-writer.ts +7 -3
- package/src/mcp/manager.ts +11 -0
- package/src/mcp/startup-events.ts +21 -0
- package/src/mcp/transports/stdio.ts +2 -1
- package/src/memories/index.ts +149 -12
- package/src/memories/storage.ts +2 -1
- package/src/memory-backend/local-backend.ts +11 -5
- package/src/mnemopi/backend.ts +1 -0
- package/src/mnemopi/config.ts +112 -12
- package/src/modes/acp/acp-agent.ts +8 -53
- package/src/modes/acp/acp-event-mapper.ts +5 -1
- package/src/modes/components/agent-hub.ts +51 -5
- package/src/modes/components/assistant-message.ts +12 -44
- package/src/modes/components/compaction-summary-message.ts +125 -26
- package/src/modes/components/custom-editor.test.ts +96 -0
- package/src/modes/components/custom-editor.ts +164 -8
- package/src/modes/components/index.ts +1 -0
- package/src/modes/components/logout-account-selector.ts +130 -0
- package/src/modes/components/mcp-add-wizard.ts +1 -1
- package/src/modes/components/model-selector.ts +2 -2
- package/src/modes/components/session-selector.ts +1 -1
- package/src/modes/components/settings-defs.ts +7 -0
- package/src/modes/components/status-line/component.ts +54 -157
- package/src/modes/components/status-line/segments.ts +1 -1
- package/src/modes/components/status-line/types.ts +2 -1
- package/src/modes/components/tool-execution.ts +82 -43
- package/src/modes/components/transcript-container.ts +70 -1
- package/src/modes/components/tree-selector.ts +1 -1
- package/src/modes/components/usage-row.ts +18 -0
- package/src/modes/components/user-message.ts +4 -2
- package/src/modes/controllers/command-controller.ts +14 -16
- package/src/modes/controllers/event-controller.ts +101 -73
- package/src/modes/controllers/extension-ui-controller.ts +6 -0
- package/src/modes/controllers/input-controller.ts +311 -57
- package/src/modes/controllers/mcp-command-controller.ts +44 -3
- package/src/modes/controllers/selector-controller.ts +68 -12
- package/src/modes/controllers/streaming-reveal.ts +4 -3
- package/src/modes/gradient-highlight.ts +21 -9
- package/src/modes/image-references.ts +20 -0
- package/src/modes/interactive-mode.ts +288 -48
- package/src/modes/magic-keywords.ts +27 -5
- package/src/modes/rpc/rpc-mode.ts +146 -14
- package/src/modes/rpc/rpc-subagents.ts +2 -2
- package/src/modes/rpc/rpc-types.ts +8 -2
- package/src/modes/runtime-init.ts +28 -3
- package/src/modes/theme/theme.ts +99 -51
- package/src/modes/types.ts +6 -7
- package/src/modes/utils/hotkeys-markdown.ts +1 -1
- package/src/modes/utils/ui-helpers.ts +36 -7
- package/src/priority.json +5 -1
- package/src/prompts/agents/task.md +1 -0
- package/src/prompts/goals/guided-goal-interview.md +8 -0
- package/src/prompts/goals/guided-goal-system.md +12 -0
- package/src/prompts/memories/read-path.md +6 -0
- package/src/prompts/system/autolearn-guidance-learn.md +1 -0
- package/src/prompts/system/autolearn-guidance.md +7 -0
- package/src/prompts/system/autolearn-nudge.md +3 -0
- package/src/prompts/system/eager-task.md +7 -0
- package/src/prompts/system/eager-todo.md +11 -6
- package/src/prompts/system/empty-stop-retry.md +4 -6
- package/src/prompts/system/subagent-system-prompt.md +4 -0
- package/src/prompts/system/system-prompt.md +10 -5
- package/src/prompts/system/title-marker-instruction.md +1 -0
- package/src/prompts/system/title-system-marker.md +16 -0
- package/src/prompts/tools/job.md +1 -0
- package/src/prompts/tools/learn.md +7 -0
- package/src/prompts/tools/manage-skill.md +9 -0
- package/src/prompts/tools/task.md +3 -0
- package/src/registry/agent-registry.ts +30 -0
- package/src/sdk.ts +103 -43
- package/src/secrets/obfuscator.ts +1 -1
- package/src/session/agent-session.ts +331 -318
- package/src/session/agent-storage.ts +18 -9
- package/src/session/history-storage.ts +3 -2
- package/src/session/indexed-session-storage.ts +7 -10
- package/src/session/messages.ts +9 -11
- package/src/session/session-context.ts +352 -0
- package/src/session/session-dump-format.ts +4 -2
- package/src/session/session-entries.ts +194 -0
- package/src/session/session-listing.ts +588 -0
- package/src/session/session-loader.ts +106 -0
- package/src/session/session-manager.ts +968 -3064
- package/src/session/session-migrations.ts +78 -0
- package/src/session/session-paths.ts +193 -0
- package/src/session/session-persistence.ts +131 -0
- package/src/session/session-storage.ts +91 -30
- package/src/session/snapcompact-inline.ts +21 -1
- package/src/session/snapcompact-savings-journal.ts +113 -0
- package/src/session/tool-choice-queue.ts +23 -11
- package/src/slash-commands/builtin-registry.ts +40 -4
- package/src/slash-commands/helpers/logout.ts +88 -0
- package/src/stt/asr-client.ts +520 -0
- package/src/stt/asr-protocol.ts +65 -0
- package/src/stt/asr-worker.ts +790 -0
- package/src/stt/downloader.ts +107 -47
- package/src/stt/endpointer.ts +259 -0
- package/src/stt/index.ts +5 -1
- package/src/stt/models.ts +150 -0
- package/src/stt/recorder.ts +247 -60
- package/src/stt/stt-controller.ts +201 -22
- package/src/stt/transcriber.ts +37 -68
- package/src/stt/wav.ts +173 -0
- package/src/system-prompt.ts +8 -0
- package/src/task/agents.ts +1 -2
- package/src/task/executor.ts +49 -15
- package/src/task/index.ts +60 -6
- package/src/task/render.ts +83 -8
- package/src/task/types.ts +54 -1
- package/src/tools/ask.ts +9 -1
- package/src/tools/ast-edit.ts +1 -1
- package/src/tools/ast-grep.ts +1 -1
- package/src/tools/bash.ts +5 -4
- package/src/tools/browser/cmux/cmux-tab.ts +1264 -0
- package/src/tools/browser/cmux/rpc.ts +156 -0
- package/src/tools/browser/cmux/socket-client.ts +309 -0
- package/src/tools/browser/registry.ts +37 -3
- package/src/tools/browser/render.ts +6 -1
- package/src/tools/browser/tab-protocol.ts +2 -0
- package/src/tools/browser/tab-supervisor.ts +189 -18
- package/src/tools/browser/tab-worker.ts +1 -1
- package/src/tools/browser.ts +16 -1
- package/src/tools/checkpoint.ts +1 -1
- package/src/tools/debug.ts +1 -1
- package/src/tools/eval-render.ts +4 -3
- package/src/tools/eval.ts +11 -6
- package/src/tools/fetch.ts +13 -2
- package/src/tools/find.ts +1 -1
- package/src/tools/gh.ts +1 -1
- package/src/tools/github-cache.ts +2 -1
- package/src/tools/image-gen.ts +1 -1
- package/src/tools/index.ts +43 -5
- package/src/tools/inspect-image.ts +3 -1
- package/src/tools/irc.ts +11 -3
- package/src/tools/job.ts +15 -3
- package/src/tools/learn.ts +144 -0
- package/src/tools/manage-skill.ts +104 -0
- package/src/tools/memory-edit.ts +1 -1
- package/src/tools/memory-recall.ts +1 -1
- package/src/tools/memory-reflect.ts +1 -1
- package/src/tools/memory-retain.ts +1 -1
- package/src/tools/plan-mode-guard.ts +53 -19
- package/src/tools/read.ts +8 -2
- package/src/tools/render-mermaid.ts +1 -1
- package/src/tools/renderers.ts +7 -11
- package/src/tools/report-tool-issue.ts +3 -2
- package/src/tools/resolve.ts +1 -1
- package/src/tools/review.ts +1 -1
- package/src/tools/search-tool-bm25.ts +1 -1
- package/src/tools/search.ts +1 -1
- package/src/tools/ssh.ts +5 -4
- package/src/tools/todo.ts +2 -2
- package/src/tools/tts.ts +204 -93
- package/src/tools/write.ts +19 -3
- package/src/tts/downloader.ts +64 -0
- package/src/tts/index.ts +8 -0
- package/src/tts/models.ts +137 -0
- package/src/tts/player.ts +137 -0
- package/src/tts/runtime.ts +21 -0
- package/src/tts/streaming-player.ts +266 -0
- package/src/tts/tts-client.ts +647 -0
- package/src/tts/tts-protocol.ts +60 -0
- package/src/tts/tts-worker.ts +497 -0
- package/src/tts/vocalizer.ts +162 -0
- package/src/tts/wav.ts +58 -0
- package/src/utils/clipboard.ts +35 -18
- package/src/utils/image-loading.ts +35 -4
- package/src/utils/thinking-display.ts +37 -0
- package/src/utils/title-generator.ts +48 -5
- package/src/utils/tool-choice.ts +16 -0
- package/src/utils/tools-manager.test.ts +25 -0
- package/src/utils/tools-manager.ts +19 -1
- package/src/web/scrapers/github.ts +96 -0
- package/src/web/search/index.ts +14 -1
- package/src/web/search/providers/searxng.ts +13 -1
- package/dist/types/cli/list-models.d.ts +0 -30
- package/dist/types/stt/setup.d.ts +0 -18
- package/src/cli/list-models.ts +0 -194
- package/src/stt/setup.ts +0 -52
- package/src/stt/transcribe.py +0 -70
|
@@ -166,6 +166,7 @@ import type {
|
|
|
166
166
|
TurnEndEvent,
|
|
167
167
|
TurnStartEvent,
|
|
168
168
|
} from "../extensibility/extensions";
|
|
169
|
+
import { createExtensionModelQuery } from "../extensibility/extensions/model-api";
|
|
169
170
|
import type { CompactOptions, ContextUsage } from "../extensibility/extensions/types";
|
|
170
171
|
import { ExtensionToolWrapper } from "../extensibility/extensions/wrapper";
|
|
171
172
|
import type { HookCommandContext } from "../extensibility/hooks/types";
|
|
@@ -187,6 +188,7 @@ import { containsWorkflow, WORKFLOW_NOTICE } from "../modes/workflow";
|
|
|
187
188
|
import { createPlanReadMatcher } from "../plan-mode/plan-protection";
|
|
188
189
|
import type { PlanModeState } from "../plan-mode/state";
|
|
189
190
|
import autoContinuePrompt from "../prompts/system/auto-continue.md" with { type: "text" };
|
|
191
|
+
import eagerTaskPrompt from "../prompts/system/eager-task.md" with { type: "text" };
|
|
190
192
|
import eagerTodoPrompt from "../prompts/system/eager-todo.md" with { type: "text" };
|
|
191
193
|
import emptyStopRetryTemplate from "../prompts/system/empty-stop-retry.md" with { type: "text" };
|
|
192
194
|
import ircAutoReplyTemplate from "../prompts/system/irc-autoreply.md" with { type: "text" };
|
|
@@ -238,7 +240,7 @@ import { type EditMode, resolveEditMode } from "../utils/edit-mode";
|
|
|
238
240
|
import { resolveFileDisplayMode } from "../utils/file-display-mode";
|
|
239
241
|
import { extractFileMentions, generateFileMentionMessages } from "../utils/file-mentions";
|
|
240
242
|
import { normalizeModelContextImages } from "../utils/image-loading";
|
|
241
|
-
import { buildNamedToolChoice } from "../utils/tool-choice";
|
|
243
|
+
import { buildNamedToolChoice, isToolChoiceActive } from "../utils/tool-choice";
|
|
242
244
|
import type { AuthStorage } from "./auth-storage";
|
|
243
245
|
import type { ClientBridge, ClientBridgePermissionOption, ClientBridgePermissionOutcome } from "./client-bridge";
|
|
244
246
|
import {
|
|
@@ -253,20 +255,17 @@ import {
|
|
|
253
255
|
type CustomMessage,
|
|
254
256
|
convertToLlm,
|
|
255
257
|
type PythonExecutionMessage,
|
|
256
|
-
|
|
258
|
+
readQueueChipText,
|
|
257
259
|
SILENT_ABORT_MARKER,
|
|
258
260
|
SKILL_PROMPT_MESSAGE_TYPE,
|
|
259
261
|
stripImagesFromMessage,
|
|
260
262
|
} from "./messages";
|
|
263
|
+
import type { SessionContext } from "./session-context";
|
|
264
|
+
import { getLatestCompactionEntry, getRestorableSessionModels } from "./session-context";
|
|
261
265
|
import { formatSessionDumpText } from "./session-dump-format";
|
|
262
|
-
import type {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
NewSessionOptions,
|
|
266
|
-
SessionContext,
|
|
267
|
-
SessionManager,
|
|
268
|
-
} from "./session-manager";
|
|
269
|
-
import { EPHEMERAL_MODEL_CHANGE_ROLE, getLatestCompactionEntry, getRestorableSessionModels } from "./session-manager";
|
|
266
|
+
import type { BranchSummaryEntry, CompactionEntry, NewSessionOptions } from "./session-entries";
|
|
267
|
+
import { EPHEMERAL_MODEL_CHANGE_ROLE } from "./session-entries";
|
|
268
|
+
import type { SessionManager } from "./session-manager";
|
|
270
269
|
import type { ShakeMode, ShakeResult } from "./shake-types";
|
|
271
270
|
import { ToolChoiceQueue } from "./tool-choice-queue";
|
|
272
271
|
import { YieldQueue } from "./yield-queue";
|
|
@@ -441,6 +440,10 @@ export interface AgentSessionConfig {
|
|
|
441
440
|
asyncJobManager?: AsyncJobManager;
|
|
442
441
|
/** Agent identity (registry id like "Main" or "Alice") used for IRC routing. */
|
|
443
442
|
agentId?: string;
|
|
443
|
+
/** Whether this session is the top-level agent or a subagent. Drives eager-task
|
|
444
|
+
* prelude gating so a top-level session created with a custom `agentId` still
|
|
445
|
+
* receives the always-mode reminder. Defaults to "main". */
|
|
446
|
+
agentKind?: "main" | "sub";
|
|
444
447
|
/**
|
|
445
448
|
* Override the provider-facing session ID for all API requests from this session.
|
|
446
449
|
* When absent, `sessionManager.getSessionId()` is used. Needed when benchmark or
|
|
@@ -862,18 +865,42 @@ function extractPermissionLocations(
|
|
|
862
865
|
// AgentSession Class
|
|
863
866
|
// ============================================================================
|
|
864
867
|
|
|
865
|
-
/** Internal record stored in the steering/followUp display queues. The optional
|
|
866
|
-
* `tag` is set only by `enqueueCustomMessageDisplay` (used for skill-prompt
|
|
867
|
-
* custom messages queued during streaming) and is matched by the custom-role
|
|
868
|
-
* `message_start` dequeue branch; user-message pushes leave it undefined and
|
|
869
|
-
* rely on the existing text-equality match. `images` carries the original
|
|
870
|
-
* (pre-normalization) image blocks so queue restoration (Esc / Alt+Up) can
|
|
871
|
-
* hand them back to the editor instead of dropping them. */
|
|
872
|
-
type QueuedDisplayEntry = { text: string; tag?: string; images?: ImageContent[] };
|
|
873
|
-
|
|
874
868
|
/** Entry returned by {@link AgentSession.clearQueue} / {@link AgentSession.popLastQueuedMessage}. */
|
|
875
869
|
export type RestoredQueuedMessage = { text: string; images?: ImageContent[] };
|
|
876
870
|
|
|
871
|
+
function queuedTextContent(message: AgentMessage): string | undefined {
|
|
872
|
+
if (!("content" in message)) return undefined;
|
|
873
|
+
const content = message.content;
|
|
874
|
+
if (typeof content === "string") return content;
|
|
875
|
+
return content.find((part): part is TextContent => part.type === "text")?.text;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
function queuedImageContent(message: AgentMessage): ImageContent[] | undefined {
|
|
879
|
+
if (!("content" in message) || typeof message.content === "string") return undefined;
|
|
880
|
+
const images = message.content.filter(
|
|
881
|
+
(part): part is ImageContent =>
|
|
882
|
+
part.type === "image" && typeof part.data === "string" && typeof part.mimeType === "string",
|
|
883
|
+
);
|
|
884
|
+
return images.length > 0 ? images : undefined;
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
function isDisplayableQueuedMessage(message: AgentMessage): boolean {
|
|
888
|
+
return !(message.role === "custom" && message.display === false);
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
function queueChipText(message: AgentMessage): string {
|
|
892
|
+
if (message.role === "custom") {
|
|
893
|
+
return readQueueChipText(message.details) ?? queuedTextContent(message) ?? "";
|
|
894
|
+
}
|
|
895
|
+
const text = queuedTextContent(message) ?? "";
|
|
896
|
+
if (text) return text;
|
|
897
|
+
return queuedImageContent(message) ? "[Image]" : "";
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
function toRestoredQueuedMessage(message: AgentMessage): RestoredQueuedMessage {
|
|
901
|
+
return { text: queueChipText(message), images: queuedImageContent(message) };
|
|
902
|
+
}
|
|
903
|
+
|
|
877
904
|
export class AgentSession {
|
|
878
905
|
readonly agent: Agent;
|
|
879
906
|
readonly sessionManager: SessionManager;
|
|
@@ -904,18 +931,10 @@ export class AgentSession {
|
|
|
904
931
|
#eventListeners: AgentSessionEventListener[] = [];
|
|
905
932
|
#commandMetadataChangedListeners: CommandMetadataChangedListener[] = [];
|
|
906
933
|
|
|
907
|
-
/** Tracks pending steering messages for UI display. Removed when delivered.
|
|
908
|
-
* Entry shape: `{ text }` for plain-text steers (user-message dequeue
|
|
909
|
-
* matches by `.text`); `{ text, tag }` for queued custom messages (skill
|
|
910
|
-
* invocations dispatched while streaming) — the custom-role dequeue
|
|
911
|
-
* matches by `.tag` so duplicate-args queued skills cannot collide. */
|
|
912
|
-
#steeringMessages: QueuedDisplayEntry[] = [];
|
|
913
|
-
/** Tracks pending follow-up messages for UI display. Removed when delivered.
|
|
914
|
-
* See `#steeringMessages` for entry shape. */
|
|
915
|
-
#followUpMessages: QueuedDisplayEntry[] = [];
|
|
916
934
|
/** Messages queued to be included with the next user prompt as context ("asides"). */
|
|
917
935
|
#pendingNextTurnMessages: CustomMessage[] = [];
|
|
918
936
|
#scheduledHiddenNextTurnGeneration: number | undefined = undefined;
|
|
937
|
+
#queuedMessageDrainScheduled = false;
|
|
919
938
|
#planModeState: PlanModeState | undefined;
|
|
920
939
|
#goalModeState: GoalModeState | undefined;
|
|
921
940
|
#goalRuntime: GoalRuntime;
|
|
@@ -979,6 +998,7 @@ export class AgentSession {
|
|
|
979
998
|
#pendingIrcAsides: CustomMessage[] = [];
|
|
980
999
|
// Agent identity (registry id) used for IRC routing and job ownership.
|
|
981
1000
|
#agentId: string | undefined;
|
|
1001
|
+
#agentKind: "main" | "sub" = "main";
|
|
982
1002
|
#providerSessionId: string | undefined;
|
|
983
1003
|
#freshProviderSessionId: string | undefined;
|
|
984
1004
|
#isDisposed = false;
|
|
@@ -1058,10 +1078,6 @@ export class AgentSession {
|
|
|
1058
1078
|
* without producing an aborted message_end). */
|
|
1059
1079
|
#planCompactAbortPending = false;
|
|
1060
1080
|
|
|
1061
|
-
/** Monotonic counter for `enqueueCustomMessageDisplay` tag generation;
|
|
1062
|
-
* combined with `Date.now()` so tags stay unique even across rapid
|
|
1063
|
-
* same-tick enqueues. */
|
|
1064
|
-
#customDisplayTagCounter = 0;
|
|
1065
1081
|
#postPromptTasks = new Set<Promise<unknown>>();
|
|
1066
1082
|
#postPromptTasksPromise: Promise<void> | undefined = undefined;
|
|
1067
1083
|
#postPromptTasksResolve: (() => void) | undefined = undefined;
|
|
@@ -1074,6 +1090,7 @@ export class AgentSession {
|
|
|
1074
1090
|
|
|
1075
1091
|
#streamingEditFileCache = new Map<string, string>();
|
|
1076
1092
|
#promptInFlightCount = 0;
|
|
1093
|
+
#abortInProgress = false;
|
|
1077
1094
|
// Wire-level agent_end emission deferred until #promptInFlightCount drops to 0.
|
|
1078
1095
|
// Internal extension hooks and post-emit work (auto-retry, auto-compaction, todo
|
|
1079
1096
|
// checks in #handleAgentEvent) still fire on the original schedule — only the
|
|
@@ -1143,24 +1160,21 @@ export class AgentSession {
|
|
|
1143
1160
|
}
|
|
1144
1161
|
}
|
|
1145
1162
|
|
|
1146
|
-
/** A steer/follow-up can land after the agent loop's final queue poll
|
|
1147
|
-
*
|
|
1148
|
-
*
|
|
1149
|
-
*
|
|
1150
|
-
*
|
|
1151
|
-
* prompt. Runs when the session settles; the guard makes it a no-op when
|
|
1152
|
-
* the queue was consumed normally or a new turn already started. */
|
|
1163
|
+
/** A steer/follow-up can land after the agent loop's final queue poll, or
|
|
1164
|
+
* after an abort stops an auto-continued queued turn. In both cases the
|
|
1165
|
+
* agent-core queue still owns the message, but no loop is left to poll it.
|
|
1166
|
+
* Runs whenever the session settles; the guard makes it a no-op when the
|
|
1167
|
+
* queue was consumed normally or a new turn already started. */
|
|
1153
1168
|
#drainStrandedQueuedMessages(): void {
|
|
1154
|
-
if (
|
|
1155
|
-
this.#
|
|
1156
|
-
shouldContinue: () => this.#canAutoContinueForFollowUp() && this.agent.hasQueuedMessages(),
|
|
1157
|
-
});
|
|
1169
|
+
if (this.#abortInProgress) return;
|
|
1170
|
+
this.#scheduleQueuedMessageDrain();
|
|
1158
1171
|
}
|
|
1159
1172
|
|
|
1160
1173
|
#resetInFlight(): void {
|
|
1161
1174
|
this.#promptInFlightCount = 0;
|
|
1162
1175
|
this.#releasePowerAssertion();
|
|
1163
1176
|
this.#flushPendingAgentEnd();
|
|
1177
|
+
this.#drainStrandedQueuedMessages();
|
|
1164
1178
|
}
|
|
1165
1179
|
|
|
1166
1180
|
#flushPendingAgentEnd(): void {
|
|
@@ -1287,6 +1301,7 @@ export class AgentSession {
|
|
|
1287
1301
|
this.#ttsrManager = config.ttsrManager;
|
|
1288
1302
|
this.#obfuscator = config.obfuscator;
|
|
1289
1303
|
this.#agentId = config.agentId;
|
|
1304
|
+
this.#agentKind = config.agentKind ?? "main";
|
|
1290
1305
|
this.#providerSessionId = config.providerSessionId;
|
|
1291
1306
|
this.agent.setAssistantMessageEventInterceptor((message, assistantMessageEvent) => {
|
|
1292
1307
|
const event: AgentEvent = {
|
|
@@ -1363,7 +1378,12 @@ export class AgentSession {
|
|
|
1363
1378
|
|
|
1364
1379
|
/** Advance the tool-choice queue and return the next directive for the upcoming LLM call. */
|
|
1365
1380
|
nextToolChoice(): ToolChoice | undefined {
|
|
1366
|
-
|
|
1381
|
+
const choice = this.#toolChoiceQueue.nextToolChoice();
|
|
1382
|
+
if (isToolChoiceActive(choice, this.agent.state.tools)) {
|
|
1383
|
+
return choice;
|
|
1384
|
+
}
|
|
1385
|
+
this.#toolChoiceQueue.reject("unavailable");
|
|
1386
|
+
return undefined;
|
|
1367
1387
|
}
|
|
1368
1388
|
|
|
1369
1389
|
/**
|
|
@@ -1471,28 +1491,6 @@ export class AgentSession {
|
|
|
1471
1491
|
this.#planCompactAbortPending = false;
|
|
1472
1492
|
}
|
|
1473
1493
|
|
|
1474
|
-
/** Register a compact display string for a custom message that the caller is
|
|
1475
|
-
* about to dispatch via `promptCustomMessage` / `sendCustomMessage`.
|
|
1476
|
-
* Returns a stable tag the caller MUST embed in
|
|
1477
|
-
* `CustomMessage.details.__pendingDisplayTag` so the agent-side
|
|
1478
|
-
* `message_start` handler can remove the matching display entry when the
|
|
1479
|
-
* queued message is consumed.
|
|
1480
|
-
*
|
|
1481
|
-
* Does NOT push to the agent's steering/followUp queue — that happens
|
|
1482
|
-
* separately inside `sendCustomMessage`. */
|
|
1483
|
-
enqueueCustomMessageDisplay(text: string, mode: "steer" | "followUp"): string {
|
|
1484
|
-
const tag = `omp-cmd-${Date.now()}-${++this.#customDisplayTagCounter}`;
|
|
1485
|
-
const displayText = text.trim();
|
|
1486
|
-
if (!displayText) return tag;
|
|
1487
|
-
const entry: QueuedDisplayEntry = { text: displayText, tag };
|
|
1488
|
-
if (mode === "steer") {
|
|
1489
|
-
this.#steeringMessages.push(entry);
|
|
1490
|
-
} else {
|
|
1491
|
-
this.#followUpMessages.push(entry);
|
|
1492
|
-
}
|
|
1493
|
-
return tag;
|
|
1494
|
-
}
|
|
1495
|
-
|
|
1496
1494
|
getAsyncJobSnapshot(options?: { recentLimit?: number }): AsyncJobSnapshot | null {
|
|
1497
1495
|
const manager = this.#asyncJobManager;
|
|
1498
1496
|
if (!manager) return null;
|
|
@@ -1614,45 +1612,6 @@ export class AgentSession {
|
|
|
1614
1612
|
|
|
1615
1613
|
/** Internal handler for agent events - shared by subscribe and reconnect */
|
|
1616
1614
|
#handleAgentEvent = async (event: AgentEvent): Promise<void> => {
|
|
1617
|
-
// When a user message starts, check if it's from either queue and remove it BEFORE emitting
|
|
1618
|
-
// This ensures the UI sees the updated queue state
|
|
1619
|
-
if (event.type === "message_start" && event.message.role === "user") {
|
|
1620
|
-
const messageText = this.#getUserMessageText(event.message);
|
|
1621
|
-
if (messageText) {
|
|
1622
|
-
// Check steering queue first (match by .text on tagged records)
|
|
1623
|
-
const steeringIndex = this.#steeringMessages.findIndex(e => e.text === messageText);
|
|
1624
|
-
if (steeringIndex !== -1) {
|
|
1625
|
-
this.#steeringMessages.splice(steeringIndex, 1);
|
|
1626
|
-
} else {
|
|
1627
|
-
// Check follow-up queue
|
|
1628
|
-
const followUpIndex = this.#followUpMessages.findIndex(e => e.text === messageText);
|
|
1629
|
-
if (followUpIndex !== -1) {
|
|
1630
|
-
this.#followUpMessages.splice(followUpIndex, 1);
|
|
1631
|
-
}
|
|
1632
|
-
}
|
|
1633
|
-
}
|
|
1634
|
-
}
|
|
1635
|
-
|
|
1636
|
-
// Tag-based dequeue for custom messages (skills queued via promptCustomMessage).
|
|
1637
|
-
// The InputController attached a stable tag via CustomMessage.details when it
|
|
1638
|
-
// registered the display chip; pull it back here to remove the matching entry
|
|
1639
|
-
// from the pending bar atomically with the agent's queue consumption. Match by
|
|
1640
|
-
// tag (not text) — two queued skills with identical args cannot collide.
|
|
1641
|
-
if (event.type === "message_start" && event.message.role === "custom") {
|
|
1642
|
-
const tag = readPendingDisplayTag(event.message.details);
|
|
1643
|
-
if (tag) {
|
|
1644
|
-
const steerIdx = this.#steeringMessages.findIndex(e => e.tag === tag);
|
|
1645
|
-
if (steerIdx !== -1) {
|
|
1646
|
-
this.#steeringMessages.splice(steerIdx, 1);
|
|
1647
|
-
} else {
|
|
1648
|
-
const followUpIdx = this.#followUpMessages.findIndex(e => e.tag === tag);
|
|
1649
|
-
if (followUpIdx !== -1) {
|
|
1650
|
-
this.#followUpMessages.splice(followUpIdx, 1);
|
|
1651
|
-
}
|
|
1652
|
-
}
|
|
1653
|
-
}
|
|
1654
|
-
}
|
|
1655
|
-
|
|
1656
1615
|
// Plan-mode → compaction transition: stamp `SILENT_ABORT_MARKER` on the
|
|
1657
1616
|
// persisted message BEFORE the obfuscator's display-side copy below.
|
|
1658
1617
|
// Invariant (must hold across refactors): this branch precedes the
|
|
@@ -1962,6 +1921,11 @@ export class AgentSession {
|
|
|
1962
1921
|
return;
|
|
1963
1922
|
}
|
|
1964
1923
|
|
|
1924
|
+
// A deliberate abort should settle the current turn, not trigger queued continuations.
|
|
1925
|
+
if (msg.stopReason === "aborted") {
|
|
1926
|
+
this.#resolveRetry();
|
|
1927
|
+
return;
|
|
1928
|
+
}
|
|
1965
1929
|
// Check for retryable errors first (overloaded, rate limit, server errors)
|
|
1966
1930
|
if (this.#isRetryableError(msg)) {
|
|
1967
1931
|
const didRetry = await this.#handleRetryableError(msg);
|
|
@@ -1984,7 +1948,7 @@ export class AgentSession {
|
|
|
1984
1948
|
if (compactionDeferredHandoff) {
|
|
1985
1949
|
return;
|
|
1986
1950
|
}
|
|
1987
|
-
if (msg.stopReason !== "error"
|
|
1951
|
+
if (msg.stopReason !== "error") {
|
|
1988
1952
|
if (this.#enforceRewindBeforeYield()) {
|
|
1989
1953
|
return;
|
|
1990
1954
|
}
|
|
@@ -2080,13 +2044,13 @@ export class AgentSession {
|
|
|
2080
2044
|
onError?: () => void;
|
|
2081
2045
|
}): void {
|
|
2082
2046
|
this.#schedulePostPromptTask(
|
|
2083
|
-
async
|
|
2047
|
+
async signal => {
|
|
2084
2048
|
// Defense in depth: if compaction/handoff slipped onto the post-prompt queue
|
|
2085
2049
|
// alongside us (e.g. via a scheduler we don't own), refuse to start a fresh
|
|
2086
2050
|
// streaming turn — agent.continue() here would race the handoff's session
|
|
2087
2051
|
// reset. The first-class fix is in #checkCompaction/the agent_end handler,
|
|
2088
2052
|
// but this guard catches anything that bypasses that path.
|
|
2089
|
-
if (this.isCompacting || this.isGeneratingHandoff) {
|
|
2053
|
+
if (signal.aborted || this.#isDisposed || this.isCompacting || this.isGeneratingHandoff) {
|
|
2090
2054
|
options?.onSkip?.();
|
|
2091
2055
|
return;
|
|
2092
2056
|
}
|
|
@@ -2094,14 +2058,21 @@ export class AgentSession {
|
|
|
2094
2058
|
options?.onSkip?.();
|
|
2095
2059
|
return;
|
|
2096
2060
|
}
|
|
2061
|
+
this.#beginInFlight();
|
|
2097
2062
|
try {
|
|
2098
2063
|
await this.#maybeRestoreRetryFallbackPrimary();
|
|
2064
|
+
if (signal.aborted || this.#isDisposed) {
|
|
2065
|
+
options?.onSkip?.();
|
|
2066
|
+
return;
|
|
2067
|
+
}
|
|
2099
2068
|
await this.agent.continue();
|
|
2100
2069
|
} catch (error) {
|
|
2101
2070
|
logger.warn("agent.continue failed after scheduling", {
|
|
2102
2071
|
error: error instanceof Error ? error.message : String(error),
|
|
2103
2072
|
});
|
|
2104
2073
|
options?.onError?.();
|
|
2074
|
+
} finally {
|
|
2075
|
+
this.#endInFlight();
|
|
2105
2076
|
}
|
|
2106
2077
|
},
|
|
2107
2078
|
{
|
|
@@ -2157,8 +2128,13 @@ export class AgentSession {
|
|
|
2157
2128
|
* and fire-and-forget `agent.continue()` may still be streaming after
|
|
2158
2129
|
* the TTSR resume gate resolves.
|
|
2159
2130
|
*/
|
|
2160
|
-
async #waitForPostPromptRecovery(): Promise<void> {
|
|
2131
|
+
async #waitForPostPromptRecovery(generation?: number): Promise<void> {
|
|
2161
2132
|
while (true) {
|
|
2133
|
+
// An abort bumps #promptGeneration. When this wait runs on behalf of a
|
|
2134
|
+
// specific prompt turn, stop as soon as that turn has been superseded:
|
|
2135
|
+
// its promise must resolve on the abort, not block on a queued
|
|
2136
|
+
// steer/follow-up that the post-abort drain starts as a fresh turn.
|
|
2137
|
+
if (generation !== undefined && this.#promptGeneration !== generation) return;
|
|
2162
2138
|
if (this.#retryPromise) {
|
|
2163
2139
|
await this.#retryPromise;
|
|
2164
2140
|
continue;
|
|
@@ -2620,18 +2596,6 @@ export class AgentSession {
|
|
|
2620
2596
|
|
|
2621
2597
|
return Array.from(candidates);
|
|
2622
2598
|
}
|
|
2623
|
-
/** Extract text content from a message */
|
|
2624
|
-
#getUserMessageText(message: Message): string {
|
|
2625
|
-
if (message.role !== "user") return "";
|
|
2626
|
-
const content = message.content;
|
|
2627
|
-
if (typeof content === "string") return content;
|
|
2628
|
-
const textBlocks = content.filter(c => c.type === "text");
|
|
2629
|
-
const text = textBlocks.map(c => (c as TextContent).text).join("");
|
|
2630
|
-
if (text.length > 0) return text;
|
|
2631
|
-
const hasImages = content.some(c => c.type === "image");
|
|
2632
|
-
return hasImages ? "[Image]" : "";
|
|
2633
|
-
}
|
|
2634
|
-
|
|
2635
2599
|
/** Find the last assistant message in agent state (including aborted ones) */
|
|
2636
2600
|
#findLastAssistantMessage(): AssistantMessage | undefined {
|
|
2637
2601
|
const messages = this.agent.state.messages;
|
|
@@ -3217,8 +3181,9 @@ export class AgentSession {
|
|
|
3217
3181
|
// session's dispose.
|
|
3218
3182
|
this.abortRetry();
|
|
3219
3183
|
this.abortCompaction();
|
|
3184
|
+
const postPromptDrain = this.#cancelPostPromptTasks();
|
|
3220
3185
|
this.agent.abort();
|
|
3221
|
-
await
|
|
3186
|
+
await postPromptDrain;
|
|
3222
3187
|
// Cancel jobs this agent registered so a subagent's teardown doesn't
|
|
3223
3188
|
// leak its background bash/task work into the parent's manager. Only
|
|
3224
3189
|
// the session that owns the manager goes on to dispose it (which itself
|
|
@@ -3340,6 +3305,10 @@ export class AgentSession {
|
|
|
3340
3305
|
return this.agent.state.isStreaming || this.#promptInFlightCount > 0;
|
|
3341
3306
|
}
|
|
3342
3307
|
|
|
3308
|
+
get isAborting(): boolean {
|
|
3309
|
+
return this.agent.isAborting;
|
|
3310
|
+
}
|
|
3311
|
+
|
|
3343
3312
|
/** Wait until streaming and deferred recovery work are fully settled. */
|
|
3344
3313
|
async waitForIdle(): Promise<void> {
|
|
3345
3314
|
await this.agent.waitForIdle();
|
|
@@ -4527,13 +4496,17 @@ export class AgentSession {
|
|
|
4527
4496
|
};
|
|
4528
4497
|
}
|
|
4529
4498
|
|
|
4499
|
+
#normalizeImagesForModel(images: ImageContent[] | undefined): Promise<ImageContent[] | undefined> {
|
|
4500
|
+
return normalizeModelContextImages(images, { model: this.model });
|
|
4501
|
+
}
|
|
4502
|
+
|
|
4530
4503
|
async #normalizeMessageContentImages(
|
|
4531
4504
|
content: string | (TextContent | ImageContent)[],
|
|
4532
4505
|
): Promise<string | (TextContent | ImageContent)[]> {
|
|
4533
4506
|
if (typeof content === "string") return content;
|
|
4534
4507
|
const images = content.filter((part): part is ImageContent => part.type === "image");
|
|
4535
4508
|
if (images.length === 0) return content;
|
|
4536
|
-
const normalizedImages = await
|
|
4509
|
+
const normalizedImages = await this.#normalizeImagesForModel(images);
|
|
4537
4510
|
if (!normalizedImages) return content;
|
|
4538
4511
|
let imageIndex = 0;
|
|
4539
4512
|
return content.map(part => (part.type === "image" ? normalizedImages[imageIndex++]! : part));
|
|
@@ -4646,9 +4619,9 @@ export class AgentSession {
|
|
|
4646
4619
|
throw new AgentBusyError();
|
|
4647
4620
|
}
|
|
4648
4621
|
if (options.streamingBehavior === "followUp") {
|
|
4649
|
-
await this.#
|
|
4622
|
+
await this.#queueUserMessage(expandedText, options?.images, "followUp");
|
|
4650
4623
|
} else {
|
|
4651
|
-
await this.#
|
|
4624
|
+
await this.#queueUserMessage(expandedText, options?.images, "steer");
|
|
4652
4625
|
}
|
|
4653
4626
|
// Steer/follow-up the keyword notices alongside the queued user message.
|
|
4654
4627
|
for (const notice of keywordNotices) {
|
|
@@ -4657,11 +4630,13 @@ export class AgentSession {
|
|
|
4657
4630
|
return true;
|
|
4658
4631
|
}
|
|
4659
4632
|
|
|
4660
|
-
// Skip eager
|
|
4633
|
+
// Skip eager preludes when the user has already queued a directive
|
|
4661
4634
|
const hasPendingUserDirective = this.#toolChoiceQueue.inspect().includes("user-force");
|
|
4662
4635
|
const eagerTodoPrelude =
|
|
4663
4636
|
!options?.synthetic && !hasPendingUserDirective ? this.#createEagerTodoPrelude(expandedText) : undefined;
|
|
4664
|
-
const
|
|
4637
|
+
const eagerTaskPrelude =
|
|
4638
|
+
!options?.synthetic && !hasPendingUserDirective ? this.#createEagerTaskPrelude(expandedText) : undefined;
|
|
4639
|
+
const normalizedImages = await this.#normalizeImagesForModel(options?.images);
|
|
4665
4640
|
|
|
4666
4641
|
const userContent: (TextContent | ImageContent)[] = [{ type: "text", text: expandedText }];
|
|
4667
4642
|
if (normalizedImages) {
|
|
@@ -4673,17 +4648,24 @@ export class AgentSession {
|
|
|
4673
4648
|
? { role: "developer" as const, content: userContent, attribution: promptAttribution, timestamp: Date.now() }
|
|
4674
4649
|
: { role: "user" as const, content: userContent, attribution: promptAttribution, timestamp: Date.now() };
|
|
4675
4650
|
|
|
4651
|
+
const preludeMessages: AgentMessage[] = [];
|
|
4676
4652
|
if (eagerTodoPrelude) {
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4653
|
+
if (eagerTodoPrelude.toolChoice) {
|
|
4654
|
+
this.#toolChoiceQueue.pushOnce(eagerTodoPrelude.toolChoice, {
|
|
4655
|
+
label: "eager-todo",
|
|
4656
|
+
});
|
|
4657
|
+
}
|
|
4658
|
+
preludeMessages.push(eagerTodoPrelude.message);
|
|
4659
|
+
}
|
|
4660
|
+
if (eagerTaskPrelude) {
|
|
4661
|
+
preludeMessages.push(eagerTaskPrelude);
|
|
4680
4662
|
}
|
|
4681
4663
|
|
|
4682
4664
|
try {
|
|
4683
4665
|
await this.#promptWithMessage(message, expandedText, {
|
|
4684
4666
|
...options,
|
|
4685
4667
|
images: normalizedImages,
|
|
4686
|
-
prependMessages:
|
|
4668
|
+
prependMessages: preludeMessages.length > 0 ? preludeMessages : undefined,
|
|
4687
4669
|
appendMessages: keywordNotices.length > 0 ? keywordNotices : undefined,
|
|
4688
4670
|
});
|
|
4689
4671
|
} finally {
|
|
@@ -4699,7 +4681,7 @@ export class AgentSession {
|
|
|
4699
4681
|
|
|
4700
4682
|
async promptCustomMessage<T = unknown>(
|
|
4701
4683
|
message: Pick<CustomMessage<T>, "customType" | "content" | "display" | "details" | "attribution">,
|
|
4702
|
-
options?: Pick<PromptOptions, "streamingBehavior" | "toolChoice"
|
|
4684
|
+
options?: Pick<PromptOptions, "streamingBehavior" | "toolChoice"> & { queueChipText?: string },
|
|
4703
4685
|
): Promise<void> {
|
|
4704
4686
|
const textContent =
|
|
4705
4687
|
typeof message.content === "string"
|
|
@@ -4723,7 +4705,10 @@ export class AgentSession {
|
|
|
4723
4705
|
if (!options?.streamingBehavior) {
|
|
4724
4706
|
throw new AgentBusyError();
|
|
4725
4707
|
}
|
|
4726
|
-
await this.sendCustomMessage(message, {
|
|
4708
|
+
await this.sendCustomMessage(message, {
|
|
4709
|
+
deliverAs: options.streamingBehavior,
|
|
4710
|
+
queueChipText: options.queueChipText,
|
|
4711
|
+
});
|
|
4727
4712
|
for (const notice of keywordNotices) {
|
|
4728
4713
|
await this.sendCustomMessage(notice, { deliverAs: options.streamingBehavior });
|
|
4729
4714
|
}
|
|
@@ -4908,7 +4893,7 @@ export class AgentSession {
|
|
|
4908
4893
|
const agentPromptOptions = options?.toolChoice ? { toolChoice: options.toolChoice } : undefined;
|
|
4909
4894
|
await this.#promptAgentWithIdleRetry(messages, agentPromptOptions);
|
|
4910
4895
|
if (!options?.skipPostPromptRecoveryWait) {
|
|
4911
|
-
await this.#waitForPostPromptRecovery();
|
|
4896
|
+
await this.#waitForPostPromptRecovery(generation);
|
|
4912
4897
|
}
|
|
4913
4898
|
} finally {
|
|
4914
4899
|
this.#endInFlight();
|
|
@@ -4958,6 +4943,7 @@ export class AgentSession {
|
|
|
4958
4943
|
sessionManager: this.sessionManager,
|
|
4959
4944
|
modelRegistry: this.#modelRegistry,
|
|
4960
4945
|
model: this.model ?? undefined,
|
|
4946
|
+
models: createExtensionModelQuery(this.#modelRegistry, this.settings, () => this.model ?? undefined),
|
|
4961
4947
|
isIdle: () => !this.isStreaming,
|
|
4962
4948
|
abort: () => {
|
|
4963
4949
|
void this.abort();
|
|
@@ -5060,7 +5046,7 @@ export class AgentSession {
|
|
|
5060
5046
|
}
|
|
5061
5047
|
|
|
5062
5048
|
const expandedText = expandPromptTemplate(text, [...this.#promptTemplates]);
|
|
5063
|
-
await this.#
|
|
5049
|
+
await this.#queueUserMessage(expandedText, images, "steer");
|
|
5064
5050
|
}
|
|
5065
5051
|
|
|
5066
5052
|
/**
|
|
@@ -5072,80 +5058,74 @@ export class AgentSession {
|
|
|
5072
5058
|
}
|
|
5073
5059
|
|
|
5074
5060
|
const expandedText = expandPromptTemplate(text, [...this.#promptTemplates]);
|
|
5075
|
-
await this.#
|
|
5061
|
+
await this.#queueUserMessage(expandedText, images, "followUp");
|
|
5076
5062
|
}
|
|
5077
5063
|
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
const
|
|
5084
|
-
this.#steeringMessages.push({ text: displayText, images });
|
|
5064
|
+
async #queueUserMessage(
|
|
5065
|
+
text: string,
|
|
5066
|
+
images: ImageContent[] | undefined,
|
|
5067
|
+
mode: "steer" | "followUp",
|
|
5068
|
+
): Promise<void> {
|
|
5069
|
+
const normalizedImages = await this.#normalizeImagesForModel(images);
|
|
5085
5070
|
const content: (TextContent | ImageContent)[] = [{ type: "text", text }];
|
|
5086
|
-
if (normalizedImages
|
|
5071
|
+
if (normalizedImages?.length) {
|
|
5087
5072
|
content.push(...normalizedImages);
|
|
5088
5073
|
}
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
shouldContinue: () => this.#canAutoContinueForFollowUp() && this.agent.hasQueuedMessages(),
|
|
5074
|
+
if (mode === "followUp") {
|
|
5075
|
+
this.agent.followUp({
|
|
5076
|
+
role: "user",
|
|
5077
|
+
content,
|
|
5078
|
+
attribution: "user",
|
|
5079
|
+
timestamp: Date.now(),
|
|
5080
|
+
});
|
|
5081
|
+
} else {
|
|
5082
|
+
this.agent.steer({
|
|
5083
|
+
role: "user",
|
|
5084
|
+
content,
|
|
5085
|
+
steering: true,
|
|
5086
|
+
attribution: "user",
|
|
5087
|
+
timestamp: Date.now(),
|
|
5104
5088
|
});
|
|
5105
5089
|
}
|
|
5090
|
+
this.#scheduleIdleQueueDrain();
|
|
5106
5091
|
}
|
|
5107
5092
|
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
|
|
5115
|
-
const content: (TextContent | ImageContent)[] = [{ type: "text", text }];
|
|
5116
|
-
if (normalizedImages && normalizedImages.length > 0) {
|
|
5117
|
-
content.push(...normalizedImages);
|
|
5093
|
+
#scheduleIdleQueueDrain(): void {
|
|
5094
|
+
this.#scheduleQueuedMessageDrain();
|
|
5095
|
+
}
|
|
5096
|
+
|
|
5097
|
+
#scheduleQueuedMessageDrain(): void {
|
|
5098
|
+
if (this.#queuedMessageDrainScheduled || !this.#canAutoContinueForFollowUp() || !this.agent.hasQueuedMessages()) {
|
|
5099
|
+
return;
|
|
5118
5100
|
}
|
|
5119
|
-
this
|
|
5120
|
-
|
|
5121
|
-
|
|
5122
|
-
|
|
5123
|
-
|
|
5101
|
+
this.#queuedMessageDrainScheduled = true;
|
|
5102
|
+
this.#scheduleAgentContinue({
|
|
5103
|
+
shouldContinue: () => {
|
|
5104
|
+
this.#queuedMessageDrainScheduled = false;
|
|
5105
|
+
return this.#canAutoContinueForFollowUp() && this.agent.hasQueuedMessages();
|
|
5106
|
+
},
|
|
5107
|
+
onSkip: () => {
|
|
5108
|
+
this.#queuedMessageDrainScheduled = false;
|
|
5109
|
+
},
|
|
5110
|
+
onError: () => {
|
|
5111
|
+
this.#queuedMessageDrainScheduled = false;
|
|
5112
|
+
},
|
|
5124
5113
|
});
|
|
5125
|
-
// When fully idle AND the session is in a resumable assistant-ended state,
|
|
5126
|
-
// schedule an immediate continue so the queued follow-up is delivered
|
|
5127
|
-
// without waiting for the next user turn. We gate on isStreaming (model
|
|
5128
|
-
// actively producing), isRetrying (auto-retry backoff is sleeping between
|
|
5129
|
-
// attempts, #retryPromise set), and the last message being assistant —
|
|
5130
|
-
// agent.continue() only dequeues follow-ups from an assistant-ended state;
|
|
5131
|
-
// resuming from user/toolResult state runs an extra model call on the
|
|
5132
|
-
// stale prompt before draining the queue.
|
|
5133
|
-
if (this.#canAutoContinueForFollowUp()) {
|
|
5134
|
-
this.#scheduleAgentContinue({
|
|
5135
|
-
shouldContinue: () => this.#canAutoContinueForFollowUp() && this.agent.hasQueuedMessages(),
|
|
5136
|
-
});
|
|
5137
|
-
}
|
|
5138
5114
|
}
|
|
5139
5115
|
|
|
5140
5116
|
/**
|
|
5141
|
-
* Gate for idle-path
|
|
5117
|
+
* Gate for idle-path queued-message auto-continue. See `#scheduleIdleQueueDrain` for rationale.
|
|
5142
5118
|
*/
|
|
5143
5119
|
#canAutoContinueForFollowUp(): boolean {
|
|
5144
5120
|
if (this.isStreaming) return false;
|
|
5145
5121
|
if (this.isRetrying) return false;
|
|
5146
5122
|
const messages = this.agent.state.messages;
|
|
5147
5123
|
const last = messages[messages.length - 1];
|
|
5148
|
-
|
|
5124
|
+
// A user interrupt during tool execution can leave the transcript ending
|
|
5125
|
+
// with the emitted tool result, not the aborted assistant message. Continuing
|
|
5126
|
+
// from that state is still resumable: Agent.continue() first polls queued
|
|
5127
|
+
// steering before making the next model call.
|
|
5128
|
+
return last?.role === "assistant" || last?.role === "toolResult";
|
|
5149
5129
|
}
|
|
5150
5130
|
|
|
5151
5131
|
queueDeferredMessage(message: CustomMessage): void {
|
|
@@ -5244,17 +5224,33 @@ export class AgentSession {
|
|
|
5244
5224
|
* - Streaming: queue as steer/follow-up or store for next turn
|
|
5245
5225
|
* - Not streaming + triggerTurn: appends to state/session, starts new turn unless the client cannot own it
|
|
5246
5226
|
* - Not streaming + no trigger: appends to state/session, no turn
|
|
5227
|
+
*
|
|
5228
|
+
* @returns true iff this call synchronously started a new turn (awaited
|
|
5229
|
+
* `agent.prompt`); false when the message was queued/appended without a turn
|
|
5230
|
+
* — including when `triggerTurn` is downgraded because the client defers
|
|
5231
|
+
* agent-initiated turns. Callers that must mirror the resulting `agent_end`
|
|
5232
|
+
* use this to avoid acting on a turn that never ran.
|
|
5247
5233
|
*/
|
|
5248
5234
|
async sendCustomMessage<T = unknown>(
|
|
5249
5235
|
message: Pick<CustomMessage<T>, "customType" | "content" | "display" | "details" | "attribution">,
|
|
5250
|
-
options?: { triggerTurn?: boolean; deliverAs?: "steer" | "followUp" | "nextTurn" },
|
|
5251
|
-
): Promise<
|
|
5236
|
+
options?: { triggerTurn?: boolean; deliverAs?: "steer" | "followUp" | "nextTurn"; queueChipText?: string },
|
|
5237
|
+
): Promise<boolean> {
|
|
5238
|
+
const details =
|
|
5239
|
+
options?.queueChipText && options.deliverAs !== "nextTurn"
|
|
5240
|
+
? ({
|
|
5241
|
+
...((message.details && typeof message.details === "object" ? message.details : {}) as Record<
|
|
5242
|
+
string,
|
|
5243
|
+
unknown
|
|
5244
|
+
>),
|
|
5245
|
+
__queueChipText: options.queueChipText,
|
|
5246
|
+
} as T)
|
|
5247
|
+
: message.details;
|
|
5252
5248
|
const appMessage: CustomMessage<T> = {
|
|
5253
5249
|
role: "custom",
|
|
5254
5250
|
customType: message.customType,
|
|
5255
5251
|
content: message.content,
|
|
5256
5252
|
display: message.display,
|
|
5257
|
-
details
|
|
5253
|
+
details,
|
|
5258
5254
|
attribution: message.attribution ?? "agent",
|
|
5259
5255
|
timestamp: Date.now(),
|
|
5260
5256
|
};
|
|
@@ -5262,7 +5258,7 @@ export class AgentSession {
|
|
|
5262
5258
|
if (this.isStreaming) {
|
|
5263
5259
|
if (options?.deliverAs === "nextTurn") {
|
|
5264
5260
|
this.#queueHiddenNextTurnMessage(normalizedAppMessage, options?.triggerTurn ?? false);
|
|
5265
|
-
return;
|
|
5261
|
+
return false;
|
|
5266
5262
|
}
|
|
5267
5263
|
|
|
5268
5264
|
if (options?.deliverAs === "followUp") {
|
|
@@ -5270,25 +5266,18 @@ export class AgentSession {
|
|
|
5270
5266
|
} else {
|
|
5271
5267
|
this.agent.steer(normalizedAppMessage);
|
|
5272
5268
|
}
|
|
5273
|
-
|
|
5274
|
-
|
|
5275
|
-
// queued on an idle agent. Mirror #queueSteer's idle-path delivery.
|
|
5276
|
-
if (this.#canAutoContinueForFollowUp()) {
|
|
5277
|
-
this.#scheduleAgentContinue({
|
|
5278
|
-
shouldContinue: () => this.#canAutoContinueForFollowUp() && this.agent.hasQueuedMessages(),
|
|
5279
|
-
});
|
|
5280
|
-
}
|
|
5281
|
-
return;
|
|
5269
|
+
this.#scheduleIdleQueueDrain();
|
|
5270
|
+
return false;
|
|
5282
5271
|
}
|
|
5283
5272
|
|
|
5284
5273
|
if (options?.deliverAs === "nextTurn") {
|
|
5285
5274
|
if (options?.triggerTurn) {
|
|
5286
5275
|
if (this.#clientBridge?.deferAgentInitiatedTurns && !this.#allowAcpAgentInitiatedTurns) {
|
|
5287
5276
|
this.#queueHiddenNextTurnMessage(normalizedAppMessage, false);
|
|
5288
|
-
return;
|
|
5277
|
+
return false;
|
|
5289
5278
|
}
|
|
5290
5279
|
await this.agent.prompt(normalizedAppMessage);
|
|
5291
|
-
return;
|
|
5280
|
+
return true;
|
|
5292
5281
|
}
|
|
5293
5282
|
this.agent.appendMessage(normalizedAppMessage);
|
|
5294
5283
|
this.sessionManager.appendCustomMessageEntry(
|
|
@@ -5298,16 +5287,16 @@ export class AgentSession {
|
|
|
5298
5287
|
message.details,
|
|
5299
5288
|
message.attribution ?? "agent",
|
|
5300
5289
|
);
|
|
5301
|
-
return;
|
|
5290
|
+
return false;
|
|
5302
5291
|
}
|
|
5303
5292
|
|
|
5304
5293
|
if (options?.triggerTurn) {
|
|
5305
5294
|
if (this.#clientBridge?.deferAgentInitiatedTurns && !this.#allowAcpAgentInitiatedTurns) {
|
|
5306
5295
|
this.#queueHiddenNextTurnMessage(normalizedAppMessage, false);
|
|
5307
|
-
return;
|
|
5296
|
+
return false;
|
|
5308
5297
|
}
|
|
5309
5298
|
await this.agent.prompt(normalizedAppMessage);
|
|
5310
|
-
return;
|
|
5299
|
+
return true;
|
|
5311
5300
|
}
|
|
5312
5301
|
|
|
5313
5302
|
this.agent.appendMessage(normalizedAppMessage);
|
|
@@ -5318,6 +5307,7 @@ export class AgentSession {
|
|
|
5318
5307
|
message.details,
|
|
5319
5308
|
message.attribution ?? "agent",
|
|
5320
5309
|
);
|
|
5310
|
+
return false;
|
|
5321
5311
|
}
|
|
5322
5312
|
|
|
5323
5313
|
/**
|
|
@@ -5352,11 +5342,11 @@ export class AgentSession {
|
|
|
5352
5342
|
}
|
|
5353
5343
|
|
|
5354
5344
|
if (options?.deliverAs === "followUp") {
|
|
5355
|
-
await this.#
|
|
5345
|
+
await this.#queueUserMessage(text, images, "followUp");
|
|
5356
5346
|
return;
|
|
5357
5347
|
}
|
|
5358
5348
|
if (options?.deliverAs === "steer") {
|
|
5359
|
-
await this.#
|
|
5349
|
+
await this.#queueUserMessage(text, images, "steer");
|
|
5360
5350
|
return;
|
|
5361
5351
|
}
|
|
5362
5352
|
|
|
@@ -5367,57 +5357,37 @@ export class AgentSession {
|
|
|
5367
5357
|
});
|
|
5368
5358
|
}
|
|
5369
5359
|
|
|
5370
|
-
/**
|
|
5371
|
-
* Clear queued messages and return them (text plus any attached images).
|
|
5372
|
-
* Useful for restoring to editor when user aborts. The internal entry
|
|
5373
|
-
* arrays are handed out as-is — a `tag` (if any) is inert once the record
|
|
5374
|
-
* leaves the queue.
|
|
5375
|
-
*/
|
|
5360
|
+
/** Clear queued messages and return them (text plus any attached images). */
|
|
5376
5361
|
clearQueue(): { steering: RestoredQueuedMessage[]; followUp: RestoredQueuedMessage[] } {
|
|
5377
|
-
const steering = this
|
|
5378
|
-
const followUp = this
|
|
5379
|
-
this.#steeringMessages = [];
|
|
5380
|
-
this.#followUpMessages = [];
|
|
5362
|
+
const steering = this.agent.peekSteeringQueue().map(toRestoredQueuedMessage);
|
|
5363
|
+
const followUp = this.agent.peekFollowUpQueue().map(toRestoredQueuedMessage);
|
|
5381
5364
|
this.agent.clearAllQueues();
|
|
5382
5365
|
return { steering, followUp };
|
|
5383
5366
|
}
|
|
5384
5367
|
|
|
5385
|
-
/** Number of pending messages (includes steering, follow-up, and next-turn messages) */
|
|
5368
|
+
/** Number of pending displayable messages (includes steering, follow-up, and next-turn messages) */
|
|
5386
5369
|
get queuedMessageCount(): number {
|
|
5387
|
-
return
|
|
5370
|
+
return (
|
|
5371
|
+
this.agent.peekSteeringQueue().filter(isDisplayableQueuedMessage).length +
|
|
5372
|
+
this.agent.peekFollowUpQueue().filter(isDisplayableQueuedMessage).length +
|
|
5373
|
+
this.#pendingNextTurnMessages.length
|
|
5374
|
+
);
|
|
5388
5375
|
}
|
|
5389
5376
|
|
|
5390
|
-
/** Get pending messages (read-only). Returns the public text-only view;
|
|
5391
|
-
* internal `{text, tag?}` records are mapped to `.text` so callers
|
|
5392
|
-
* (`updatePendingMessagesDisplay`, `restoreQueuedMessagesToEditor`) see
|
|
5393
|
-
* the unchanged historical shape. */
|
|
5394
5377
|
getQueuedMessages(): { steering: readonly string[]; followUp: readonly string[] } {
|
|
5395
5378
|
return {
|
|
5396
|
-
steering: this
|
|
5397
|
-
followUp: this
|
|
5379
|
+
steering: this.agent.peekSteeringQueue().filter(isDisplayableQueuedMessage).map(queueChipText),
|
|
5380
|
+
followUp: this.agent.peekFollowUpQueue().filter(isDisplayableQueuedMessage).map(queueChipText),
|
|
5398
5381
|
};
|
|
5399
5382
|
}
|
|
5400
5383
|
|
|
5401
5384
|
/**
|
|
5402
5385
|
* Pop the last queued message (steering first, then follow-up).
|
|
5403
5386
|
* Used by dequeue keybinding to restore messages to editor one at a time.
|
|
5404
|
-
* Returns the popped entry's text and images; the tag (if any) dies with
|
|
5405
|
-
* the record — no orphan state can outlive the queue entry.
|
|
5406
5387
|
*/
|
|
5407
5388
|
popLastQueuedMessage(): RestoredQueuedMessage | undefined {
|
|
5408
|
-
|
|
5409
|
-
|
|
5410
|
-
const entry = this.#steeringMessages.pop();
|
|
5411
|
-
this.agent.popLastSteer();
|
|
5412
|
-
return entry;
|
|
5413
|
-
}
|
|
5414
|
-
// Then from follow-up
|
|
5415
|
-
if (this.#followUpMessages.length > 0) {
|
|
5416
|
-
const entry = this.#followUpMessages.pop();
|
|
5417
|
-
this.agent.popLastFollowUp();
|
|
5418
|
-
return entry;
|
|
5419
|
-
}
|
|
5420
|
-
return undefined;
|
|
5389
|
+
const message = this.agent.popLastSteer() ?? this.agent.popLastFollowUp();
|
|
5390
|
+
return message ? toRestoredQueuedMessage(message) : undefined;
|
|
5421
5391
|
}
|
|
5422
5392
|
|
|
5423
5393
|
get skillsSettings(): SkillsSettings | undefined {
|
|
@@ -5474,44 +5444,40 @@ export class AgentSession {
|
|
|
5474
5444
|
* abort. Omit it for internal/lifecycle aborts.
|
|
5475
5445
|
*/
|
|
5476
5446
|
async abort(options?: { goalReason?: "interrupted" | "internal"; reason?: string }): Promise<void> {
|
|
5477
|
-
|
|
5478
|
-
|
|
5479
|
-
|
|
5480
|
-
this
|
|
5481
|
-
|
|
5482
|
-
|
|
5483
|
-
|
|
5484
|
-
|
|
5485
|
-
|
|
5486
|
-
|
|
5487
|
-
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5497
|
-
|
|
5498
|
-
|
|
5447
|
+
// Session switch/compact paths disconnect first; explicit aborts should
|
|
5448
|
+
// leave any queued steer/follow-up visible for the user rather than
|
|
5449
|
+
// auto-starting a fresh turn during cleanup.
|
|
5450
|
+
this.#abortInProgress = true;
|
|
5451
|
+
try {
|
|
5452
|
+
this.abortRetry();
|
|
5453
|
+
this.#promptGeneration++;
|
|
5454
|
+
this.#scheduledHiddenNextTurnGeneration = undefined;
|
|
5455
|
+
this.abortCompaction();
|
|
5456
|
+
this.abortHandoff();
|
|
5457
|
+
this.abortBash();
|
|
5458
|
+
this.abortEval();
|
|
5459
|
+
const postPromptDrain = this.#cancelPostPromptTasks();
|
|
5460
|
+
this.agent.abort(options?.reason);
|
|
5461
|
+
await postPromptDrain;
|
|
5462
|
+
await this.agent.waitForIdle();
|
|
5463
|
+
await this.#goalRuntime.onTaskAborted({ reason: options?.goalReason ?? "interrupted" });
|
|
5464
|
+
// Clear prompt-in-flight state: waitForIdle resolves when the agent loop's finally
|
|
5465
|
+
// block runs, but nested prompt setup/finalizers may still be unwinding. Without this,
|
|
5466
|
+
// a subsequent prompt() can incorrectly observe the session as busy after an abort.
|
|
5467
|
+
this.#resetInFlight();
|
|
5468
|
+
// Safety net: if the agent loop aborted without producing an assistant
|
|
5469
|
+
// message (e.g. failed before the first stream), the in-flight yield was
|
|
5470
|
+
// never resolved or rejected by the normal message_end path. Reject it now
|
|
5471
|
+
// so any requeue callback still fires and the queue stays consistent.
|
|
5472
|
+
if (this.#toolChoiceQueue.hasInFlight) {
|
|
5473
|
+
this.#toolChoiceQueue.reject("aborted");
|
|
5474
|
+
}
|
|
5475
|
+
} finally {
|
|
5476
|
+
this.#abortInProgress = false;
|
|
5477
|
+
this.#drainStrandedQueuedMessages();
|
|
5499
5478
|
}
|
|
5500
5479
|
}
|
|
5501
5480
|
|
|
5502
|
-
/**
|
|
5503
|
-
* Abort active work, then immediately resume the agent so queued steer/follow-up
|
|
5504
|
-
* messages drain instead of waiting for another natural turn boundary.
|
|
5505
|
-
*/
|
|
5506
|
-
async interruptAndFlushQueuedMessages(options?: { reason?: string }): Promise<void> {
|
|
5507
|
-
if (!this.agent.hasQueuedMessages()) return;
|
|
5508
|
-
await this.abort({ reason: options?.reason });
|
|
5509
|
-
if (!this.agent.hasQueuedMessages()) return;
|
|
5510
|
-
if (this.isCompacting || this.isGeneratingHandoff) return;
|
|
5511
|
-
await this.#maybeRestoreRetryFallbackPrimary();
|
|
5512
|
-
await this.agent.continue();
|
|
5513
|
-
}
|
|
5514
|
-
|
|
5515
5481
|
/**
|
|
5516
5482
|
* Start a new session, optionally with initial messages and parent tracking.
|
|
5517
5483
|
* Clears all messages and starts a new session.
|
|
@@ -5562,8 +5528,6 @@ export class AgentSession {
|
|
|
5562
5528
|
this.#rekeyMnemopiMemoryForCurrentSessionId();
|
|
5563
5529
|
this.#resetHindsightConversationTrackingIfHindsight();
|
|
5564
5530
|
this.#resetMnemopiConversationTrackingIfMnemopi();
|
|
5565
|
-
this.#steeringMessages = [];
|
|
5566
|
-
this.#followUpMessages = [];
|
|
5567
5531
|
this.#pendingNextTurnMessages = [];
|
|
5568
5532
|
this.#scheduledHiddenNextTurnGeneration = undefined;
|
|
5569
5533
|
|
|
@@ -5678,7 +5642,10 @@ export class AgentSession {
|
|
|
5678
5642
|
|
|
5679
5643
|
/**
|
|
5680
5644
|
* Set model directly.
|
|
5681
|
-
* Validates
|
|
5645
|
+
* Validates that a credential source is configured (synchronously, without
|
|
5646
|
+
* refreshing OAuth or running command-backed key programs) and saves to the
|
|
5647
|
+
* active session. Persists settings only when requested. The concrete key is
|
|
5648
|
+
* resolved lazily per request, so switching never blocks the event loop.
|
|
5682
5649
|
* @throws Error if no API key available for the model
|
|
5683
5650
|
*/
|
|
5684
5651
|
async setModel(
|
|
@@ -5687,8 +5654,7 @@ export class AgentSession {
|
|
|
5687
5654
|
options?: { selector?: string; thinkingLevel?: ThinkingLevel; persist?: boolean },
|
|
5688
5655
|
): Promise<void> {
|
|
5689
5656
|
const previousEditMode = this.#resolveActiveEditMode();
|
|
5690
|
-
|
|
5691
|
-
if (!apiKey) {
|
|
5657
|
+
if (!this.#modelRegistry.hasConfiguredAuth(model)) {
|
|
5692
5658
|
throw new Error(`No API key for ${model.provider}/${model.id}`);
|
|
5693
5659
|
}
|
|
5694
5660
|
|
|
@@ -5711,7 +5677,9 @@ export class AgentSession {
|
|
|
5711
5677
|
|
|
5712
5678
|
/**
|
|
5713
5679
|
* Set model temporarily (for this session only).
|
|
5714
|
-
* Validates
|
|
5680
|
+
* Validates that a credential source is configured (synchronously, without
|
|
5681
|
+
* refreshing OAuth or running command-backed key programs), saves to session
|
|
5682
|
+
* log but NOT to settings.
|
|
5715
5683
|
* @throws Error if no API key available for the model
|
|
5716
5684
|
*/
|
|
5717
5685
|
async setModelTemporary(
|
|
@@ -5720,8 +5688,7 @@ export class AgentSession {
|
|
|
5720
5688
|
options?: { ephemeral?: boolean },
|
|
5721
5689
|
): Promise<void> {
|
|
5722
5690
|
const previousEditMode = this.#resolveActiveEditMode();
|
|
5723
|
-
|
|
5724
|
-
if (!apiKey) {
|
|
5691
|
+
if (!this.#modelRegistry.hasConfiguredAuth(model)) {
|
|
5725
5692
|
throw new Error(`No API key for ${model.provider}/${model.id}`);
|
|
5726
5693
|
}
|
|
5727
5694
|
|
|
@@ -6113,7 +6080,12 @@ export class AgentSession {
|
|
|
6113
6080
|
// Already on under any scope — keep the user's scoped value.
|
|
6114
6081
|
return;
|
|
6115
6082
|
}
|
|
6116
|
-
|
|
6083
|
+
if (!enabled) {
|
|
6084
|
+
this.setServiceTier(undefined);
|
|
6085
|
+
return;
|
|
6086
|
+
}
|
|
6087
|
+
const scope = this.settings.get("fastModeScope");
|
|
6088
|
+
this.setServiceTier(scope === "openai" ? "openai-only" : scope === "claude" ? "claude-only" : "priority");
|
|
6117
6089
|
}
|
|
6118
6090
|
|
|
6119
6091
|
toggleFastMode(): boolean {
|
|
@@ -6705,8 +6677,6 @@ export class AgentSession {
|
|
|
6705
6677
|
this.#rekeyMnemopiMemoryForCurrentSessionId();
|
|
6706
6678
|
this.#resetHindsightConversationTrackingIfHindsight();
|
|
6707
6679
|
this.#resetMnemopiConversationTrackingIfMnemopi();
|
|
6708
|
-
this.#steeringMessages = [];
|
|
6709
|
-
this.#followUpMessages = [];
|
|
6710
6680
|
this.#pendingNextTurnMessages = [];
|
|
6711
6681
|
this.#scheduledHiddenNextTurnGeneration = undefined;
|
|
6712
6682
|
this.#todoReminderCount = 0;
|
|
@@ -6978,10 +6948,11 @@ export class AgentSession {
|
|
|
6978
6948
|
#isEmptyAssistantStop(assistantMessage: AssistantMessage): boolean {
|
|
6979
6949
|
switch (assistantMessage.stopReason) {
|
|
6980
6950
|
case "stop":
|
|
6951
|
+
// Reasoning/thinking-only turns are not actionable: they do not
|
|
6952
|
+
// answer the user and do not give the agent loop a tool call to run.
|
|
6981
6953
|
for (const content of assistantMessage.content) {
|
|
6982
6954
|
if (content.type === "toolCall") return false;
|
|
6983
6955
|
if (content.type === "text" && hasNonWhitespace(content.text)) return false;
|
|
6984
|
-
if (content.type === "thinking" && hasNonWhitespace(content.thinking)) return false;
|
|
6985
6956
|
}
|
|
6986
6957
|
return true;
|
|
6987
6958
|
case "toolUse":
|
|
@@ -7132,10 +7103,28 @@ export class AgentSession {
|
|
|
7132
7103
|
});
|
|
7133
7104
|
}
|
|
7134
7105
|
|
|
7135
|
-
|
|
7136
|
-
|
|
7106
|
+
/**
|
|
7107
|
+
* Render context shared by the eager todo/task preludes. `toolRefs` resolves each
|
|
7108
|
+
* tool's wire name (matching `buildSystemPrompt`'s `toolRefs`) so the reminder names
|
|
7109
|
+
* the tool the model actually sees when an extension renames it; `taskBatch` gates
|
|
7110
|
+
* batch-call guidance that would steer toward a failing call shape when `task.batch`
|
|
7111
|
+
* is off (the flat single-spawn schema rejects `tasks`/`context`).
|
|
7112
|
+
*/
|
|
7113
|
+
#buildEagerPreludeContext(): { toolRefs: Record<string, string>; taskBatch: boolean } {
|
|
7114
|
+
const wireName = (name: string): string => {
|
|
7115
|
+
const tool = this.#toolRegistry.get(name);
|
|
7116
|
+
return typeof tool?.customWireName === "string" ? tool.customWireName : name;
|
|
7117
|
+
};
|
|
7118
|
+
return {
|
|
7119
|
+
toolRefs: { task: wireName("task"), todo: wireName("todo") },
|
|
7120
|
+
taskBatch: this.settings.get("task.batch"),
|
|
7121
|
+
};
|
|
7122
|
+
}
|
|
7123
|
+
|
|
7124
|
+
#createEagerTodoPrelude(promptText: string): { message: AgentMessage; toolChoice?: ToolChoice } | undefined {
|
|
7125
|
+
const mode = this.settings.get("todo.eager");
|
|
7137
7126
|
const todosEnabled = this.settings.get("todo.enabled");
|
|
7138
|
-
if (
|
|
7127
|
+
if (mode === "default" || !todosEnabled) {
|
|
7139
7128
|
return undefined;
|
|
7140
7129
|
}
|
|
7141
7130
|
|
|
@@ -7170,27 +7159,53 @@ export class AgentSession {
|
|
|
7170
7159
|
return undefined;
|
|
7171
7160
|
}
|
|
7172
7161
|
|
|
7162
|
+
const message: AgentMessage = {
|
|
7163
|
+
role: "custom",
|
|
7164
|
+
customType: "eager-todo-prelude",
|
|
7165
|
+
content: prompt.render(eagerTodoPrompt, { ...this.#buildEagerPreludeContext(), forced: mode === "always" }),
|
|
7166
|
+
display: false,
|
|
7167
|
+
attribution: "agent",
|
|
7168
|
+
timestamp: Date.now(),
|
|
7169
|
+
};
|
|
7170
|
+
// `preferred` suggests a todo list (reminder only); `always` also forces the
|
|
7171
|
+
// `todo` tool on the first turn — the previous boolean-on behavior.
|
|
7172
|
+
if (mode === "preferred") {
|
|
7173
|
+
return { message };
|
|
7174
|
+
}
|
|
7173
7175
|
const todoToolChoice = buildNamedToolChoice("todo", this.model);
|
|
7174
7176
|
if (!todoToolChoice) {
|
|
7175
|
-
|
|
7176
|
-
|
|
7177
|
-
|
|
7178
|
-
|
|
7179
|
-
|
|
7180
|
-
|
|
7181
|
-
|
|
7182
|
-
|
|
7183
|
-
|
|
7177
|
+
// `always` on a model that can't be forced degrades to reminder-only (no
|
|
7178
|
+
// tool_choice). For `todo.eager: true` users migrated to `always`, such
|
|
7179
|
+
// models now receive the first-turn reminder where they previously got
|
|
7180
|
+
// nothing (see the CHANGELOG entry); `always ⊇ preferred` is preserved.
|
|
7181
|
+
logger.warn(
|
|
7182
|
+
"Eager todo proceeding with the reminder only because the current model does not support a forced todo tool_choice",
|
|
7183
|
+
{ modelApi: this.model?.api, modelId: this.model?.id },
|
|
7184
|
+
);
|
|
7185
|
+
return { message };
|
|
7186
|
+
}
|
|
7187
|
+
return { message, toolChoice: todoToolChoice };
|
|
7188
|
+
}
|
|
7189
|
+
|
|
7190
|
+
#createEagerTaskPrelude(promptText: string): AgentMessage | undefined {
|
|
7191
|
+
if (this.settings.get("task.eager") !== "always") return undefined;
|
|
7192
|
+
// Main agent only: subagents keep `task` active (the parent only filters `todo`),
|
|
7193
|
+
// so a salient delegate-reminder there would amplify nested fan-out. Gate on the
|
|
7194
|
+
// resolved agent kind, not the id, so a top-level session with a custom `agentId`
|
|
7195
|
+
// still gets the reminder.
|
|
7196
|
+
if (this.#agentKind === "sub") return undefined;
|
|
7197
|
+
if (this.#planModeState?.enabled) return undefined;
|
|
7198
|
+
if (this.agent.state.messages.some(m => m.role === "user")) return undefined;
|
|
7199
|
+
const trimmed = promptText.trimEnd();
|
|
7200
|
+
if (trimmed.endsWith("?") || trimmed.endsWith("!")) return undefined;
|
|
7201
|
+
if (!this.getActiveToolNames().includes("task")) return undefined;
|
|
7184
7202
|
return {
|
|
7185
|
-
|
|
7186
|
-
|
|
7187
|
-
|
|
7188
|
-
|
|
7189
|
-
|
|
7190
|
-
|
|
7191
|
-
timestamp: Date.now(),
|
|
7192
|
-
},
|
|
7193
|
-
toolChoice: todoToolChoice,
|
|
7203
|
+
role: "custom",
|
|
7204
|
+
customType: "eager-task-prelude",
|
|
7205
|
+
content: prompt.render(eagerTaskPrompt, this.#buildEagerPreludeContext()),
|
|
7206
|
+
display: false,
|
|
7207
|
+
attribution: "agent",
|
|
7208
|
+
timestamp: Date.now(),
|
|
7194
7209
|
};
|
|
7195
7210
|
}
|
|
7196
7211
|
/**
|
|
@@ -7315,7 +7330,7 @@ export class AgentSession {
|
|
|
7315
7330
|
const candidate = this.#resolveContextPromotionConfiguredTarget(currentModel, availableModels);
|
|
7316
7331
|
if (!candidate) return undefined;
|
|
7317
7332
|
if (modelsAreEqual(candidate, currentModel)) return undefined;
|
|
7318
|
-
if (candidate.contextWindow <= contextWindow) return undefined;
|
|
7333
|
+
if (candidate.contextWindow == null || candidate.contextWindow <= contextWindow) return undefined;
|
|
7319
7334
|
const apiKey = await this.#modelRegistry.getApiKey(candidate, this.sessionId);
|
|
7320
7335
|
if (!apiKey) return undefined;
|
|
7321
7336
|
return candidate;
|
|
@@ -7626,7 +7641,7 @@ export class AgentSession {
|
|
|
7626
7641
|
addCandidate(this.#resolveRoleModelFull(role, availableModels, currentModel).model);
|
|
7627
7642
|
}
|
|
7628
7643
|
|
|
7629
|
-
const sortedByContext = [...availableModels].sort((a, b) => b.contextWindow - a.contextWindow);
|
|
7644
|
+
const sortedByContext = [...availableModels].sort((a, b) => (b.contextWindow ?? 0) - (a.contextWindow ?? 0));
|
|
7630
7645
|
for (const model of sortedByContext) {
|
|
7631
7646
|
if (!seen.has(this.#getModelKey(model))) {
|
|
7632
7647
|
addCandidate(model);
|
|
@@ -9603,8 +9618,8 @@ export class AgentSession {
|
|
|
9603
9618
|
// the existing message objects is sufficient and avoids structured-clone failures for
|
|
9604
9619
|
// extension/custom metadata that is valid to persist but not cloneable.
|
|
9605
9620
|
const previousAgentMessages = [...this.agent.state.messages];
|
|
9606
|
-
const previousSteeringMessages = [...this
|
|
9607
|
-
const previousFollowUpMessages = [...this
|
|
9621
|
+
const previousSteeringMessages = [...this.agent.peekSteeringQueue()];
|
|
9622
|
+
const previousFollowUpMessages = [...this.agent.peekFollowUpQueue()];
|
|
9608
9623
|
const previousPendingNextTurnMessages = [...this.#pendingNextTurnMessages];
|
|
9609
9624
|
const previousScheduledHiddenNextTurnGeneration = this.#scheduledHiddenNextTurnGeneration;
|
|
9610
9625
|
const previousModel = this.model;
|
|
@@ -9621,8 +9636,7 @@ export class AgentSession {
|
|
|
9621
9636
|
? this.#getSessionDefaultSelectedMCPToolNames(previousSessionFile)
|
|
9622
9637
|
: undefined;
|
|
9623
9638
|
|
|
9624
|
-
this
|
|
9625
|
-
this.#followUpMessages = [];
|
|
9639
|
+
this.agent.clearAllQueues();
|
|
9626
9640
|
this.#pendingNextTurnMessages = [];
|
|
9627
9641
|
this.#scheduledHiddenNextTurnGeneration = undefined;
|
|
9628
9642
|
|
|
@@ -9763,8 +9777,7 @@ export class AgentSession {
|
|
|
9763
9777
|
this.#baseSystemPrompt = previousBaseSystemPrompt;
|
|
9764
9778
|
this.agent.setSystemPrompt(previousSystemPrompt);
|
|
9765
9779
|
this.agent.replaceMessages(previousAgentMessages);
|
|
9766
|
-
this
|
|
9767
|
-
this.#followUpMessages = previousFollowUpMessages;
|
|
9780
|
+
this.agent.replaceQueues(previousSteeringMessages, previousFollowUpMessages);
|
|
9768
9781
|
this.#pendingNextTurnMessages = previousPendingNextTurnMessages;
|
|
9769
9782
|
this.#scheduledHiddenNextTurnGeneration = previousScheduledHiddenNextTurnGeneration;
|
|
9770
9783
|
if (previousModel) {
|