@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
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
type NativeScrollbackCommittedRows,
|
|
5
5
|
type NativeScrollbackLiveRegion,
|
|
6
6
|
type RenderStablePrefix,
|
|
7
|
+
type ViewportTailProvider,
|
|
7
8
|
} from "@oh-my-pi/pi-tui";
|
|
8
9
|
|
|
9
10
|
const kSnapshot = Symbol("transcript.liveDiffSnapshot");
|
|
@@ -139,6 +140,8 @@ interface BlockSegment {
|
|
|
139
140
|
}
|
|
140
141
|
|
|
141
142
|
const EMPTY_SEGMENTS: BlockSegment[] = [];
|
|
143
|
+
/** Shared empty result for an empty viewport-tail render (no allocation). */
|
|
144
|
+
const EMPTY_TAIL: readonly string[] = [];
|
|
142
145
|
|
|
143
146
|
interface LiveCommitState {
|
|
144
147
|
appendOnly: boolean;
|
|
@@ -415,7 +418,7 @@ function deriveLiveCommitState(
|
|
|
415
418
|
*/
|
|
416
419
|
export class TranscriptContainer
|
|
417
420
|
extends Container
|
|
418
|
-
implements NativeScrollbackLiveRegion, NativeScrollbackCommittedRows, RenderStablePrefix
|
|
421
|
+
implements NativeScrollbackLiveRegion, NativeScrollbackCommittedRows, RenderStablePrefix, ViewportTailProvider
|
|
419
422
|
{
|
|
420
423
|
// Bumped to retire every block's diff snapshot at once (theme change /
|
|
421
424
|
// clear); a snapshot is only honored when its stored generation matches.
|
|
@@ -432,6 +435,14 @@ export class TranscriptContainer
|
|
|
432
435
|
// until it re-earns append-only via VOLATILE_REARM_FRAMES clean frames;
|
|
433
436
|
// the engine then backfills the stalled gap.
|
|
434
437
|
#nativeScrollbackCommitSafeEnd: number | undefined;
|
|
438
|
+
// Local line index up to which the leading run of live blocks is DURABLE: a
|
|
439
|
+
// commit-stable block's full body is permanent content even while its interior
|
|
440
|
+
// rows re-lay-out (a streaming markdown table re-aligning columns), so the
|
|
441
|
+
// engine must append their scroll-off snapshot rather than drop it. Reported
|
|
442
|
+
// separately from the byte-stable commit-safe end because these rows may still
|
|
443
|
+
// drift after commit; the engine commits them audit-exempt. Provisional
|
|
444
|
+
// (commit-unstable) blocks never extend it.
|
|
445
|
+
#nativeScrollbackSnapshotSafeEnd: number | undefined;
|
|
435
446
|
// Persistent assembled transcript rows. Rows before the stable floor are
|
|
436
447
|
// byte-identical to the previous render; rows at/after it were re-pushed.
|
|
437
448
|
#lines: string[] = [];
|
|
@@ -476,6 +487,10 @@ export class TranscriptContainer
|
|
|
476
487
|
return this.#nativeScrollbackCommitSafeEnd;
|
|
477
488
|
}
|
|
478
489
|
|
|
490
|
+
getNativeScrollbackSnapshotSafeEnd(): number | undefined {
|
|
491
|
+
return this.#nativeScrollbackSnapshotSafeEnd;
|
|
492
|
+
}
|
|
493
|
+
|
|
479
494
|
/**
|
|
480
495
|
* Whether `component` sits below a still-mutating block — i.e. inside the
|
|
481
496
|
* live region, where its rows cannot have been committed to native
|
|
@@ -520,10 +535,54 @@ export class TranscriptContainer
|
|
|
520
535
|
return index === children.length - 1;
|
|
521
536
|
}
|
|
522
537
|
|
|
538
|
+
/**
|
|
539
|
+
* Render only the bottom `maxRows` rows of the transcript at `width`, walking
|
|
540
|
+
* blocks from the last toward the first and stopping the instant enough rows
|
|
541
|
+
* are collected — blocks above the fold are never rendered. The engine's
|
|
542
|
+
* resize viewport fast path uses this so a drag (a SIGWINCH burst, each event
|
|
543
|
+
* a fresh width that misses every per-width cache) re-lays-out only the
|
|
544
|
+
* handful of visible blocks instead of the whole history every event.
|
|
545
|
+
*
|
|
546
|
+
* State-isolated by contract: touches none of the persistent full-compose
|
|
547
|
+
* fields (#lines, #segments, the per-block diff snapshots, the commit/stable
|
|
548
|
+
* bookkeeping), so the authoritative full render on settle reconciles exactly
|
|
549
|
+
* as if this never ran. Calling each block's render() still warms its own
|
|
550
|
+
* per-width cache, which that settle render then reuses for free.
|
|
551
|
+
*
|
|
552
|
+
* Consecutive visible blocks are joined by exactly one blank separator, the
|
|
553
|
+
* same rule render() applies, so the result equals the bottom of a full
|
|
554
|
+
* render except for an at-most-one-row separator on the topmost included
|
|
555
|
+
* block — a transient discrepancy the settle paint overwrites.
|
|
556
|
+
*/
|
|
557
|
+
renderViewportTail(width: number, maxRows: number): readonly string[] {
|
|
558
|
+
width = Math.max(1, width);
|
|
559
|
+
if (maxRows <= 0) return EMPTY_TAIL;
|
|
560
|
+
const collected: (readonly string[])[] = [];
|
|
561
|
+
let total = 0;
|
|
562
|
+
for (let i = this.children.length - 1; i >= 0 && total < maxRows; i--) {
|
|
563
|
+
const contribution = stripPlainBlankEdges(this.children[i]!.render(width));
|
|
564
|
+
if (contribution.length === 0) continue;
|
|
565
|
+
// One blank separator sits between this block and the (already
|
|
566
|
+
// collected) visible block below it.
|
|
567
|
+
if (collected.length > 0) total += 1;
|
|
568
|
+
collected.push(contribution);
|
|
569
|
+
total += contribution.length;
|
|
570
|
+
}
|
|
571
|
+
if (collected.length === 0) return EMPTY_TAIL;
|
|
572
|
+
const rows: string[] = [];
|
|
573
|
+
for (let k = collected.length - 1; k >= 0; k--) {
|
|
574
|
+
if (rows.length > 0) rows.push("");
|
|
575
|
+
const body = collected[k]!;
|
|
576
|
+
for (let j = 0; j < body.length; j++) rows.push(body[j]!);
|
|
577
|
+
}
|
|
578
|
+
return rows.length > maxRows ? rows.slice(rows.length - maxRows) : rows;
|
|
579
|
+
}
|
|
580
|
+
|
|
523
581
|
override render(width: number): readonly string[] {
|
|
524
582
|
width = Math.max(1, width);
|
|
525
583
|
this.#nativeScrollbackLiveRegionStart = undefined;
|
|
526
584
|
this.#nativeScrollbackCommitSafeEnd = undefined;
|
|
585
|
+
this.#nativeScrollbackSnapshotSafeEnd = undefined;
|
|
527
586
|
|
|
528
587
|
const count = this.children.length;
|
|
529
588
|
|
|
@@ -696,6 +755,16 @@ export class TranscriptContainer
|
|
|
696
755
|
if (safeLength > 0) {
|
|
697
756
|
this.#nativeScrollbackCommitSafeEnd = blockStart + safeLength;
|
|
698
757
|
}
|
|
758
|
+
// Durable snapshot end: a commit-stable block's whole body is durable
|
|
759
|
+
// content — its scrolled-off rows are permanent even while interior
|
|
760
|
+
// rows re-lay-out (a streaming table re-aligning columns), so the
|
|
761
|
+
// engine must commit their snapshot on scroll-off rather than drop it.
|
|
762
|
+
// Finalized blocks are wholly durable; provisional (commit-unstable)
|
|
763
|
+
// blocks offer nothing beyond their byte-stable safe length.
|
|
764
|
+
const snapshotLength = finalized || isBlockCommitStable(child) ? contribution.length : safeLength;
|
|
765
|
+
if (snapshotLength > 0) {
|
|
766
|
+
this.#nativeScrollbackSnapshotSafeEnd = blockStart + snapshotLength;
|
|
767
|
+
}
|
|
699
768
|
// A finalized, fully safe block may let the contiguous safe run extend
|
|
700
769
|
// into blocks rendered below it. A still-live block keeps pushing lower
|
|
701
770
|
// rows around as it grows, so the run closes there.
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
import type { TreeFilterMode } from "../../config/settings-schema";
|
|
16
16
|
import { theme } from "../../modes/theme/theme";
|
|
17
17
|
import { matchesAppInterrupt, matchesSelectDown, matchesSelectUp } from "../../modes/utils/keybinding-matchers";
|
|
18
|
-
import type { SessionTreeNode } from "../../session/session-
|
|
18
|
+
import type { SessionTreeNode } from "../../session/session-entries";
|
|
19
19
|
import { shortenPath } from "../../tools/render-utils";
|
|
20
20
|
import { toPathList } from "../../tools/search";
|
|
21
21
|
import { DynamicBorder } from "./dynamic-border";
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Usage } from "@oh-my-pi/pi-ai";
|
|
2
|
+
import { Container, Spacer, Text } from "@oh-my-pi/pi-tui";
|
|
3
|
+
import { formatNumber } from "@oh-my-pi/pi-utils";
|
|
4
|
+
import { theme } from "../../modes/theme/theme";
|
|
5
|
+
|
|
6
|
+
export function createUsageRowBlock(usage: Usage): Container {
|
|
7
|
+
const totalInput = usage.input + usage.cacheWrite;
|
|
8
|
+
const parts: string[] = [];
|
|
9
|
+
parts.push(`${theme.icon.input} ${formatNumber(totalInput)}`);
|
|
10
|
+
parts.push(`${theme.icon.output} ${formatNumber(usage.output)}`);
|
|
11
|
+
if (usage.cacheRead > 0) {
|
|
12
|
+
parts.push(`cache: ${formatNumber(usage.cacheRead)}`);
|
|
13
|
+
}
|
|
14
|
+
const block = new Container();
|
|
15
|
+
block.addChild(new Spacer(1));
|
|
16
|
+
block.addChild(new Text(theme.fg("dim", parts.join(" ")), 1, 0));
|
|
17
|
+
return block;
|
|
18
|
+
}
|
|
@@ -4,9 +4,11 @@ import { imageReferenceHyperlink, renderPlaceholders } from "../image-references
|
|
|
4
4
|
import { highlightMagicKeywords } from "../magic-keywords";
|
|
5
5
|
|
|
6
6
|
// OSC 133 shell integration: marks prompt zones for terminal multiplexers
|
|
7
|
+
// Do not emit OSC 133 C ("command start") here: the transcript has no matching
|
|
8
|
+
// command-finished marker, so terminals can group later assistant/tool output
|
|
9
|
+
// under the first submitted prompt.
|
|
7
10
|
const OSC133_ZONE_START = "\x1b]133;A\x07";
|
|
8
11
|
const OSC133_ZONE_END = "\x1b]133;B\x07";
|
|
9
|
-
const OSC133_ZONE_FINAL = "\x1b]133;C\x07";
|
|
10
12
|
|
|
11
13
|
/**
|
|
12
14
|
* Component that renders a user message
|
|
@@ -58,7 +60,7 @@ export class UserMessageComponent extends Container {
|
|
|
58
60
|
}
|
|
59
61
|
const wrapped = lines.slice();
|
|
60
62
|
wrapped[0] = OSC133_ZONE_START + wrapped[0];
|
|
61
|
-
wrapped[wrapped.length - 1] = wrapped[wrapped.length - 1] + OSC133_ZONE_END
|
|
63
|
+
wrapped[wrapped.length - 1] = wrapped[wrapped.length - 1] + OSC133_ZONE_END;
|
|
62
64
|
this.#zoneSource = lines;
|
|
63
65
|
this.#zoneLines = wrapped;
|
|
64
66
|
return wrapped;
|
|
@@ -38,7 +38,7 @@ import { buildHotkeysMarkdown } from "../../modes/utils/hotkeys-markdown";
|
|
|
38
38
|
import { buildToolsMarkdown } from "../../modes/utils/tools-markdown";
|
|
39
39
|
import type { AsyncJobSnapshotItem } from "../../session/agent-session";
|
|
40
40
|
import type { AuthStorage, OAuthAccountIdentity } from "../../session/auth-storage";
|
|
41
|
-
import type { NewSessionOptions } from "../../session/session-
|
|
41
|
+
import type { NewSessionOptions } from "../../session/session-entries";
|
|
42
42
|
import { formatShakeSummary, type ShakeMode, type ShakeResult } from "../../session/shake-types";
|
|
43
43
|
import { limitMatchesActiveAccount } from "../../slash-commands/helpers/active-oauth-account";
|
|
44
44
|
import { outputMeta } from "../../tools/output-meta";
|
|
@@ -965,7 +965,10 @@ export class CommandController {
|
|
|
965
965
|
this.ctx.ui.requestRender();
|
|
966
966
|
}
|
|
967
967
|
|
|
968
|
-
async handleCompactCommand(
|
|
968
|
+
async handleCompactCommand(
|
|
969
|
+
customInstructions?: string,
|
|
970
|
+
beforeFlush?: (outcome: CompactionOutcome) => void | Promise<void>,
|
|
971
|
+
): Promise<CompactionOutcome> {
|
|
969
972
|
const entries = this.ctx.sessionManager.getEntries();
|
|
970
973
|
const messageCount = entries.filter(e => e.type === "message").length;
|
|
971
974
|
|
|
@@ -974,7 +977,7 @@ export class CommandController {
|
|
|
974
977
|
return "ok";
|
|
975
978
|
}
|
|
976
979
|
|
|
977
|
-
return this.executeCompaction(customInstructions, false);
|
|
980
|
+
return this.executeCompaction(customInstructions, false, beforeFlush);
|
|
978
981
|
}
|
|
979
982
|
|
|
980
983
|
/**
|
|
@@ -1019,6 +1022,7 @@ export class CommandController {
|
|
|
1019
1022
|
async executeCompaction(
|
|
1020
1023
|
customInstructionsOrOptions?: string | CompactOptions,
|
|
1021
1024
|
isAuto = false,
|
|
1025
|
+
beforeFlush?: (outcome: CompactionOutcome) => void | Promise<void>,
|
|
1022
1026
|
): Promise<CompactionOutcome> {
|
|
1023
1027
|
if (this.ctx.loadingAnimation) {
|
|
1024
1028
|
this.ctx.loadingAnimation.stop();
|
|
@@ -1026,12 +1030,6 @@ export class CommandController {
|
|
|
1026
1030
|
}
|
|
1027
1031
|
this.ctx.statusContainer.clear();
|
|
1028
1032
|
|
|
1029
|
-
const originalOnEscape = this.ctx.editor.onEscape;
|
|
1030
|
-
this.ctx.editor.onEscape = () => {
|
|
1031
|
-
this.ctx.session.abortCompaction();
|
|
1032
|
-
};
|
|
1033
|
-
|
|
1034
|
-
this.ctx.chatContainer.addChild(new Spacer(1));
|
|
1035
1033
|
const label = isAuto ? "Auto-compacting context... (esc to cancel)" : "Compacting context... (esc to cancel)";
|
|
1036
1034
|
const compactingLoader = new Loader(
|
|
1037
1035
|
this.ctx.ui,
|
|
@@ -1052,6 +1050,8 @@ export class CommandController {
|
|
|
1052
1050
|
: undefined;
|
|
1053
1051
|
await this.ctx.session.compact(instructions, options);
|
|
1054
1052
|
|
|
1053
|
+
compactingLoader.stop();
|
|
1054
|
+
this.ctx.statusContainer.clear();
|
|
1055
1055
|
this.ctx.rebuildChatFromMessages();
|
|
1056
1056
|
|
|
1057
1057
|
this.ctx.statusLine.invalidate();
|
|
@@ -1068,8 +1068,12 @@ export class CommandController {
|
|
|
1068
1068
|
} finally {
|
|
1069
1069
|
compactingLoader.stop();
|
|
1070
1070
|
this.ctx.statusContainer.clear();
|
|
1071
|
-
this.ctx.editor.onEscape = originalOnEscape;
|
|
1072
1071
|
}
|
|
1072
|
+
// Run the caller's pre-flush hook (e.g. the plan-approval model transition)
|
|
1073
|
+
// before queued user input is dispatched, so any turn queued during
|
|
1074
|
+
// compaction executes on the post-compaction model rather than the model
|
|
1075
|
+
// compaction itself ran on.
|
|
1076
|
+
if (beforeFlush) await beforeFlush(outcome);
|
|
1073
1077
|
await this.ctx.flushCompactionQueue({ willRetry: false });
|
|
1074
1078
|
return outcome;
|
|
1075
1079
|
}
|
|
@@ -1089,11 +1093,6 @@ export class CommandController {
|
|
|
1089
1093
|
}
|
|
1090
1094
|
this.ctx.statusContainer.clear();
|
|
1091
1095
|
|
|
1092
|
-
const originalOnEscape = this.ctx.editor.onEscape;
|
|
1093
|
-
this.ctx.editor.onEscape = () => {
|
|
1094
|
-
this.ctx.session.abortHandoff();
|
|
1095
|
-
};
|
|
1096
|
-
|
|
1097
1096
|
const handoffLoader = new Loader(
|
|
1098
1097
|
this.ctx.ui,
|
|
1099
1098
|
spinner => theme.fg("accent", spinner),
|
|
@@ -1138,7 +1137,6 @@ export class CommandController {
|
|
|
1138
1137
|
} finally {
|
|
1139
1138
|
handoffLoader.stop();
|
|
1140
1139
|
this.ctx.statusContainer.clear();
|
|
1141
|
-
this.ctx.editor.onEscape = originalOnEscape;
|
|
1142
1140
|
}
|
|
1143
1141
|
this.ctx.ui.requestRender();
|
|
1144
1142
|
}
|
|
@@ -2,6 +2,7 @@ import { INTENT_FIELD } from "@oh-my-pi/pi-agent-core";
|
|
|
2
2
|
import { calculatePromptTokens } from "@oh-my-pi/pi-agent-core/compaction/compaction";
|
|
3
3
|
import type { AssistantMessage, ImageContent } from "@oh-my-pi/pi-ai";
|
|
4
4
|
import { type Component, Loader, TERMINAL } from "@oh-my-pi/pi-tui";
|
|
5
|
+
import { extractTextContent } from "../../commit/utils";
|
|
5
6
|
import { settings } from "../../config/settings";
|
|
6
7
|
import { getFileSnapshotStore } from "../../edit/file-snapshot-store";
|
|
7
8
|
import { AssistantMessageComponent } from "../../modes/components/assistant-message";
|
|
@@ -13,12 +14,15 @@ import {
|
|
|
13
14
|
import { TodoReminderComponent } from "../../modes/components/todo-reminder";
|
|
14
15
|
import { ToolExecutionComponent } from "../../modes/components/tool-execution";
|
|
15
16
|
import { TtsrNotificationComponent } from "../../modes/components/ttsr-notification";
|
|
17
|
+
import { createUsageRowBlock } from "../../modes/components/usage-row";
|
|
16
18
|
import { getSymbolTheme, theme } from "../../modes/theme/theme";
|
|
17
19
|
import type { InteractiveModeContext, TodoPhase } from "../../modes/types";
|
|
18
20
|
import type { PlanApprovalDetails } from "../../plan-mode/approved-plan";
|
|
19
21
|
import type { AgentSessionEvent } from "../../session/agent-session";
|
|
20
|
-
import { isSilentAbort,
|
|
22
|
+
import { isSilentAbort, readQueueChipText, resolveAbortLabel } from "../../session/messages";
|
|
21
23
|
import type { ResolveToolDetails } from "../../tools/resolve";
|
|
24
|
+
import { vocalizer } from "../../tts/vocalizer";
|
|
25
|
+
import { hasVisibleThinking } from "../../utils/thinking-display";
|
|
22
26
|
import { interruptHint } from "../shared";
|
|
23
27
|
import { StreamingRevealController } from "./streaming-reveal";
|
|
24
28
|
import { ToolArgsRevealController } from "./tool-args-reveal";
|
|
@@ -37,16 +41,6 @@ const IRC_MESSAGE_VISIBLE_TTL_MS = 10_000;
|
|
|
37
41
|
*/
|
|
38
42
|
const MAX_LIVE_IRC_CARDS = 4;
|
|
39
43
|
|
|
40
|
-
/**
|
|
41
|
-
* Loader label shown the instant a user interrupt (Esc) is requested, kept until
|
|
42
|
-
* the agent turn fully unwinds. Esc fires the abort synchronously, but the loop
|
|
43
|
-
* only stops the spinner at `agent_end`, which it cannot reach until every
|
|
44
|
-
* in-flight tool settles its abort in `executeToolCalls` (`Promise.allSettled`).
|
|
45
|
-
* Swapping the steady "Working…" for this acknowledges the keypress instead of
|
|
46
|
-
* reading as an ignored Esc for the seconds a slow tool takes to tear down.
|
|
47
|
-
*/
|
|
48
|
-
export const INTERRUPTING_WORKING_MESSAGE = "Interrupting…";
|
|
49
|
-
|
|
50
44
|
type AgentSessionEventHandlers = {
|
|
51
45
|
[E in AgentSessionEventKind]: (event: Extract<AgentSessionEvent, { type: E }>) => Promise<void>;
|
|
52
46
|
};
|
|
@@ -63,8 +57,6 @@ export class EventController {
|
|
|
63
57
|
#renderedCustomMessages = new Set<string>();
|
|
64
58
|
#lastIntent: string | undefined = undefined;
|
|
65
59
|
#backgroundToolCallIds = new Set<string>();
|
|
66
|
-
#agentTurnActive = false;
|
|
67
|
-
#interrupting = false;
|
|
68
60
|
#readToolCallArgs = new Map<string, Record<string, unknown>>();
|
|
69
61
|
#readToolCallAssistantComponents = new Map<string, AssistantMessageComponent>();
|
|
70
62
|
#lastAssistantComponent: AssistantMessageComponent | undefined = undefined;
|
|
@@ -103,8 +95,8 @@ export class EventController {
|
|
|
103
95
|
this.#handlers = {
|
|
104
96
|
agent_start: e => this.#handleAgentStart(e),
|
|
105
97
|
agent_end: e => this.#handleAgentEnd(e),
|
|
106
|
-
turn_start: async () =>
|
|
107
|
-
turn_end: async
|
|
98
|
+
turn_start: async () => this.#handleTurnStart(),
|
|
99
|
+
turn_end: async e => this.#handleTurnEnd(e),
|
|
108
100
|
message_start: e => this.#handleMessageStart(e),
|
|
109
101
|
message_update: e => this.#handleMessageUpdate(e),
|
|
110
102
|
message_end: e => this.#handleMessageEnd(e),
|
|
@@ -193,7 +185,7 @@ export class EventController {
|
|
|
193
185
|
return true;
|
|
194
186
|
}
|
|
195
187
|
#updateWorkingMessageFromIntent(intent: unknown): void {
|
|
196
|
-
if (this
|
|
188
|
+
if (this.ctx.session.isAborting) return;
|
|
197
189
|
// Streamed JSON can deliver non-string `_i` (object, number, boolean) before
|
|
198
190
|
// schema validation; `?.` only guards null/undefined, so guard the type too.
|
|
199
191
|
if (typeof intent !== "string") return;
|
|
@@ -203,19 +195,6 @@ export class EventController {
|
|
|
203
195
|
this.ctx.setWorkingMessage(`${trimmed}${interruptHint()}`);
|
|
204
196
|
}
|
|
205
197
|
|
|
206
|
-
/**
|
|
207
|
-
* Acknowledge a user interrupt (Esc) immediately: switch the loader to
|
|
208
|
-
* `INTERRUPTING_WORKING_MESSAGE` and freeze intent-driven working-message
|
|
209
|
-
* updates for the rest of the turn so a late `tool_execution_start` intent
|
|
210
|
-
* cannot repaint a "Working…/<intent>" line over the acknowledgment. Reset at
|
|
211
|
-
* the next `agent_start`. No-op outside an active turn or if already set.
|
|
212
|
-
*/
|
|
213
|
-
notifyInterrupting(): void {
|
|
214
|
-
if (!this.#agentTurnActive || this.#interrupting) return;
|
|
215
|
-
this.#interrupting = true;
|
|
216
|
-
this.ctx.setWorkingMessage(INTERRUPTING_WORKING_MESSAGE);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
198
|
subscribeToAgent(): void {
|
|
220
199
|
this.ctx.unsubscribe = this.ctx.session.subscribe(async (event: AgentSessionEvent) => {
|
|
221
200
|
await this.handleEvent(event);
|
|
@@ -233,8 +212,6 @@ export class EventController {
|
|
|
233
212
|
this.#renderedCustomMessages.clear();
|
|
234
213
|
this.#lastIntent = undefined;
|
|
235
214
|
this.#backgroundToolCallIds.clear();
|
|
236
|
-
this.#agentTurnActive = false;
|
|
237
|
-
this.#interrupting = false;
|
|
238
215
|
this.#readToolCallArgs.clear();
|
|
239
216
|
this.#readToolCallAssistantComponents.clear();
|
|
240
217
|
this.#lastAssistantComponent = undefined;
|
|
@@ -264,8 +241,6 @@ export class EventController {
|
|
|
264
241
|
}
|
|
265
242
|
|
|
266
243
|
async #handleAgentStart(_event: Extract<AgentSessionEvent, { type: "agent_start" }>): Promise<void> {
|
|
267
|
-
this.#agentTurnActive = true;
|
|
268
|
-
this.#interrupting = false;
|
|
269
244
|
this.#lastIntent = undefined;
|
|
270
245
|
this.#readToolCallArgs.clear();
|
|
271
246
|
this.#readToolCallAssistantComponents.clear();
|
|
@@ -276,10 +251,6 @@ export class EventController {
|
|
|
276
251
|
this.#pinnedErrorComponent?.setErrorPinned(false);
|
|
277
252
|
this.#pinnedErrorComponent = undefined;
|
|
278
253
|
this.ctx.clearPinnedError();
|
|
279
|
-
if (this.ctx.retryEscapeHandler) {
|
|
280
|
-
this.ctx.editor.onEscape = this.ctx.retryEscapeHandler;
|
|
281
|
-
this.ctx.retryEscapeHandler = undefined;
|
|
282
|
-
}
|
|
283
254
|
if (this.ctx.retryLoader) {
|
|
284
255
|
this.ctx.retryLoader.stop();
|
|
285
256
|
this.ctx.retryLoader = undefined;
|
|
@@ -299,15 +270,10 @@ export class EventController {
|
|
|
299
270
|
this.#renderedCustomMessages.add(signature);
|
|
300
271
|
this.#resetReadGroup();
|
|
301
272
|
this.ctx.addMessageToChat(event.message);
|
|
302
|
-
//
|
|
303
|
-
//
|
|
304
|
-
//
|
|
305
|
-
|
|
306
|
-
// re-rendered to match. Gated on tag presence so non-queued customs
|
|
307
|
-
// (ttsr-injection, irc:*, async-result, hookMessage) skip the
|
|
308
|
-
// rebuild; their dispatch path never registered a pending chip.
|
|
309
|
-
// Mirrors the user-role refresh at the bottom of this function.
|
|
310
|
-
if (event.message.role === "custom" && readPendingDisplayTag(event.message.details)) {
|
|
273
|
+
// Queued custom-message chips are derived from the agent queue; refresh the
|
|
274
|
+
// pending bar when the queued custom is consumed so the chip disappears
|
|
275
|
+
// immediately.
|
|
276
|
+
if (event.message.role === "custom" && readQueueChipText(event.message.details)) {
|
|
311
277
|
this.ctx.updatePendingMessagesDisplay();
|
|
312
278
|
}
|
|
313
279
|
this.ctx.ui.requestRender();
|
|
@@ -467,7 +433,47 @@ export class EventController {
|
|
|
467
433
|
}
|
|
468
434
|
}
|
|
469
435
|
|
|
436
|
+
/** A new turn interrupts any speech still queued/playing from the previous one. */
|
|
437
|
+
#handleTurnStart(): void {
|
|
438
|
+
vocalizer.clear();
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Speak streamed assistant output as a side effect of the turn. The mode
|
|
443
|
+
* decides which deltas feed the vocalizer (the vocalizer re-checks enabled):
|
|
444
|
+
* assistant|all speak text; all also speaks thinking; yield speaks nothing
|
|
445
|
+
* live (the final message is spoken at turn end).
|
|
446
|
+
*/
|
|
447
|
+
#vocalizeDelta(event: Extract<AgentSessionEvent, { type: "message_update" }>): void {
|
|
448
|
+
if (!settings.get("speech.enabled")) return;
|
|
449
|
+
const mode = settings.get("speech.mode");
|
|
450
|
+
const delta = event.assistantMessageEvent;
|
|
451
|
+
if (delta.type === "text_delta" && (mode === "assistant" || mode === "all")) {
|
|
452
|
+
vocalizer.pushDelta(delta.delta);
|
|
453
|
+
} else if (delta.type === "thinking_delta" && mode === "all") {
|
|
454
|
+
vocalizer.pushDelta(delta.delta);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* End-of-turn vocalization: yield mode speaks the final assistant message in
|
|
460
|
+
* one shot here (the only mode that is post-hoc); every other mode just makes
|
|
461
|
+
* sure the live buffer's trailing partial gets flushed.
|
|
462
|
+
*/
|
|
463
|
+
#handleTurnEnd(event: Extract<AgentSessionEvent, { type: "turn_end" }>): void {
|
|
464
|
+
if (!settings.get("speech.enabled")) return;
|
|
465
|
+
if (settings.get("speech.mode") !== "yield") {
|
|
466
|
+
vocalizer.flush();
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
if (event.message.role !== "assistant") return;
|
|
470
|
+
if (event.message.stopReason === "aborted") return; // interrupted: never speak the aborted partial
|
|
471
|
+
const text = extractTextContent(event.message);
|
|
472
|
+
if (text) vocalizer.speak(text);
|
|
473
|
+
}
|
|
474
|
+
|
|
470
475
|
async #handleMessageUpdate(event: Extract<AgentSessionEvent, { type: "message_update" }>): Promise<void> {
|
|
476
|
+
this.#vocalizeDelta(event);
|
|
471
477
|
if (this.ctx.streamingComponent && event.message.role === "assistant") {
|
|
472
478
|
this.ctx.streamingMessage = event.message;
|
|
473
479
|
this.#streamingReveal.setTarget(this.ctx.streamingMessage);
|
|
@@ -475,7 +481,7 @@ export class EventController {
|
|
|
475
481
|
const visibleBlockCount = this.ctx.streamingMessage.content.filter(
|
|
476
482
|
content =>
|
|
477
483
|
(content.type === "text" && content.text.trim().length > 0) ||
|
|
478
|
-
(content.type === "thinking" && content
|
|
484
|
+
(content.type === "thinking" && hasVisibleThinking(content)),
|
|
479
485
|
).length;
|
|
480
486
|
if (visibleBlockCount > this.#lastVisibleBlockCount) {
|
|
481
487
|
this.#resetReadGroup();
|
|
@@ -491,14 +497,7 @@ export class EventController {
|
|
|
491
497
|
// stream (a big write/edit/eval) sits below a still-live block and
|
|
492
498
|
// can never reach native scrollback: the head of the preview is
|
|
493
499
|
// neither committed nor on screen and the transcript reads as cut.
|
|
494
|
-
|
|
495
|
-
// known at message_end and appends to this block, which would shift
|
|
496
|
-
// committed tool rows below it every turn (audit recommit →
|
|
497
|
-
// duplicated preview copies in scrollback).
|
|
498
|
-
if (
|
|
499
|
-
this.ctx.streamingMessage.content.some(content => content.type === "toolCall") &&
|
|
500
|
-
!settings.get("display.showTokenUsage")
|
|
501
|
-
) {
|
|
500
|
+
if (this.ctx.streamingMessage.content.some(content => content.type === "toolCall")) {
|
|
502
501
|
this.ctx.streamingComponent.markTranscriptBlockFinalized();
|
|
503
502
|
}
|
|
504
503
|
for (const content of this.ctx.streamingMessage.content) {
|
|
@@ -603,6 +602,17 @@ export class EventController {
|
|
|
603
602
|
|
|
604
603
|
async #handleMessageEnd(event: Extract<AgentSessionEvent, { type: "message_end" }>): Promise<void> {
|
|
605
604
|
if (event.message.role === "user") return;
|
|
605
|
+
if (event.message.role === "assistant" && settings.get("speech.enabled")) {
|
|
606
|
+
if (event.message.stopReason === "aborted") {
|
|
607
|
+
// Esc / Ctrl+C / interrupt: stop speaking now and drop the trailing partial.
|
|
608
|
+
vocalizer.clear();
|
|
609
|
+
} else {
|
|
610
|
+
const mode = settings.get("speech.mode");
|
|
611
|
+
// Speak the last partial sentence of a completed message; yield mode
|
|
612
|
+
// instead speaks the whole final message at turn end.
|
|
613
|
+
if (mode === "assistant" || mode === "all") vocalizer.flush();
|
|
614
|
+
}
|
|
615
|
+
}
|
|
606
616
|
if (this.ctx.streamingComponent && event.message.role === "assistant") {
|
|
607
617
|
this.ctx.streamingMessage = event.message;
|
|
608
618
|
this.#streamingReveal.stop();
|
|
@@ -651,8 +661,10 @@ export class EventController {
|
|
|
651
661
|
this.#resolveDisplaceablePoll();
|
|
652
662
|
}
|
|
653
663
|
this.#lastAssistantComponent = this.ctx.streamingComponent;
|
|
654
|
-
this.#lastAssistantComponent.setUsageInfo(event.message.usage);
|
|
655
664
|
this.#lastAssistantComponent.markTranscriptBlockFinalized();
|
|
665
|
+
if (settings.get("display.showTokenUsage")) {
|
|
666
|
+
this.ctx.chatContainer.addChild(createUsageRowBlock(event.message.usage));
|
|
667
|
+
}
|
|
656
668
|
this.ctx.streamingComponent = undefined;
|
|
657
669
|
this.ctx.streamingMessage = undefined;
|
|
658
670
|
// Pin a turn-ending provider error (e.g. Anthropic content-filter block)
|
|
@@ -823,7 +835,21 @@ export class EventController {
|
|
|
823
835
|
}
|
|
824
836
|
}
|
|
825
837
|
async #handleAgentEnd(_event: Extract<AgentSessionEvent, { type: "agent_end" }>): Promise<void> {
|
|
826
|
-
|
|
838
|
+
// A superseded agent_end: the agent is already streaming a fresh turn, so
|
|
839
|
+
// this event belongs to a turn that has already been replaced. The session
|
|
840
|
+
// dispatches to listeners fire-and-forget across an async extension-emit hop
|
|
841
|
+
// (#emitSessionEvent), so an interrupted turn's agent_end can land AFTER the
|
|
842
|
+
// resumed turn's agent_start (e.g. any post-turn agent.continue()). Running
|
|
843
|
+
// the turn-end teardown now would stop the loader the live turn just created,
|
|
844
|
+
// leaving "Working…" gone while the agent keeps running. The live turn owns
|
|
845
|
+
// the loader and finalizes it at its own agent_end (isStreaming === false by
|
|
846
|
+
// then). Mirrors the collab guest's !isStreaming loader reconciler.
|
|
847
|
+
if (this.ctx.session.isStreaming) return;
|
|
848
|
+
|
|
849
|
+
await this.#finishAgentEnd();
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
async #finishAgentEnd(): Promise<void> {
|
|
827
853
|
this.#streamingReveal.stop();
|
|
828
854
|
this.#toolArgsReveal.flushAll();
|
|
829
855
|
if (this.ctx.loadingAnimation) {
|
|
@@ -867,14 +893,27 @@ export class EventController {
|
|
|
867
893
|
this.sendCompletionNotification();
|
|
868
894
|
}
|
|
869
895
|
|
|
896
|
+
/**
|
|
897
|
+
* Tear down the live "Working…" loader: stop its animation timer AND clear the
|
|
898
|
+
* reference. A transient overlay (auto-compaction / auto-retry) that only ran
|
|
899
|
+
* `statusContainer.clear()` detached the loader from the container but left
|
|
900
|
+
* `ctx.loadingAnimation` set, so the resumed turn's `agent_start` →
|
|
901
|
+
* `ensureLoadingAnimation()` (guarded by `if (!this.loadingAnimation)`) skipped
|
|
902
|
+
* re-adding it and the spinner vanished while the agent kept streaming. Nulling
|
|
903
|
+
* the reference here lets the next `agent_start` recreate and re-attach it.
|
|
904
|
+
*/
|
|
905
|
+
#stopWorkingLoader(): void {
|
|
906
|
+
if (this.ctx.loadingAnimation) {
|
|
907
|
+
this.ctx.loadingAnimation.stop();
|
|
908
|
+
this.ctx.loadingAnimation = undefined;
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
|
|
870
912
|
async #handleAutoCompactionStart(
|
|
871
913
|
event: Extract<AgentSessionEvent, { type: "auto_compaction_start" }>,
|
|
872
914
|
): Promise<void> {
|
|
873
915
|
this.#cancelIdleCompaction();
|
|
874
|
-
this
|
|
875
|
-
this.ctx.editor.onEscape = () => {
|
|
876
|
-
this.ctx.viewSession.abortCompaction();
|
|
877
|
-
};
|
|
916
|
+
this.#stopWorkingLoader();
|
|
878
917
|
this.ctx.statusContainer.clear();
|
|
879
918
|
const reasonText =
|
|
880
919
|
event.reason === "overflow"
|
|
@@ -903,10 +942,6 @@ export class EventController {
|
|
|
903
942
|
|
|
904
943
|
async #handleAutoCompactionEnd(event: Extract<AgentSessionEvent, { type: "auto_compaction_end" }>): Promise<void> {
|
|
905
944
|
this.#cancelIdleCompaction();
|
|
906
|
-
if (this.ctx.autoCompactionEscapeHandler) {
|
|
907
|
-
this.ctx.editor.onEscape = this.ctx.autoCompactionEscapeHandler;
|
|
908
|
-
this.ctx.autoCompactionEscapeHandler = undefined;
|
|
909
|
-
}
|
|
910
945
|
if (this.ctx.autoCompactionLoader) {
|
|
911
946
|
this.ctx.autoCompactionLoader.stop();
|
|
912
947
|
this.ctx.autoCompactionLoader = undefined;
|
|
@@ -964,10 +999,7 @@ export class EventController {
|
|
|
964
999
|
}
|
|
965
1000
|
|
|
966
1001
|
async #handleAutoRetryStart(event: Extract<AgentSessionEvent, { type: "auto_retry_start" }>): Promise<void> {
|
|
967
|
-
this
|
|
968
|
-
this.ctx.editor.onEscape = () => {
|
|
969
|
-
this.ctx.viewSession.abortRetry();
|
|
970
|
-
};
|
|
1002
|
+
this.#stopWorkingLoader();
|
|
971
1003
|
this.ctx.statusContainer.clear();
|
|
972
1004
|
const delaySeconds = Math.round(event.delayMs / 1000);
|
|
973
1005
|
this.ctx.retryLoader = new Loader(
|
|
@@ -982,10 +1014,6 @@ export class EventController {
|
|
|
982
1014
|
}
|
|
983
1015
|
|
|
984
1016
|
async #handleAutoRetryEnd(event: Extract<AgentSessionEvent, { type: "auto_retry_end" }>): Promise<void> {
|
|
985
|
-
if (this.ctx.retryEscapeHandler) {
|
|
986
|
-
this.ctx.editor.onEscape = this.ctx.retryEscapeHandler;
|
|
987
|
-
this.ctx.retryEscapeHandler = undefined;
|
|
988
|
-
}
|
|
989
1017
|
if (this.ctx.retryLoader) {
|
|
990
1018
|
this.ctx.retryLoader.stop();
|
|
991
1019
|
this.ctx.retryLoader = undefined;
|
|
@@ -17,6 +17,7 @@ import type {
|
|
|
17
17
|
TerminalInputHandler,
|
|
18
18
|
} from "../../extensibility/extensions";
|
|
19
19
|
import { getSessionSlashCommands } from "../../extensibility/extensions/get-commands-handler";
|
|
20
|
+
import { createExtensionModelQuery } from "../../extensibility/extensions/model-api";
|
|
20
21
|
import { HookEditorComponent } from "../../modes/components/hook-editor";
|
|
21
22
|
import { HookInputComponent } from "../../modes/components/hook-input";
|
|
22
23
|
import { HookSelectorComponent, type HookSelectorSlider } from "../../modes/components/hook-selector";
|
|
@@ -491,6 +492,11 @@ export class ExtensionUiController {
|
|
|
491
492
|
sessionManager: this.ctx.session.sessionManager,
|
|
492
493
|
modelRegistry: this.ctx.session.modelRegistry,
|
|
493
494
|
model: this.ctx.session.model,
|
|
495
|
+
models: createExtensionModelQuery(
|
|
496
|
+
this.ctx.session.modelRegistry,
|
|
497
|
+
this.ctx.session.settings,
|
|
498
|
+
() => this.ctx.session.model,
|
|
499
|
+
),
|
|
494
500
|
isIdle: () => !this.ctx.session.isStreaming,
|
|
495
501
|
hasPendingMessages: () => this.ctx.session.queuedMessageCount > 0,
|
|
496
502
|
abort: () => {
|