@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 * as path from "node:path";
|
|
|
4
4
|
import {
|
|
5
5
|
type AuthCredential,
|
|
6
6
|
type AuthCredentialStore,
|
|
7
|
+
isSqliteBusyError,
|
|
7
8
|
SqliteAuthCredentialStore,
|
|
8
9
|
type StoredAuthCredential,
|
|
9
10
|
} from "@oh-my-pi/pi-ai";
|
|
@@ -78,10 +79,14 @@ export class AgentStorage {
|
|
|
78
79
|
* AuthCredentialStore handles auth_credentials and cache tables.
|
|
79
80
|
*/
|
|
80
81
|
#initializeSchema(): void {
|
|
82
|
+
// Install the busy handler BEFORE any lock-taking statement (incl.
|
|
83
|
+
// `PRAGMA journal_mode=WAL`, which acquires an exclusive lock during WAL
|
|
84
|
+
// recovery). Without this, concurrent omp startups can crash here with
|
|
85
|
+
// `SQLITE_BUSY` / `SQLITE_BUSY_RECOVERY`. See issue #2421.
|
|
86
|
+
this.#db.run("PRAGMA busy_timeout = 5000");
|
|
81
87
|
this.#db.run(`
|
|
82
88
|
PRAGMA journal_mode=WAL;
|
|
83
89
|
PRAGMA synchronous=NORMAL;
|
|
84
|
-
PRAGMA busy_timeout=5000;
|
|
85
90
|
|
|
86
91
|
CREATE TABLE IF NOT EXISTS model_usage (
|
|
87
92
|
model_key TEXT PRIMARY KEY,
|
|
@@ -208,7 +213,8 @@ FROM model_usage_legacy
|
|
|
208
213
|
|
|
209
214
|
/**
|
|
210
215
|
* Returns singleton instance for the given database path, creating if needed.
|
|
211
|
-
* Retries on SQLITE_BUSY
|
|
216
|
+
* Retries on the `SQLITE_BUSY` family (including `SQLITE_BUSY_RECOVERY`) with
|
|
217
|
+
* exponential backoff. See issue #2421.
|
|
212
218
|
* @param dbPath - Path to the SQLite database file (defaults to config path)
|
|
213
219
|
* @returns AgentStorage instance for the given path
|
|
214
220
|
*/
|
|
@@ -216,7 +222,7 @@ FROM model_usage_legacy
|
|
|
216
222
|
const existing = instances.get(dbPath);
|
|
217
223
|
if (existing) return existing;
|
|
218
224
|
|
|
219
|
-
const maxRetries =
|
|
225
|
+
const maxRetries = 4;
|
|
220
226
|
const baseDelayMs = 100;
|
|
221
227
|
let lastError: Error | undefined;
|
|
222
228
|
|
|
@@ -226,17 +232,20 @@ FROM model_usage_legacy
|
|
|
226
232
|
instances.set(dbPath, storage);
|
|
227
233
|
return storage;
|
|
228
234
|
} catch (err) {
|
|
229
|
-
|
|
230
|
-
if (!isSqliteBusy) {
|
|
235
|
+
if (!isSqliteBusyError(err)) {
|
|
231
236
|
throw err;
|
|
232
237
|
}
|
|
233
|
-
lastError = err
|
|
234
|
-
|
|
235
|
-
|
|
238
|
+
lastError = err instanceof Error ? err : new Error(String(err));
|
|
239
|
+
if (attempt < maxRetries - 1) {
|
|
240
|
+
await Bun.sleep(baseDelayMs * 2 ** attempt);
|
|
241
|
+
}
|
|
236
242
|
}
|
|
237
243
|
}
|
|
238
244
|
|
|
239
|
-
throw
|
|
245
|
+
throw new Error(
|
|
246
|
+
`Failed to open agent database at '${dbPath}' after ${maxRetries} attempts: ${lastError?.message}`,
|
|
247
|
+
{ cause: lastError },
|
|
248
|
+
);
|
|
240
249
|
}
|
|
241
250
|
|
|
242
251
|
/**
|
|
@@ -84,12 +84,13 @@ export class HistoryStorage {
|
|
|
84
84
|
|
|
85
85
|
this.#db = new Database(dbPath);
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
// Install the busy handler BEFORE any lock-taking statement. See #2421.
|
|
88
|
+
this.#db.run("PRAGMA busy_timeout = 5000");
|
|
88
89
|
|
|
90
|
+
const hasFts = this.#db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='history_fts'").get();
|
|
89
91
|
this.#db.run(`
|
|
90
92
|
PRAGMA journal_mode=WAL;
|
|
91
93
|
PRAGMA synchronous=NORMAL;
|
|
92
|
-
PRAGMA busy_timeout=5000;
|
|
93
94
|
|
|
94
95
|
CREATE TABLE IF NOT EXISTS history (
|
|
95
96
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
@@ -173,6 +173,10 @@ export class IndexedSessionStorage implements SessionStorage {
|
|
|
173
173
|
}
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
+
writeTextAtomic(path: string, content: string): Promise<void> {
|
|
177
|
+
return this.writeText(path, content);
|
|
178
|
+
}
|
|
179
|
+
|
|
176
180
|
async rename(src: string, dst: string): Promise<void> {
|
|
177
181
|
await this.#awaitPath(src);
|
|
178
182
|
await this.#awaitPath(dst);
|
|
@@ -390,14 +394,7 @@ class IndexedSessionStorageWriter implements SessionStorageWriter {
|
|
|
390
394
|
return next;
|
|
391
395
|
}
|
|
392
396
|
|
|
393
|
-
|
|
394
|
-
if (this.#closed) throw new Error("Writer closed");
|
|
395
|
-
if (this.#error) throw this.#error;
|
|
396
|
-
const mtimeMs = this.#storage._appendForWriter(this.#path, line);
|
|
397
|
-
this.#trackPromise(this.#storage._queueAppend(this.#path, line, mtimeMs, () => this.#error));
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
async writeLine(line: string): Promise<void> {
|
|
397
|
+
async append(line: string): Promise<void> {
|
|
401
398
|
if (this.#closed) throw new Error("Writer closed");
|
|
402
399
|
if (this.#error) throw this.#error;
|
|
403
400
|
const mtimeMs = this.#storage._appendForWriter(this.#path, line);
|
|
@@ -410,8 +407,8 @@ class IndexedSessionStorageWriter implements SessionStorageWriter {
|
|
|
410
407
|
if (this.#error) throw this.#error;
|
|
411
408
|
}
|
|
412
409
|
|
|
413
|
-
|
|
414
|
-
|
|
410
|
+
isOpen(): boolean {
|
|
411
|
+
return !this.#closed;
|
|
415
412
|
}
|
|
416
413
|
|
|
417
414
|
async close(): Promise<void> {
|
package/src/session/messages.ts
CHANGED
|
@@ -40,13 +40,11 @@ export interface SkillPromptDetails {
|
|
|
40
40
|
path: string;
|
|
41
41
|
args?: string;
|
|
42
42
|
lineCount: number;
|
|
43
|
-
/** Internal:
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
|
|
48
|
-
* via the `INTERNAL_DETAILS_FIELDS` allowlist below. */
|
|
49
|
-
__pendingDisplayTag?: string;
|
|
43
|
+
/** Internal: compact label shown for a queued custom message. Optional —
|
|
44
|
+
* non-streaming skill prompts never set it. Stripped from persisted
|
|
45
|
+
* `details` by `SessionManager.appendCustomMessageEntry` via the
|
|
46
|
+
* `INTERNAL_DETAILS_FIELDS` allowlist below. */
|
|
47
|
+
__queueChipText?: string;
|
|
50
48
|
}
|
|
51
49
|
|
|
52
50
|
/** Sentinel value for `AssistantMessage.errorMessage` indicating that the abort
|
|
@@ -104,12 +102,12 @@ export function resolveAbortLabel(errorMessage: string | undefined, retryAttempt
|
|
|
104
102
|
return "Operation aborted";
|
|
105
103
|
}
|
|
106
104
|
|
|
107
|
-
/** Extract the optional `
|
|
105
|
+
/** Extract the optional `__queueChipText` field from a CustomMessage's
|
|
108
106
|
* `details` blob. Safe over `unknown`; returns undefined when the field is
|
|
109
107
|
* absent or non-string. */
|
|
110
|
-
export function
|
|
108
|
+
export function readQueueChipText(details: unknown): string | undefined {
|
|
111
109
|
if (typeof details !== "object" || details === null) return undefined;
|
|
112
|
-
const candidate = (details as {
|
|
110
|
+
const candidate = (details as { __queueChipText?: unknown }).__queueChipText;
|
|
113
111
|
return typeof candidate === "string" ? candidate : undefined;
|
|
114
112
|
}
|
|
115
113
|
|
|
@@ -118,7 +116,7 @@ export function readPendingDisplayTag(details: unknown): string | undefined {
|
|
|
118
116
|
* the CustomMessageEntry to disk. Scoped intentionally narrow: only fields
|
|
119
117
|
* declared here are stripped. Adding a new entry is a deliberate, reviewed
|
|
120
118
|
* change — unrelated future payload fields are never silently dropped. */
|
|
121
|
-
export const INTERNAL_DETAILS_FIELDS = ["
|
|
119
|
+
export const INTERNAL_DETAILS_FIELDS = ["__queueChipText"] as const;
|
|
122
120
|
|
|
123
121
|
/** Return a `details` copy with every key in `INTERNAL_DETAILS_FIELDS`
|
|
124
122
|
* removed. Returns the input unchanged when there is nothing to strip
|
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
|
2
|
+
import type { ProviderPayload, ServiceTier } from "@oh-my-pi/pi-ai";
|
|
3
|
+
import * as snapcompact from "@oh-my-pi/snapcompact";
|
|
4
|
+
import { createBranchSummaryMessage, createCompactionSummaryMessage, createCustomMessage } from "./messages";
|
|
5
|
+
import { type CompactionEntry, EPHEMERAL_MODEL_CHANGE_ROLE, type SessionEntry } from "./session-entries";
|
|
6
|
+
|
|
7
|
+
export interface SessionContext {
|
|
8
|
+
messages: AgentMessage[];
|
|
9
|
+
thinkingLevel?: string;
|
|
10
|
+
serviceTier?: ServiceTier;
|
|
11
|
+
/** Model roles: { default: "provider/modelId", small: "provider/modelId", ... } */
|
|
12
|
+
models: Record<string, string>;
|
|
13
|
+
/** Names of TTSR rules that have been injected this session */
|
|
14
|
+
injectedTtsrRules: string[];
|
|
15
|
+
/** MCP tool names selected through discovery for this session branch. */
|
|
16
|
+
selectedMCPToolNames: string[];
|
|
17
|
+
/** Whether this branch contains an explicit persisted MCP selection entry. */
|
|
18
|
+
hasPersistedMCPToolSelection: boolean;
|
|
19
|
+
/** Active mode (e.g. "plan") or "none" if no special mode is active */
|
|
20
|
+
mode: string;
|
|
21
|
+
/** Mode-specific data from the last mode_change entry */
|
|
22
|
+
modeData?: Record<string, unknown>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Lists session model strings to try when restoring, in fallback order. */
|
|
26
|
+
export function getRestorableSessionModels(
|
|
27
|
+
models: Readonly<Record<string, string>>,
|
|
28
|
+
lastModelChangeRole: string | undefined,
|
|
29
|
+
): string[] {
|
|
30
|
+
const defaultModel = models.default;
|
|
31
|
+
if (
|
|
32
|
+
!lastModelChangeRole ||
|
|
33
|
+
lastModelChangeRole === "default" ||
|
|
34
|
+
lastModelChangeRole === EPHEMERAL_MODEL_CHANGE_ROLE
|
|
35
|
+
) {
|
|
36
|
+
return defaultModel ? [defaultModel] : [];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const roleModel = models[lastModelChangeRole];
|
|
40
|
+
if (!roleModel) return defaultModel ? [defaultModel] : [];
|
|
41
|
+
if (!defaultModel || roleModel === defaultModel) return [roleModel];
|
|
42
|
+
return [roleModel, defaultModel];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function getLatestCompactionEntry(entries: SessionEntry[]): CompactionEntry | null {
|
|
46
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
47
|
+
if (entries[i].type === "compaction") {
|
|
48
|
+
return entries[i] as CompactionEntry;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface BuildSessionContextOptions {
|
|
55
|
+
/**
|
|
56
|
+
* Build the full-history display transcript instead of the LLM context:
|
|
57
|
+
* every path entry in chronological order, with each compaction emitted
|
|
58
|
+
* inline as a `compactionSummary` message at the position it fired rather
|
|
59
|
+
* than replacing the history before it. Display-only — never send the
|
|
60
|
+
* result to a provider.
|
|
61
|
+
*/
|
|
62
|
+
transcript?: boolean;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Build the session context from entries using tree traversal.
|
|
67
|
+
* If leafId is provided, walks from that entry to root.
|
|
68
|
+
* Handles compaction and branch summaries along the path.
|
|
69
|
+
*/
|
|
70
|
+
export function buildSessionContext(
|
|
71
|
+
entries: SessionEntry[],
|
|
72
|
+
leafId?: string | null,
|
|
73
|
+
byId?: Map<string, SessionEntry>,
|
|
74
|
+
options?: BuildSessionContextOptions,
|
|
75
|
+
): SessionContext {
|
|
76
|
+
// Build uuid index if not available
|
|
77
|
+
if (!byId) {
|
|
78
|
+
byId = new Map<string, SessionEntry>();
|
|
79
|
+
for (const entry of entries) {
|
|
80
|
+
byId.set(entry.id, entry);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Find leaf
|
|
85
|
+
let leaf: SessionEntry | undefined;
|
|
86
|
+
if (leafId === null) {
|
|
87
|
+
// Explicitly null - return no messages (navigated to before first entry)
|
|
88
|
+
return {
|
|
89
|
+
messages: [],
|
|
90
|
+
thinkingLevel: "off",
|
|
91
|
+
serviceTier: undefined,
|
|
92
|
+
models: {},
|
|
93
|
+
injectedTtsrRules: [],
|
|
94
|
+
selectedMCPToolNames: [],
|
|
95
|
+
hasPersistedMCPToolSelection: false,
|
|
96
|
+
mode: "none",
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
if (leafId) {
|
|
100
|
+
leaf = byId.get(leafId);
|
|
101
|
+
}
|
|
102
|
+
if (!leaf) {
|
|
103
|
+
// Fallback to last entry (when leafId is undefined)
|
|
104
|
+
leaf = entries[entries.length - 1];
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (!leaf) {
|
|
108
|
+
return {
|
|
109
|
+
messages: [],
|
|
110
|
+
thinkingLevel: "off",
|
|
111
|
+
serviceTier: undefined,
|
|
112
|
+
models: {},
|
|
113
|
+
injectedTtsrRules: [],
|
|
114
|
+
selectedMCPToolNames: [],
|
|
115
|
+
hasPersistedMCPToolSelection: false,
|
|
116
|
+
mode: "none",
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Walk from leaf to root, collecting path
|
|
121
|
+
const path: SessionEntry[] = [];
|
|
122
|
+
let current: SessionEntry | undefined = leaf;
|
|
123
|
+
while (current) {
|
|
124
|
+
path.unshift(current);
|
|
125
|
+
current = current.parentId ? byId.get(current.parentId) : undefined;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Extract settings and find compaction
|
|
129
|
+
let thinkingLevel: string | undefined = "off";
|
|
130
|
+
let serviceTier: ServiceTier | undefined;
|
|
131
|
+
const models: Record<string, string> = {};
|
|
132
|
+
let compaction: CompactionEntry | null = null;
|
|
133
|
+
const injectedTtsrRulesSet = new Set<string>();
|
|
134
|
+
let selectedMCPToolNames: string[] = [];
|
|
135
|
+
let hasPersistedMCPToolSelection = false;
|
|
136
|
+
let mode = "none";
|
|
137
|
+
let modeData: Record<string, unknown> | undefined;
|
|
138
|
+
// Track whether an explicit `model_change` with role="default" has been
|
|
139
|
+
// seen on this path. Once a user (or the agent itself) records an
|
|
140
|
+
// explicit default, later assistant-message inference must NOT overwrite
|
|
141
|
+
// it: temporary fallbacks (retry fallback, context promotion) and
|
|
142
|
+
// server-side model downgrades both produce assistant messages tagged
|
|
143
|
+
// with the wrong model id, which previously clobbered the user's pick on
|
|
144
|
+
// resume (issue #849).
|
|
145
|
+
let hasExplicitDefaultModel = false;
|
|
146
|
+
|
|
147
|
+
for (const entry of path) {
|
|
148
|
+
if (entry.type === "thinking_level_change") {
|
|
149
|
+
thinkingLevel = entry.thinkingLevel ?? "off";
|
|
150
|
+
} else if (entry.type === "model_change") {
|
|
151
|
+
// New format: { model: "provider/id", role?: string }
|
|
152
|
+
if (entry.model) {
|
|
153
|
+
const role = entry.role ?? "default";
|
|
154
|
+
models[role] = entry.model;
|
|
155
|
+
if (role === "default") {
|
|
156
|
+
hasExplicitDefaultModel = true;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
} else if (entry.type === "service_tier_change") {
|
|
160
|
+
serviceTier = entry.serviceTier ?? undefined;
|
|
161
|
+
} else if (entry.type === "message" && entry.message.role === "assistant") {
|
|
162
|
+
// Legacy fallback: infer default model from assistant messages only
|
|
163
|
+
// when no explicit `model_change` (role=default) entry has been
|
|
164
|
+
// recorded yet. Newer sessions always record an explicit default
|
|
165
|
+
// model_change at the start of the conversation, so this branch is
|
|
166
|
+
// only used to keep pre-model_change sessions working.
|
|
167
|
+
if (!hasExplicitDefaultModel) {
|
|
168
|
+
models.default = `${entry.message.provider}/${entry.message.model}`;
|
|
169
|
+
}
|
|
170
|
+
} else if (entry.type === "compaction") {
|
|
171
|
+
compaction = entry;
|
|
172
|
+
} else if (entry.type === "ttsr_injection") {
|
|
173
|
+
// Collect injected TTSR rule names
|
|
174
|
+
for (const ruleName of entry.injectedRules) {
|
|
175
|
+
injectedTtsrRulesSet.add(ruleName);
|
|
176
|
+
}
|
|
177
|
+
} else if (entry.type === "mcp_tool_selection") {
|
|
178
|
+
selectedMCPToolNames = [...entry.selectedToolNames];
|
|
179
|
+
hasPersistedMCPToolSelection = true;
|
|
180
|
+
} else if (entry.type === "mode_change") {
|
|
181
|
+
mode = entry.mode;
|
|
182
|
+
modeData = entry.data;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const injectedTtsrRules = Array.from(injectedTtsrRulesSet);
|
|
187
|
+
|
|
188
|
+
// Build messages and collect corresponding entries
|
|
189
|
+
// When there's a compaction, we need to:
|
|
190
|
+
// 1. Emit summary first (entry = compaction)
|
|
191
|
+
// 2. Emit kept messages (from firstKeptEntryId up to compaction)
|
|
192
|
+
// 3. Emit messages after compaction
|
|
193
|
+
const messages: AgentMessage[] = [];
|
|
194
|
+
|
|
195
|
+
const appendMessage = (entry: SessionEntry) => {
|
|
196
|
+
if (entry.type === "message") {
|
|
197
|
+
messages.push(entry.message);
|
|
198
|
+
} else if (entry.type === "custom_message") {
|
|
199
|
+
messages.push(
|
|
200
|
+
createCustomMessage(
|
|
201
|
+
entry.customType,
|
|
202
|
+
entry.content,
|
|
203
|
+
entry.display,
|
|
204
|
+
entry.details,
|
|
205
|
+
entry.timestamp,
|
|
206
|
+
entry.attribution,
|
|
207
|
+
),
|
|
208
|
+
);
|
|
209
|
+
} else if (entry.type === "branch_summary" && entry.summary) {
|
|
210
|
+
messages.push(createBranchSummaryMessage(entry.summary, entry.fromId, entry.timestamp));
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
if (options?.transcript) {
|
|
215
|
+
// Display transcript: every entry in chronological order. Compactions do
|
|
216
|
+
// not erase prior history here — each renders inline (as a divider in the
|
|
217
|
+
// TUI) at the point it fired, with any snapcompact frames re-attached so
|
|
218
|
+
// the component can report them.
|
|
219
|
+
for (const entry of path) {
|
|
220
|
+
if (entry.type === "compaction") {
|
|
221
|
+
const snapcompactArchive = snapcompact.getPreservedArchive(entry.preserveData);
|
|
222
|
+
messages.push(
|
|
223
|
+
createCompactionSummaryMessage(
|
|
224
|
+
entry.summary,
|
|
225
|
+
entry.tokensBefore,
|
|
226
|
+
entry.timestamp,
|
|
227
|
+
entry.shortSummary,
|
|
228
|
+
undefined,
|
|
229
|
+
snapcompactArchive ? snapcompact.images(snapcompactArchive) : undefined,
|
|
230
|
+
),
|
|
231
|
+
);
|
|
232
|
+
} else {
|
|
233
|
+
appendMessage(entry);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
} else if (compaction) {
|
|
237
|
+
const providerPayload: ProviderPayload | undefined = (() => {
|
|
238
|
+
const candidate = compaction.preserveData?.openaiRemoteCompaction;
|
|
239
|
+
if (!candidate || typeof candidate !== "object") return undefined;
|
|
240
|
+
const remote = candidate as { provider?: unknown; replacementHistory?: unknown };
|
|
241
|
+
if (typeof remote.provider !== "string" || remote.provider.length === 0) return undefined;
|
|
242
|
+
if (!Array.isArray(remote.replacementHistory)) return undefined;
|
|
243
|
+
return {
|
|
244
|
+
type: "openaiResponsesHistory",
|
|
245
|
+
provider: remote.provider,
|
|
246
|
+
items: remote.replacementHistory as Array<Record<string, unknown>>,
|
|
247
|
+
};
|
|
248
|
+
})();
|
|
249
|
+
const remoteReplacementHistory = providerPayload?.items;
|
|
250
|
+
|
|
251
|
+
// Emit summary first; re-attach any archived snapcompact frames so the
|
|
252
|
+
// model can keep reading the archived history after every context rebuild.
|
|
253
|
+
const snapcompactArchive = snapcompact.getPreservedArchive(compaction.preserveData);
|
|
254
|
+
messages.push(
|
|
255
|
+
createCompactionSummaryMessage(
|
|
256
|
+
compaction.summary,
|
|
257
|
+
compaction.tokensBefore,
|
|
258
|
+
compaction.timestamp,
|
|
259
|
+
compaction.shortSummary,
|
|
260
|
+
providerPayload,
|
|
261
|
+
snapcompactArchive ? snapcompact.images(snapcompactArchive) : undefined,
|
|
262
|
+
),
|
|
263
|
+
);
|
|
264
|
+
|
|
265
|
+
// Find compaction index in path
|
|
266
|
+
const compactionIdx = path.findIndex(e => e.type === "compaction" && e.id === compaction.id);
|
|
267
|
+
|
|
268
|
+
if (!remoteReplacementHistory) {
|
|
269
|
+
// Emit kept messages (before compaction, starting from firstKeptEntryId)
|
|
270
|
+
let foundFirstKept = false;
|
|
271
|
+
for (let i = 0; i < compactionIdx; i++) {
|
|
272
|
+
const entry = path[i];
|
|
273
|
+
if (entry.id === compaction.firstKeptEntryId) {
|
|
274
|
+
foundFirstKept = true;
|
|
275
|
+
}
|
|
276
|
+
if (foundFirstKept) {
|
|
277
|
+
appendMessage(entry);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Emit messages after compaction
|
|
283
|
+
for (let i = compactionIdx + 1; i < path.length; i++) {
|
|
284
|
+
const entry = path[i];
|
|
285
|
+
appendMessage(entry);
|
|
286
|
+
}
|
|
287
|
+
} else {
|
|
288
|
+
// No compaction - emit all messages, handle branch summaries and custom messages
|
|
289
|
+
for (const entry of path) {
|
|
290
|
+
appendMessage(entry);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Strip dangling tool_use blocks — a tool_use with no matching tool_result on the
|
|
295
|
+
// resolved leaf→root path — from ANY assistant turn, not just the trailing one.
|
|
296
|
+
// This happens whenever the leaf (or a branch point) lands such that an assistant
|
|
297
|
+
// turn's tool results are off the selected path: its result children live on a
|
|
298
|
+
// sibling branch, or it is the leaf itself (results are children below it). Left
|
|
299
|
+
// in place, `transformMessages` fabricates one synthetic "aborted"/"No result
|
|
300
|
+
// provided" result per dangling call, which render as phantom failed calls and
|
|
301
|
+
// re-inject the failed batch into the model's
|
|
302
|
+
// context — the rewind/restore loop.
|
|
303
|
+
//
|
|
304
|
+
// Stripping is necessary but not sufficient: a *modified* assistant turn that still
|
|
305
|
+
// carries signed `thinking`/`redacted_thinking` is rejected by Anthropic — "thinking
|
|
306
|
+
// blocks in the latest assistant message cannot be modified", and signed thinking
|
|
307
|
+
// replayed out of its original turn shape can also fail signature validation (this
|
|
308
|
+
// bites the handoff/branch-summary request). So when we rewrite a turn we also
|
|
309
|
+
// neutralize its protected reasoning: drop `redactedThinking` (encrypted, no
|
|
310
|
+
// plaintext to keep) and clear `thinking` signatures so the provider encoder
|
|
311
|
+
// downgrades them to plain text (verified accepted by the live API), preserving the
|
|
312
|
+
// visible reasoning while removing the immutability/invalid-signature hazard. Drop a
|
|
313
|
+
// turn left with no content. (Live turns never qualify: their results are persisted
|
|
314
|
+
// on the same path before any context rebuild.)
|
|
315
|
+
const pairedToolResultIds = new Set<string>();
|
|
316
|
+
for (const message of messages) {
|
|
317
|
+
if (message.role === "toolResult") pairedToolResultIds.add(message.toolCallId);
|
|
318
|
+
}
|
|
319
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
320
|
+
const message = messages[i];
|
|
321
|
+
if (message.role !== "assistant") continue;
|
|
322
|
+
const hasDangling = message.content.some(
|
|
323
|
+
block => block.type === "toolCall" && !pairedToolResultIds.has(block.id),
|
|
324
|
+
);
|
|
325
|
+
if (!hasDangling) continue;
|
|
326
|
+
const normalized = message.content
|
|
327
|
+
.filter(
|
|
328
|
+
block =>
|
|
329
|
+
!(block.type === "toolCall" && !pairedToolResultIds.has(block.id)) && block.type !== "redactedThinking",
|
|
330
|
+
)
|
|
331
|
+
.map(block =>
|
|
332
|
+
block.type === "thinking" && block.thinkingSignature ? { ...block, thinkingSignature: undefined } : block,
|
|
333
|
+
);
|
|
334
|
+
if (normalized.length === 0) {
|
|
335
|
+
messages.splice(i, 1);
|
|
336
|
+
} else {
|
|
337
|
+
messages[i] = { ...message, content: normalized };
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
return {
|
|
342
|
+
messages,
|
|
343
|
+
thinkingLevel,
|
|
344
|
+
serviceTier,
|
|
345
|
+
models,
|
|
346
|
+
injectedTtsrRules,
|
|
347
|
+
selectedMCPToolNames,
|
|
348
|
+
hasPersistedMCPToolSelection,
|
|
349
|
+
mode,
|
|
350
|
+
modeData,
|
|
351
|
+
};
|
|
352
|
+
}
|
|
@@ -5,6 +5,7 @@ import type { AgentMessage, ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
|
5
5
|
import { INTENT_FIELD } from "@oh-my-pi/pi-agent-core";
|
|
6
6
|
import type { AssistantMessage, Model } from "@oh-my-pi/pi-ai";
|
|
7
7
|
import { isZodSchema, zodToWireSchema } from "@oh-my-pi/pi-ai/utils/schema";
|
|
8
|
+
import { getVisibleThinkingText } from "../utils/thinking-display";
|
|
8
9
|
import {
|
|
9
10
|
type BashExecutionMessage,
|
|
10
11
|
type BranchSummaryMessage,
|
|
@@ -126,9 +127,10 @@ export function formatSessionDumpText(options: FormatSessionDumpTextOptions): st
|
|
|
126
127
|
if (c.type === "text") {
|
|
127
128
|
lines.push(c.text);
|
|
128
129
|
} else if (c.type === "thinking") {
|
|
129
|
-
|
|
130
|
+
const thinking = getVisibleThinkingText(c);
|
|
131
|
+
if (thinking.length === 0) continue;
|
|
130
132
|
lines.push("<thinking>");
|
|
131
|
-
lines.push(
|
|
133
|
+
lines.push(thinking);
|
|
132
134
|
lines.push("</thinking>\n");
|
|
133
135
|
} else if (c.type === "toolCall") {
|
|
134
136
|
lines.push(`<invoke name="${c.name}">`);
|