@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
|
@@ -90,6 +90,13 @@ const CONDITIONS: Record<string, () => boolean> = {
|
|
|
90
90
|
return false;
|
|
91
91
|
}
|
|
92
92
|
},
|
|
93
|
+
autolearnActive: () => {
|
|
94
|
+
try {
|
|
95
|
+
return Settings.instance.get("autolearn.enabled") === true;
|
|
96
|
+
} catch {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
},
|
|
93
100
|
autoThinkingActive: () => {
|
|
94
101
|
try {
|
|
95
102
|
return Settings.instance.get("defaultThinkingLevel") === "auto";
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
|
4
|
-
import { estimateTokens } from "@oh-my-pi/pi-agent-core/compaction";
|
|
5
4
|
import { type Component, truncateToWidth, visibleWidth } from "@oh-my-pi/pi-tui";
|
|
6
5
|
import { getProjectDir } from "@oh-my-pi/pi-utils";
|
|
7
6
|
import { $ } from "bun";
|
|
@@ -11,7 +10,6 @@ import * as git from "../../../utils/git";
|
|
|
11
10
|
import { getSessionAccentAnsi, getSessionAccentHex } from "../../../utils/session-color";
|
|
12
11
|
import { sanitizeStatusText } from "../../shared";
|
|
13
12
|
import { theme } from "../../theme/theme";
|
|
14
|
-
import { computeNonMessageTokens } from "../../utils/context-usage";
|
|
15
13
|
import { canReuseCachedPr, createPrCacheContext, isSamePrCacheContext, type PrCacheContext } from "./git-utils";
|
|
16
14
|
import { getPreset } from "./presets";
|
|
17
15
|
import { renderSegment, type SegmentContext } from "./segments";
|
|
@@ -26,30 +24,15 @@ import type {
|
|
|
26
24
|
} from "./types";
|
|
27
25
|
|
|
28
26
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
29
|
-
//
|
|
27
|
+
// Context-usage memo
|
|
30
28
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
31
29
|
|
|
32
30
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* Cache lives on the message — multiple `StatusLineComponent` instances
|
|
39
|
-
* share it for free, and entries collect with the message itself when the
|
|
40
|
-
* conversation is replaced or compacted.
|
|
41
|
-
*/
|
|
42
|
-
const kTokenCache = Symbol("statusLine.tokenCache");
|
|
43
|
-
interface TaggedMessage {
|
|
44
|
-
[kTokenCache]?: { fingerprint: string; tokens: number };
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Cheap structural fingerprint mirroring `estimateTokens`'s content walk.
|
|
49
|
-
* O(blocks) — only reads string `.length` and primitives, never copies or
|
|
50
|
-
* serializes content. Any in-place mutation that alters total tokenized
|
|
51
|
-
* content also alters one of the byte-length sums or block counts captured
|
|
52
|
-
* here, forcing the cached `estimateTokens` value to be recomputed.
|
|
31
|
+
* Cheap structural fingerprint of a message's tokenizable content. O(blocks) —
|
|
32
|
+
* only reads string `.length` and primitives, never copies or serializes.
|
|
33
|
+
* Detects in-place growth of the streaming tail (and other in-place mutations)
|
|
34
|
+
* so the cached `getContextUsage()` result is recomputed when — and only when —
|
|
35
|
+
* the numbers it depends on change.
|
|
53
36
|
*/
|
|
54
37
|
function messageFingerprint(msg: AgentMessage): string {
|
|
55
38
|
const role = (msg as { role?: string }).role ?? "";
|
|
@@ -107,29 +90,17 @@ function messageFingerprint(msg: AgentMessage): string {
|
|
|
107
90
|
return `${role}:${ts}:${textLen}:${blocks}:${images}`;
|
|
108
91
|
}
|
|
109
92
|
|
|
110
|
-
|
|
111
|
-
* Token count for a single message, using the per-message sidecar cache.
|
|
112
|
-
* The caller MUST skip caching for the last message during streaming —
|
|
113
|
-
* it may still be growing and its tokens belong recomputed each refresh.
|
|
114
|
-
*/
|
|
115
|
-
function tokensForMessage(msg: AgentMessage): number {
|
|
116
|
-
const fp = messageFingerprint(msg);
|
|
117
|
-
const tagged = msg as TaggedMessage;
|
|
118
|
-
const cached = tagged[kTokenCache];
|
|
119
|
-
if (cached && cached.fingerprint === fp) return cached.tokens;
|
|
120
|
-
const tokens = estimateTokens(msg);
|
|
121
|
-
tagged[kTokenCache] = { fingerprint: fp, tokens };
|
|
122
|
-
return tokens;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
interface MessageTokenTotalsCache {
|
|
93
|
+
interface ContextUsageMemo {
|
|
126
94
|
messagesRef: readonly AgentMessage[];
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
95
|
+
length: number;
|
|
96
|
+
lastFingerprint: string | undefined;
|
|
97
|
+
modelContextWindow: number;
|
|
98
|
+
usedTokens: number | null;
|
|
99
|
+
contextWindow: number;
|
|
131
100
|
}
|
|
132
101
|
|
|
102
|
+
const EMPTY_MESSAGES: readonly AgentMessage[] = [];
|
|
103
|
+
|
|
133
104
|
function hasContextSegment(segments: readonly StatusLineSegmentId[]): boolean {
|
|
134
105
|
return segments.includes("context_pct") || segments.includes("context_total");
|
|
135
106
|
}
|
|
@@ -176,19 +147,12 @@ export class StatusLineComponent implements Component {
|
|
|
176
147
|
} | null = null;
|
|
177
148
|
#usageFetchedAt = 0;
|
|
178
149
|
#usageInFlight = false;
|
|
179
|
-
// Context
|
|
180
|
-
//
|
|
181
|
-
//
|
|
182
|
-
//
|
|
183
|
-
//
|
|
184
|
-
|
|
185
|
-
// promotion, matching the normal append-only session flow.
|
|
186
|
-
// Cached non-message total (system prompt + tools + skills). Invalidated
|
|
187
|
-
// when the inputs-identity fingerprint changes (model swap, skill toggle,
|
|
188
|
-
// tool registration).
|
|
189
|
-
#nonMessageTokensCache: number | undefined;
|
|
190
|
-
#nonMessageInputsKey: string | undefined;
|
|
191
|
-
#messageTokenTotalsCache: MessageTokenTotalsCache | undefined;
|
|
150
|
+
// Context-usage memo. The status line redraws on every agent event, so the
|
|
151
|
+
// hot path must not recompute context tokens unless an input changed.
|
|
152
|
+
// `getContextUsage()` anchors on the last assistant's real prompt-token
|
|
153
|
+
// count (matching the provider and the `/context` panel), so a stable
|
|
154
|
+
// message list + model window yields a stable result we can return verbatim.
|
|
155
|
+
#contextUsageCache: ContextUsageMemo | undefined;
|
|
192
156
|
|
|
193
157
|
constructor(private session: AgentSession) {
|
|
194
158
|
this.#settings = {
|
|
@@ -310,9 +274,7 @@ export class StatusLineComponent implements Component {
|
|
|
310
274
|
this.#cachedUsage = null;
|
|
311
275
|
this.#usageFetchedAt = 0;
|
|
312
276
|
this.#usageInFlight = false;
|
|
313
|
-
this.#
|
|
314
|
-
this.#nonMessageInputsKey = undefined;
|
|
315
|
-
this.#messageTokenTotalsCache = undefined;
|
|
277
|
+
this.#contextUsageCache = undefined;
|
|
316
278
|
this.#lastTokensPerSecond = null;
|
|
317
279
|
this.#lastTokensPerSecondTimestamp = null;
|
|
318
280
|
}
|
|
@@ -544,109 +506,44 @@ export class StatusLineComponent implements Component {
|
|
|
544
506
|
}
|
|
545
507
|
|
|
546
508
|
/**
|
|
547
|
-
*
|
|
548
|
-
*
|
|
549
|
-
*
|
|
550
|
-
*
|
|
509
|
+
* Used-tokens / context-window totals for the status-line context% segment,
|
|
510
|
+
* memoized so the per-event redraw stays O(1) when nothing changed.
|
|
511
|
+
*
|
|
512
|
+
* The numerator comes from `session.getContextUsage()`, which anchors on the
|
|
513
|
+
* last assistant's real prompt-token count — so the bar matches the provider
|
|
514
|
+
* and the `/context` panel — and reports `null` while that count is unknown
|
|
515
|
+
* (right after compaction, before the next response). Exposed (non-private)
|
|
516
|
+
* for unit tests and the collab host's state broadcast.
|
|
551
517
|
*/
|
|
552
|
-
getCachedContextBreakdown(): { usedTokens: number; contextWindow: number } {
|
|
553
|
-
const messages = this.session.messages ??
|
|
554
|
-
const
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
// when the inputs identity fingerprint changes — usually never
|
|
558
|
-
// during a streaming turn. ~10-30 ms when it does refresh.
|
|
559
|
-
const inputsKey = this.#computeNonMessageInputsKey();
|
|
560
|
-
if (this.#nonMessageTokensCache === undefined || this.#nonMessageInputsKey !== inputsKey) {
|
|
561
|
-
this.#nonMessageTokensCache = computeNonMessageTokens(this.session);
|
|
562
|
-
this.#nonMessageInputsKey = inputsKey;
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
// 2) Message tokens — incremental rolling total. The sidecar cache lives
|
|
566
|
-
// on each stable message object (all but the current tail). Normal
|
|
567
|
-
// streaming turns only recompute the last message and newly appended
|
|
568
|
-
// entries. Full rebuild only when the message array is replaced,
|
|
569
|
-
// shrinks, or the recently-promoted stable tail mutates in place.
|
|
570
|
-
const messagesTokens = this.#getCachedMessageTokens(messages);
|
|
571
|
-
|
|
572
|
-
const usedTokens = this.#nonMessageTokensCache + messagesTokens;
|
|
573
|
-
return { usedTokens, contextWindow };
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
#getCachedMessageTokens(messages: readonly AgentMessage[]): number {
|
|
577
|
-
const cache = this.#messageTokenTotalsCache;
|
|
578
|
-
if (!cache || cache.messagesRef !== messages || messages.length <= cache.stableCount) {
|
|
579
|
-
return this.#rebuildMessageTokenTotals(messages);
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
let stableTokens = cache.stableTokens;
|
|
583
|
-
let stableCount = cache.stableCount;
|
|
584
|
-
const stableLimit = Math.max(0, messages.length - 1);
|
|
518
|
+
getCachedContextBreakdown(): { usedTokens: number | null; contextWindow: number } {
|
|
519
|
+
const messages = this.session.messages ?? EMPTY_MESSAGES;
|
|
520
|
+
const modelContextWindow = this.session.model?.contextWindow ?? 0;
|
|
521
|
+
const length = messages.length;
|
|
522
|
+
const lastFingerprint = length > 0 ? messageFingerprint(messages[length - 1]!) : undefined;
|
|
585
523
|
|
|
524
|
+
const cache = this.#contextUsageCache;
|
|
586
525
|
if (
|
|
587
|
-
cache
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
cache.
|
|
591
|
-
cache.
|
|
526
|
+
cache &&
|
|
527
|
+
cache.messagesRef === messages &&
|
|
528
|
+
cache.length === length &&
|
|
529
|
+
cache.lastFingerprint === lastFingerprint &&
|
|
530
|
+
cache.modelContextWindow === modelContextWindow
|
|
592
531
|
) {
|
|
593
|
-
return
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
while (stableCount < stableLimit) {
|
|
597
|
-
const promoted = messages[stableCount]!;
|
|
598
|
-
stableTokens += tokensForMessage(promoted);
|
|
599
|
-
stableCount++;
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
const lastStableMessage = stableCount > 0 ? messages[stableCount - 1] : undefined;
|
|
603
|
-
const lastStableFingerprint = lastStableMessage ? messageFingerprint(lastStableMessage) : undefined;
|
|
604
|
-
const lastMessage = messages.at(-1);
|
|
605
|
-
const lastTokens = lastMessage ? estimateTokens(lastMessage) : 0;
|
|
606
|
-
this.#messageTokenTotalsCache = {
|
|
607
|
-
messagesRef: messages,
|
|
608
|
-
stableCount,
|
|
609
|
-
stableTokens,
|
|
610
|
-
lastStableMessage,
|
|
611
|
-
lastStableFingerprint,
|
|
612
|
-
};
|
|
613
|
-
return stableTokens + lastTokens;
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
#rebuildMessageTokenTotals(messages: readonly AgentMessage[]): number {
|
|
617
|
-
let stableTokens = 0;
|
|
618
|
-
const stableLimit = Math.max(0, messages.length - 1);
|
|
619
|
-
for (let i = 0; i < stableLimit; i++) {
|
|
620
|
-
stableTokens += tokensForMessage(messages[i]!);
|
|
532
|
+
return { usedTokens: cache.usedTokens, contextWindow: cache.contextWindow };
|
|
621
533
|
}
|
|
622
534
|
|
|
623
|
-
const
|
|
624
|
-
const
|
|
625
|
-
const
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
this.#messageTokenTotalsCache = {
|
|
535
|
+
const usage = this.session.getContextUsage();
|
|
536
|
+
const usedTokens = usage?.tokens ?? null;
|
|
537
|
+
const contextWindow = usage?.contextWindow ?? modelContextWindow;
|
|
538
|
+
this.#contextUsageCache = {
|
|
629
539
|
messagesRef: messages,
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
540
|
+
length,
|
|
541
|
+
lastFingerprint,
|
|
542
|
+
modelContextWindow,
|
|
543
|
+
usedTokens,
|
|
544
|
+
contextWindow,
|
|
634
545
|
};
|
|
635
|
-
return
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
/**
|
|
639
|
-
* Build an identity fingerprint for the non-message inputs (system prompt,
|
|
640
|
-
* tools, skills). When this changes, the non-message token cache must be
|
|
641
|
-
* recomputed. Cheap: just lengths + first-string-length. Doesn't need to
|
|
642
|
-
* be cryptographically unique — only stable for the same inputs.
|
|
643
|
-
*/
|
|
644
|
-
#computeNonMessageInputsKey(): string {
|
|
645
|
-
const sp = this.session.systemPrompt ?? [];
|
|
646
|
-
const tools = this.session.agent?.state?.tools ?? [];
|
|
647
|
-
const skills = this.session.skills ?? [];
|
|
648
|
-
const modelId = this.session.model?.id ?? "";
|
|
649
|
-
return `${modelId}|${sp.length}:${sp[0]?.length ?? 0}|${tools.length}|${skills.length}`;
|
|
546
|
+
return { usedTokens, contextWindow };
|
|
650
547
|
}
|
|
651
548
|
|
|
652
549
|
#buildSegmentContext(
|
|
@@ -673,14 +570,14 @@ export class StatusLineComponent implements Component {
|
|
|
673
570
|
tokensPerSecond: this.#getTokensPerSecond(),
|
|
674
571
|
};
|
|
675
572
|
|
|
676
|
-
let contextTokens = 0;
|
|
677
573
|
let contextWindow = state.model?.contextWindow ?? this.session.model?.contextWindow ?? 0;
|
|
574
|
+
let contextPercent: number | null = 0;
|
|
678
575
|
if (includeContext) {
|
|
679
576
|
const breakdown = this.getCachedContextBreakdown();
|
|
680
|
-
contextTokens = breakdown.usedTokens;
|
|
681
577
|
contextWindow = breakdown.contextWindow || contextWindow;
|
|
578
|
+
contextPercent =
|
|
579
|
+
breakdown.usedTokens === null ? null : contextWindow > 0 ? (breakdown.usedTokens / contextWindow) * 100 : 0;
|
|
682
580
|
}
|
|
683
|
-
let contextPercent = contextWindow > 0 ? (contextTokens / contextWindow) * 100 : 0;
|
|
684
581
|
|
|
685
582
|
// Collab guest: context comes from the host's state frames — the local
|
|
686
583
|
// replica does no accounting of its own.
|
|
@@ -364,7 +364,7 @@ const contextPctSegment: StatusLineSegment = {
|
|
|
364
364
|
const autoIcon = ctx.autoCompactEnabled && theme.icon.auto ? ` ${theme.icon.auto}` : "";
|
|
365
365
|
const text = `${formatContextUsage(pct, window)}${autoIcon}`;
|
|
366
366
|
|
|
367
|
-
const color = getContextUsageThemeColor(getContextUsageLevel(pct, window));
|
|
367
|
+
const color = getContextUsageThemeColor(getContextUsageLevel(pct ?? 0, window));
|
|
368
368
|
const content = withIcon(theme.icon.context, theme.fg(color, text));
|
|
369
369
|
|
|
370
370
|
return { content, visible: true };
|
|
@@ -71,7 +71,8 @@ export interface SegmentContext {
|
|
|
71
71
|
cost: number;
|
|
72
72
|
tokensPerSecond: number | null;
|
|
73
73
|
};
|
|
74
|
-
|
|
74
|
+
/** Context usage percent, or null when unknown (e.g. right after compaction). */
|
|
75
|
+
contextPercent: number | null;
|
|
75
76
|
contextWindow: number;
|
|
76
77
|
autoCompactEnabled: boolean;
|
|
77
78
|
subagentCount: number;
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
Image,
|
|
9
9
|
ImageProtocol,
|
|
10
10
|
imageFallback,
|
|
11
|
+
type NativeScrollbackLiveRegion,
|
|
11
12
|
Spacer,
|
|
12
13
|
TERMINAL,
|
|
13
14
|
Text,
|
|
@@ -16,7 +17,7 @@ import {
|
|
|
16
17
|
import { getProjectDir, logger, sanitizeText } from "@oh-my-pi/pi-utils";
|
|
17
18
|
import { EDIT_MODE_STRATEGIES, type EditMode, type PerFileDiffPreview } from "../../edit";
|
|
18
19
|
import type { Theme } from "../../modes/theme/theme";
|
|
19
|
-
import { theme } from "../../modes/theme/theme";
|
|
20
|
+
import { getThemeEpoch, theme } from "../../modes/theme/theme";
|
|
20
21
|
import { BASH_DEFAULT_PREVIEW_LINES } from "../../tools/bash";
|
|
21
22
|
import { EVAL_DEFAULT_PREVIEW_LINES } from "../../tools/eval";
|
|
22
23
|
import { isWaitingPollDetails } from "../../tools/job";
|
|
@@ -148,10 +149,16 @@ export interface ToolExecutionHandle {
|
|
|
148
149
|
/** Drive pending-tool redraws at 30fps for live tool headers and displaceable
|
|
149
150
|
* poll blocks. The TUI throttles at the same cadence, and static frames diff to
|
|
150
151
|
* a no-op redraw at ~zero cost. */
|
|
151
|
-
const SPINNER_RENDER_INTERVAL_MS = 1000 / 30;
|
|
152
|
+
export const SPINNER_RENDER_INTERVAL_MS = 1000 / 30;
|
|
152
153
|
/** Advance the spinner glyph at its classic ~12.5fps step, decoupled from the
|
|
153
154
|
* render cadence (mirrors `Loader`). */
|
|
154
|
-
const SPINNER_GLYPH_ADVANCE_MS = 80;
|
|
155
|
+
export const SPINNER_GLYPH_ADVANCE_MS = 80;
|
|
156
|
+
|
|
157
|
+
/** Phase-locked spinner glyph index shared by every live tool block so parallel
|
|
158
|
+
* spinners advance in lockstep instead of each tracking its own start time. */
|
|
159
|
+
export function sharedSpinnerFrame(frameCount: number, now: number = performance.now()): number {
|
|
160
|
+
return frameCount > 0 ? Math.floor(now / SPINNER_GLYPH_ADVANCE_MS) % frameCount : 0;
|
|
161
|
+
}
|
|
155
162
|
|
|
156
163
|
// Stable per-instance counter so each tool execution's inline images get a
|
|
157
164
|
// graphics id that survives child re-creation (the image budget keys off it).
|
|
@@ -160,7 +167,7 @@ let toolExecutionInstanceSeq = 0;
|
|
|
160
167
|
/**
|
|
161
168
|
* Component that renders a tool call with its result (updateable)
|
|
162
169
|
*/
|
|
163
|
-
export class ToolExecutionComponent extends Container {
|
|
170
|
+
export class ToolExecutionComponent extends Container implements NativeScrollbackLiveRegion {
|
|
164
171
|
#contentBox: Box; // Used for custom tools and bash visual truncation
|
|
165
172
|
#contentText: Text; // For built-in tools (with its own padding/bg)
|
|
166
173
|
#multiFileBoxes: (Box | Spacer)[] = []; // Extra boxes for multi-file edit results
|
|
@@ -176,6 +183,22 @@ export class ToolExecutionComponent extends Container {
|
|
|
176
183
|
#editAllowFuzzy: boolean | undefined;
|
|
177
184
|
#snapshots?: SnapshotStore;
|
|
178
185
|
#isPartial = true;
|
|
186
|
+
#resultVersion = 0;
|
|
187
|
+
#lastDisplayKey: string | undefined;
|
|
188
|
+
// Bumped whenever a render input that #rebuildDisplay consumes but the memo
|
|
189
|
+
// key cannot cheaply hash changes: streamed call args, the async edit-diff
|
|
190
|
+
// preview, and Kitty PNG conversions. Folded into the dirty key so those
|
|
191
|
+
// updates are not swallowed by the memo (see #updateDisplay).
|
|
192
|
+
#displayInputVersion = 0;
|
|
193
|
+
// Set once #rebuildDisplay has populated the display. Replaces a
|
|
194
|
+
// #contentBox.children.length probe so the memo fast-path also covers the
|
|
195
|
+
// #contentText fallback path (which leaves #contentBox empty).
|
|
196
|
+
#displayBuilt = false;
|
|
197
|
+
// Number of Image children the last rebuild emitted. Only when this is > 0 does
|
|
198
|
+
// the memo key fold in viewport-dependent image sizing (resolveImageOptions),
|
|
199
|
+
// so a terminal resize re-shapes image-bearing results to rescale them without
|
|
200
|
+
// forcing the common image-free result to re-shape on every resize tick.
|
|
201
|
+
#renderedImageCount = 0;
|
|
179
202
|
#tool?: AgentTool;
|
|
180
203
|
#ui: TUI;
|
|
181
204
|
#cwd: string;
|
|
@@ -196,7 +219,6 @@ export class ToolExecutionComponent extends Container {
|
|
|
196
219
|
// Spinner animation for partial task results
|
|
197
220
|
#spinnerFrame?: number;
|
|
198
221
|
#spinnerInterval?: NodeJS.Timeout;
|
|
199
|
-
#lastSpinnerAdvanceAt = 0;
|
|
200
222
|
// Todo write completion strikethrough reveal animation
|
|
201
223
|
#todoStrikeInterval?: NodeJS.Timeout;
|
|
202
224
|
// Track if args are still being streamed (for edit/write spinner)
|
|
@@ -281,6 +303,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
281
303
|
// signals "nothing meaningful changed" and the renderer can skip.
|
|
282
304
|
if (args === this.#args) return;
|
|
283
305
|
this.#args = args;
|
|
306
|
+
this.#displayInputVersion++;
|
|
284
307
|
this.#updateSpinnerAnimation();
|
|
285
308
|
this.#editDiffInFlight = this.#runPreviewDiff();
|
|
286
309
|
this.#updateDisplay();
|
|
@@ -365,6 +388,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
365
388
|
if (controller.signal.aborted) return;
|
|
366
389
|
if (previews) {
|
|
367
390
|
this.#editDiffPreview = isStreaming ? stabilizeStreamingPreviews(previews) : previews;
|
|
391
|
+
this.#displayInputVersion++;
|
|
368
392
|
this.#updateDisplay();
|
|
369
393
|
this.#ui.requestRender();
|
|
370
394
|
}
|
|
@@ -393,6 +417,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
393
417
|
return;
|
|
394
418
|
}
|
|
395
419
|
this.#result = result;
|
|
420
|
+
this.#resultVersion++;
|
|
396
421
|
this.#isPartial = isPartial;
|
|
397
422
|
// A `job` poll that found every watched job still running is transient
|
|
398
423
|
// "still waiting" chrome; keep the block displaceable so the next `job`
|
|
@@ -446,6 +471,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
446
471
|
.toBase64()
|
|
447
472
|
.then(data => {
|
|
448
473
|
this.#convertedImages.set(index, { data, mimeType: "image/png" });
|
|
474
|
+
this.#displayInputVersion++;
|
|
449
475
|
this.#updateDisplay();
|
|
450
476
|
this.#ui.requestRender();
|
|
451
477
|
})
|
|
@@ -470,32 +496,18 @@ export class ToolExecutionComponent extends Container {
|
|
|
470
496
|
// once the block leaves the live region.
|
|
471
497
|
const needsSpinner = isStreamingArgs || isPartialTask || this.isDisplaceableBlock();
|
|
472
498
|
if (needsSpinner && !this.#spinnerInterval) {
|
|
473
|
-
const now = performance.now();
|
|
474
499
|
const frameCount = theme.spinnerFrames.length;
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
this.#renderState.spinnerFrame = 0;
|
|
479
|
-
}
|
|
500
|
+
const frame = sharedSpinnerFrame(frameCount);
|
|
501
|
+
this.#spinnerFrame = frame;
|
|
502
|
+
this.#renderState.spinnerFrame = frame;
|
|
480
503
|
this.#spinnerInterval = setInterval(() => {
|
|
481
504
|
// If a detached task interval from an older render path is still live,
|
|
482
505
|
// stop it the instant the block leaves the repaintable region.
|
|
483
506
|
if (this.#maybeFreezeBackgroundTask()) return;
|
|
484
507
|
const now = performance.now();
|
|
485
508
|
const frameCount = theme.spinnerFrames.length;
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
// instead of resetting to `now` avoids the 30fps timer quantizing the
|
|
489
|
-
// glyph down to one step every three ticks.
|
|
490
|
-
if (frameCount > 0) {
|
|
491
|
-
const elapsed = now - this.#lastSpinnerAdvanceAt;
|
|
492
|
-
if (elapsed >= SPINNER_GLYPH_ADVANCE_MS) {
|
|
493
|
-
const steps = Math.floor(elapsed / SPINNER_GLYPH_ADVANCE_MS);
|
|
494
|
-
this.#spinnerFrame = ((this.#spinnerFrame ?? 0) + steps) % frameCount;
|
|
495
|
-
this.#renderState.spinnerFrame = this.#spinnerFrame;
|
|
496
|
-
this.#lastSpinnerAdvanceAt += steps * SPINNER_GLYPH_ADVANCE_MS;
|
|
497
|
-
}
|
|
498
|
-
}
|
|
509
|
+
this.#spinnerFrame = sharedSpinnerFrame(frameCount, now);
|
|
510
|
+
this.#renderState.spinnerFrame = this.#spinnerFrame;
|
|
499
511
|
this.#ui.requestRender();
|
|
500
512
|
}, SPINNER_RENDER_INTERVAL_MS);
|
|
501
513
|
} else if (!needsSpinner && this.#spinnerInterval) {
|
|
@@ -568,6 +580,17 @@ export class ToolExecutionComponent extends Container {
|
|
|
568
580
|
}
|
|
569
581
|
}
|
|
570
582
|
|
|
583
|
+
/**
|
|
584
|
+
* Standalone harnesses may mount a tool component directly under `TUI`
|
|
585
|
+
* instead of inside `TranscriptContainer`. In that shape the component must
|
|
586
|
+
* report its own live-region seam for provisional previews, or the core
|
|
587
|
+
* renderer treats it like shell output and commits tail-window edit/eval/bash
|
|
588
|
+
* previews to immutable native scrollback before the result replaces them.
|
|
589
|
+
*/
|
|
590
|
+
getNativeScrollbackLiveRegionStart(): number | undefined {
|
|
591
|
+
return !this.isTranscriptBlockFinalized() && !this.isTranscriptBlockCommitStable() ? 0 : undefined;
|
|
592
|
+
}
|
|
593
|
+
|
|
571
594
|
/**
|
|
572
595
|
* Whether this block has reached a terminal state for transcript freezing.
|
|
573
596
|
* Reports `false` while it can still visually change so the
|
|
@@ -591,28 +614,20 @@ export class ToolExecutionComponent extends Container {
|
|
|
591
614
|
|
|
592
615
|
/**
|
|
593
616
|
* Whether this still-live block's settled rows may enter native scrollback
|
|
594
|
-
* (see `FinalizableBlock.isTranscriptBlockCommitStable`).
|
|
595
|
-
*
|
|
596
|
-
*
|
|
597
|
-
*
|
|
598
|
-
*
|
|
599
|
-
*
|
|
600
|
-
* the call box above the final block the moment the result lands. Every
|
|
601
|
-
* other pending preview streams top-anchored append-shaped rows the
|
|
602
|
-
* result render preserves (a task call's context/assignment markdown, a
|
|
603
|
-
* write's content), so it stays commit-eligible — a call taller than the
|
|
604
|
-
* viewport scrolls into native history mid-stream instead of reading as
|
|
605
|
-
* cut off until the result. Expanded blocks always stream top-anchored
|
|
606
|
-
* (the over-tall write/eval scrollback contract). Displaceable waiting
|
|
607
|
-
* polls are removed wholesale by the next poll and must never commit.
|
|
617
|
+
* (see `FinalizableBlock.isTranscriptBlockCommitStable`). Renderers classify
|
|
618
|
+
* pending views by durability instead of by tool name: a provisional view is
|
|
619
|
+
* allowed to be useful on screen, but finalization may replace or re-anchor
|
|
620
|
+
* it wholesale, so committing any of its rows would strand stale preview
|
|
621
|
+
* bytes in immutable scrollback. Non-provisional views stream rows whose
|
|
622
|
+
* committed prefix survives the remaining transitions.
|
|
608
623
|
*/
|
|
609
624
|
isTranscriptBlockCommitStable(): boolean {
|
|
610
625
|
if (this.#displaceable) return false;
|
|
611
|
-
if (this
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
return
|
|
626
|
+
if (this.isTranscriptBlockFinalized()) return true;
|
|
627
|
+
const tool = this.#tool as { provisionalPendingPreview?: boolean | "collapsed" } | undefined;
|
|
628
|
+
const provisionalPendingPreview =
|
|
629
|
+
tool?.provisionalPendingPreview ?? toolRenderers[this.#toolName]?.provisionalPendingPreview;
|
|
630
|
+
return provisionalPendingPreview !== true && (provisionalPendingPreview !== "collapsed" || this.#expanded);
|
|
616
631
|
}
|
|
617
632
|
|
|
618
633
|
/**
|
|
@@ -674,6 +689,29 @@ export class ToolExecutionComponent extends Container {
|
|
|
674
689
|
}
|
|
675
690
|
|
|
676
691
|
#updateDisplay(): void {
|
|
692
|
+
// `TERMINAL.imageProtocol` is resolved by an async capability probe during
|
|
693
|
+
// TUI startup, so a result rendered before it lands must re-shape once it
|
|
694
|
+
// does (it gates Image children vs text fallback in #rebuildDisplay); keyed
|
|
695
|
+
// here for the same reason markdown.ts keys its render cache on it.
|
|
696
|
+
const key = `${this.#resultVersion}|${this.#expanded}|${this.#isPartial}|${this.#spinnerFrame ?? "-"}|${this.#showImages}|${getThemeEpoch()}|${this.#displayInputVersion}|${this.#backgroundTaskFrozen}|${TERMINAL.imageProtocol ?? "-"}|${this.#imageSizeKey()}`;
|
|
697
|
+
if (key === this.#lastDisplayKey && this.#displayBuilt) return;
|
|
698
|
+
this.#lastDisplayKey = key;
|
|
699
|
+
|
|
700
|
+
this.#rebuildDisplay();
|
|
701
|
+
this.#displayBuilt = true;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
// Viewport-/settings-dependent image sizing folded into the memo key only when
|
|
705
|
+
// the last rebuild actually emitted images, so a terminal resize re-shapes an
|
|
706
|
+
// image-bearing result (to rescale it) without re-shaping every image-free
|
|
707
|
+
// result on each resize tick.
|
|
708
|
+
#imageSizeKey(): string {
|
|
709
|
+
if (this.#renderedImageCount === 0) return "-";
|
|
710
|
+
const o = resolveImageOptions();
|
|
711
|
+
return `${o.maxWidthCells}:${o.maxHeightCells ?? "-"}`;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
#rebuildDisplay(): void {
|
|
677
715
|
// Sync shared mutable render state for component closures
|
|
678
716
|
this.#renderState.expanded = this.#expanded;
|
|
679
717
|
this.#renderState.isPartial = this.#isPartial;
|
|
@@ -917,6 +955,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
917
955
|
}
|
|
918
956
|
}
|
|
919
957
|
}
|
|
958
|
+
this.#renderedImageCount = this.#imageComponents.length;
|
|
920
959
|
}
|
|
921
960
|
|
|
922
961
|
#getCallArgsForRender(): any {
|