@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
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Synthesize text with the local TTS engine and play it (or save it with --out).
|
|
3
|
+
*
|
|
4
|
+
* Demonstrates the on-device speech stack end to end: the first run downloads
|
|
5
|
+
* the configured local model, synthesis happens in the TTS worker subprocess,
|
|
6
|
+
* and the resulting WAV is either played through the speakers or written to disk.
|
|
7
|
+
*/
|
|
8
|
+
import * as os from "node:os";
|
|
9
|
+
import * as path from "node:path";
|
|
10
|
+
import { getProjectDir, Snowflake } from "@oh-my-pi/pi-utils";
|
|
11
|
+
import { Args, Command, Flags } from "@oh-my-pi/pi-utils/cli";
|
|
12
|
+
import chalk from "chalk";
|
|
13
|
+
import { Settings, settings } from "../config/settings";
|
|
14
|
+
import { playAudioFile, removeTempFile } from "../tts/player";
|
|
15
|
+
import { shutdownTtsClient, ttsClient } from "../tts/tts-client";
|
|
16
|
+
import { encodeWav } from "../tts/wav";
|
|
17
|
+
|
|
18
|
+
export default class Say extends Command {
|
|
19
|
+
static description = "Synthesize text with the local TTS engine and play it through the speakers";
|
|
20
|
+
|
|
21
|
+
static args = {
|
|
22
|
+
text: Args.string({ required: true, description: "Text to speak" }),
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
static flags = {
|
|
26
|
+
voice: Flags.string({ description: "Voice id" }),
|
|
27
|
+
model: Flags.string({ description: "Local TTS model key" }),
|
|
28
|
+
out: Flags.string({ char: "o", description: "Write WAV to this path instead of playing" }),
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
static examples = [
|
|
32
|
+
'omp say "hello world"',
|
|
33
|
+
'omp say "hello world" --out /tmp/hello.wav',
|
|
34
|
+
'omp say "bonjour" --voice af_heart --model kokoro',
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
async run(): Promise<void> {
|
|
38
|
+
const { args, flags } = await this.parse(Say);
|
|
39
|
+
const text = args.text ?? "";
|
|
40
|
+
|
|
41
|
+
await Settings.init({ cwd: getProjectDir() });
|
|
42
|
+
const model = flags.model ?? settings.get("tts.localModel");
|
|
43
|
+
const voice = flags.voice ?? settings.get("tts.localVoice");
|
|
44
|
+
|
|
45
|
+
let exitCode = 0;
|
|
46
|
+
const unsubscribe = ttsClient.onProgress(event => {
|
|
47
|
+
if (event.status === "progress" && typeof event.progress === "number") {
|
|
48
|
+
process.stderr.write(
|
|
49
|
+
`\r${chalk.dim(`downloading ${event.file ?? model}: ${Math.round(event.progress)}%`)}`,
|
|
50
|
+
);
|
|
51
|
+
} else if (event.status === "done" || event.status === "ready") {
|
|
52
|
+
// Clear the progress line once the download finishes.
|
|
53
|
+
process.stderr.write("\r\x1b[K");
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
const audio = await ttsClient.synthesize(model, text, { voice });
|
|
59
|
+
if (!audio) {
|
|
60
|
+
process.stderr.write(
|
|
61
|
+
chalk.red(
|
|
62
|
+
`error: could not synthesize with local TTS model "${model}". ` +
|
|
63
|
+
"Run `omp setup speech` to install it.\n",
|
|
64
|
+
),
|
|
65
|
+
);
|
|
66
|
+
exitCode = 1;
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const wav = encodeWav(audio.pcm, audio.sampleRate);
|
|
71
|
+
const durationSec = audio.pcm.length / audio.sampleRate;
|
|
72
|
+
|
|
73
|
+
if (flags.out) {
|
|
74
|
+
await Bun.write(flags.out, wav);
|
|
75
|
+
process.stdout.write(
|
|
76
|
+
`${chalk.green("saved")} ${flags.out} ` +
|
|
77
|
+
`${chalk.dim(`(${voice}, ${model}, ${durationSec.toFixed(1)}s, ${wav.byteLength} bytes)`)}\n`,
|
|
78
|
+
);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const tmp = path.join(os.tmpdir(), `omp-say-${Snowflake.next()}.wav`);
|
|
83
|
+
await Bun.write(tmp, wav);
|
|
84
|
+
try {
|
|
85
|
+
await playAudioFile(tmp);
|
|
86
|
+
process.stdout.write(
|
|
87
|
+
`${chalk.green("spoke")} ${chalk.dim(`(${voice}, ${model}, ${durationSec.toFixed(1)}s)`)}\n`,
|
|
88
|
+
);
|
|
89
|
+
} finally {
|
|
90
|
+
await removeTempFile(tmp);
|
|
91
|
+
}
|
|
92
|
+
} catch (err) {
|
|
93
|
+
process.stderr.write(chalk.red(`error: ${err instanceof Error ? err.message : String(err)}\n`));
|
|
94
|
+
exitCode = 1;
|
|
95
|
+
} finally {
|
|
96
|
+
unsubscribe();
|
|
97
|
+
await shutdownTtsClient();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (exitCode !== 0) process.exit(exitCode);
|
|
101
|
+
}
|
|
102
|
+
}
|
package/src/commands/setup.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { runSetupCommand, type SetupCommandArgs, type SetupComponent } from "../
|
|
|
7
7
|
import { runRootCommand } from "../main";
|
|
8
8
|
import { initTheme } from "../modes/theme/theme";
|
|
9
9
|
|
|
10
|
-
const COMPONENTS: SetupComponent[] = ["python", "
|
|
10
|
+
const COMPONENTS: SetupComponent[] = ["python", "speech"];
|
|
11
11
|
|
|
12
12
|
export interface OnboardingSetupDependencies {
|
|
13
13
|
runRoot?: typeof runRootCommand;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get the API key or OAuth token for a provider.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { PROVIDER_REGISTRY } from "@oh-my-pi/pi-ai";
|
|
6
|
+
import { Args, Command, Flags } from "@oh-my-pi/pi-utils/cli";
|
|
7
|
+
import chalk from "chalk";
|
|
8
|
+
import { isAuthenticated, ModelRegistry } from "../config/model-registry";
|
|
9
|
+
import { discoverAuthStorage } from "../sdk";
|
|
10
|
+
|
|
11
|
+
export default class Token extends Command {
|
|
12
|
+
static description = "Get the API key or OAuth token for a provider";
|
|
13
|
+
|
|
14
|
+
static args = {
|
|
15
|
+
provider: Args.string({
|
|
16
|
+
description: "Provider ID (e.g. anthropic, openai)",
|
|
17
|
+
required: true,
|
|
18
|
+
}),
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
static flags = {
|
|
22
|
+
raw: Flags.boolean({
|
|
23
|
+
description: "Output the raw credential value without parsing nested JSON structures",
|
|
24
|
+
default: false,
|
|
25
|
+
}),
|
|
26
|
+
"force-refresh": Flags.boolean({
|
|
27
|
+
description: "Force refresh the OAuth token even if it has not expired",
|
|
28
|
+
default: false,
|
|
29
|
+
}),
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
static examples = [
|
|
33
|
+
"# Get API key for Anthropic\n omp token anthropic",
|
|
34
|
+
"# Get raw Copilot credential JSON\n omp token github-copilot --raw",
|
|
35
|
+
"# Force refresh and get Gemini CLI token\n omp token google-gemini-cli --force-refresh",
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
async run(): Promise<void> {
|
|
39
|
+
const { args, flags } = await this.parse(Token);
|
|
40
|
+
const providerName = args.provider ?? "";
|
|
41
|
+
const provider = providerName.toLowerCase();
|
|
42
|
+
|
|
43
|
+
const authStorage = await discoverAuthStorage();
|
|
44
|
+
const modelRegistry = new ModelRegistry(authStorage);
|
|
45
|
+
|
|
46
|
+
// Resolve the API key / token
|
|
47
|
+
const apiKey = await modelRegistry.getApiKeyForProvider(provider, undefined, {
|
|
48
|
+
forceRefresh: flags["force-refresh"],
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
if (!isAuthenticated(apiKey)) {
|
|
52
|
+
// Find all active/configured providers
|
|
53
|
+
const activeProviders = new Set<string>();
|
|
54
|
+
for (const p of PROVIDER_REGISTRY) {
|
|
55
|
+
if (authStorage.hasAuth(p.id)) {
|
|
56
|
+
activeProviders.add(p.id);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const all = authStorage.getAll();
|
|
60
|
+
for (const p in all) {
|
|
61
|
+
if (authStorage.hasAuth(p)) {
|
|
62
|
+
activeProviders.add(p);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const msg = `No active credential found for provider "${providerName}".`;
|
|
67
|
+
process.stderr.write(`${chalk.red(msg)}\n`);
|
|
68
|
+
if (activeProviders.size > 0) {
|
|
69
|
+
process.stderr.write(`Configured providers: ${Array.from(activeProviders).sort().join(", ")}\n`);
|
|
70
|
+
}
|
|
71
|
+
process.exitCode = 1;
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (!flags.raw) {
|
|
76
|
+
try {
|
|
77
|
+
const parsed = JSON.parse(apiKey);
|
|
78
|
+
if (parsed && typeof parsed === "object" && typeof parsed.token === "string") {
|
|
79
|
+
process.stdout.write(`${parsed.token}\n`);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
} catch {
|
|
83
|
+
// Not a JSON string, print as-is
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
process.stdout.write(`${apiKey}\n`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { prompt } from "@oh-my-pi/pi-utils";
|
|
2
|
-
import
|
|
2
|
+
import { z } from "zod/v4";
|
|
3
3
|
import analyzeFilePrompt from "../../../commit/agentic/prompts/analyze-file.md" with { type: "text" };
|
|
4
4
|
import type { CommitAgentState } from "../../../commit/agentic/state";
|
|
5
5
|
import type { NumstatEntry } from "../../../commit/types";
|
|
@@ -38,6 +38,9 @@ function buildToolSession(
|
|
|
38
38
|
return {
|
|
39
39
|
cwd: options.cwd,
|
|
40
40
|
hasUI: false,
|
|
41
|
+
// Programmatic fan-out: results feed the commit agent's evidence, not a
|
|
42
|
+
// model choosing further spawns, so the specialization nudge is noise here.
|
|
43
|
+
suppressSpawnAdvisory: true,
|
|
41
44
|
getSessionFile: () => ctx.sessionManager.getSessionFile() ?? null,
|
|
42
45
|
getSessionSpawns: () => options.spawns,
|
|
43
46
|
settings: options.settings,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
2
|
import type { CommitAgentState, GitOverviewSnapshot } from "../../../commit/agentic/state";
|
|
3
3
|
import { extractScopeCandidates } from "../../../commit/analysis/scope";
|
|
4
4
|
import type { CustomTool } from "../../../extensibility/custom-tools/types";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
2
|
import type { CommitAgentState } from "../../../commit/agentic/state";
|
|
3
3
|
import { CHANGELOG_CATEGORIES, type ChangelogCategory } from "../../../commit/types";
|
|
4
4
|
import type { CustomTool } from "../../../extensibility/custom-tools/types";
|
|
@@ -2,7 +2,7 @@ import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
|
2
2
|
import type { Api, ApiKey, AssistantMessage, Model } from "@oh-my-pi/pi-ai";
|
|
3
3
|
import { completeSimple, validateToolCall } from "@oh-my-pi/pi-ai";
|
|
4
4
|
import { prompt } from "@oh-my-pi/pi-utils";
|
|
5
|
-
import
|
|
5
|
+
import { z } from "zod/v4";
|
|
6
6
|
import summarySystemPrompt from "../../commit/prompts/summary-system.md" with { type: "text" };
|
|
7
7
|
import summaryUserPrompt from "../../commit/prompts/summary-user.md" with { type: "text" };
|
|
8
8
|
import type { CommitSummary } from "../../commit/types";
|
|
@@ -2,7 +2,7 @@ import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
|
2
2
|
import type { Api, ApiKey, AssistantMessage, Model } from "@oh-my-pi/pi-ai";
|
|
3
3
|
import { completeSimple, validateToolCall } from "@oh-my-pi/pi-ai";
|
|
4
4
|
import { prompt } from "@oh-my-pi/pi-utils";
|
|
5
|
-
import
|
|
5
|
+
import { z } from "zod/v4";
|
|
6
6
|
import changelogSystemPrompt from "../../commit/prompts/changelog-system.md" with { type: "text" };
|
|
7
7
|
import changelogUserPrompt from "../../commit/prompts/changelog-user.md" with { type: "text" };
|
|
8
8
|
import { CHANGELOG_CATEGORIES, type ChangelogCategory, type ChangelogGenerationResult } from "../../commit/types";
|
package/src/commit/shared-llm.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AssistantMessage } from "@oh-my-pi/pi-ai";
|
|
2
2
|
import { validateToolCall } from "@oh-my-pi/pi-ai";
|
|
3
|
-
import
|
|
3
|
+
import { z } from "zod/v4";
|
|
4
4
|
import type { ChangelogCategory, ConventionalAnalysis } from "./types";
|
|
5
5
|
import { extractTextContent, extractToolCall, normalizeAnalysis, parseJsonPayload } from "./utils";
|
|
6
6
|
|
|
@@ -212,8 +212,8 @@ export const KEYBINDINGS = {
|
|
|
212
212
|
description: "Search history",
|
|
213
213
|
},
|
|
214
214
|
"app.stt.toggle": {
|
|
215
|
-
defaultKeys:
|
|
216
|
-
description: "Toggle speech-to-text",
|
|
215
|
+
defaultKeys: [],
|
|
216
|
+
description: "Toggle speech-to-text (default gesture: hold Space)",
|
|
217
217
|
},
|
|
218
218
|
} as const satisfies KeybindingDefinitions;
|
|
219
219
|
|
|
@@ -393,12 +393,16 @@ export async function discoverOpenAIModelsList(
|
|
|
393
393
|
const response = apiKey
|
|
394
394
|
? await withAuth(apiKey, key => attempt({ ...baseHeaders, Authorization: `Bearer ${key}` }))
|
|
395
395
|
: await attempt(baseHeaders);
|
|
396
|
-
const payload = (await response.json()) as {
|
|
396
|
+
const payload = (await response.json()) as {
|
|
397
|
+
data?: Array<{ id?: string; max_model_len?: unknown; context_length?: unknown }>;
|
|
398
|
+
};
|
|
397
399
|
const models = payload.data ?? [];
|
|
398
400
|
const discovered: Model<Api>[] = [];
|
|
399
401
|
for (const item of models) {
|
|
400
402
|
const id = item.id;
|
|
401
403
|
if (!id) continue;
|
|
404
|
+
const contextWindow =
|
|
405
|
+
toPositiveNumberOrUndefined(item.max_model_len) ?? toPositiveNumberOrUndefined(item.context_length) ?? 128000;
|
|
402
406
|
discovered.push(
|
|
403
407
|
buildModel({
|
|
404
408
|
id,
|
|
@@ -409,8 +413,8 @@ export async function discoverOpenAIModelsList(
|
|
|
409
413
|
reasoning: false,
|
|
410
414
|
input: ["text"],
|
|
411
415
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
412
|
-
contextWindow
|
|
413
|
-
maxTokens: discoveryDefaultMaxTokens(providerConfig.api),
|
|
416
|
+
contextWindow,
|
|
417
|
+
maxTokens: Math.min(contextWindow, discoveryDefaultMaxTokens(providerConfig.api)),
|
|
414
418
|
headers,
|
|
415
419
|
compat: {
|
|
416
420
|
supportsStore: false,
|
|
@@ -463,7 +467,7 @@ export async function discoverProxyModels(
|
|
|
463
467
|
? await withAuth(apiKey, key => attempt({ ...baseHeaders, Authorization: `Bearer ${key}` }))
|
|
464
468
|
: await attempt(baseHeaders);
|
|
465
469
|
const payload = (await response.json()) as {
|
|
466
|
-
data?: Array<{ id?: string; name?: string; supported_endpoint_types?: string[] }>;
|
|
470
|
+
data?: Array<{ id?: string; name?: string; supported_endpoint_types?: string[]; context_length?: number }>;
|
|
467
471
|
};
|
|
468
472
|
const items = payload.data ?? [];
|
|
469
473
|
const discovered: Model<Api>[] = [];
|
|
@@ -499,7 +503,9 @@ export async function discoverProxyModels(
|
|
|
499
503
|
// upstream bundled catalogs, so keep costs local-unknown even when
|
|
500
504
|
// we successfully recover the upstream model identity.
|
|
501
505
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
502
|
-
|
|
506
|
+
// Prefer the context_length the API reports for this model; fall
|
|
507
|
+
// back to the bundled reference, then a sane default.
|
|
508
|
+
contextWindow: toPositiveNumberOrUndefined(item.context_length) ?? reference?.contextWindow ?? 128000,
|
|
503
509
|
maxTokens: reference?.maxTokens ?? discoveryDefaultMaxTokens(api),
|
|
504
510
|
headers,
|
|
505
511
|
// OpenAI-compat fields are no-ops on anthropic models; the
|
|
@@ -17,8 +17,6 @@ import {
|
|
|
17
17
|
googleGeminiCliModelManagerOptions,
|
|
18
18
|
openaiCodexModelManagerOptions,
|
|
19
19
|
PROVIDER_DESCRIPTORS,
|
|
20
|
-
UNK_CONTEXT_WINDOW,
|
|
21
|
-
UNK_MAX_TOKENS,
|
|
22
20
|
} from "@oh-my-pi/pi-catalog/provider-models";
|
|
23
21
|
import {
|
|
24
22
|
collapseBuiltModelVariants,
|
|
@@ -26,9 +24,11 @@ import {
|
|
|
26
24
|
resolveVariantAlias,
|
|
27
25
|
} from "@oh-my-pi/pi-catalog/variant-collapse";
|
|
28
26
|
|
|
29
|
-
//
|
|
30
|
-
//
|
|
27
|
+
// Sentinels for local-only OAuth tokens — declared inline to avoid loading
|
|
28
|
+
// provider modules at startup. Must match packages/ai/src/registry/lm-studio.ts
|
|
29
|
+
// and packages/ai/src/registry/vllm.ts.
|
|
31
30
|
const DEFAULT_LOCAL_TOKEN = "lm-studio-local";
|
|
31
|
+
const DEFAULT_VLLM_LOCAL_TOKEN = "vllm-local";
|
|
32
32
|
|
|
33
33
|
const SPECIAL_MODEL_MANAGER_PROVIDER_IDS: readonly string[] = [
|
|
34
34
|
"google-antigravity",
|
|
@@ -84,6 +84,10 @@ export function isAuthenticated(apiKey: string | undefined | null): apiKey is st
|
|
|
84
84
|
return Boolean(apiKey) && apiKey !== kNoAuth;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
function isDiscoveryBearerApiKey(apiKey: string | undefined | null): apiKey is string {
|
|
88
|
+
return isAuthenticated(apiKey) && apiKey !== DEFAULT_LOCAL_TOKEN && apiKey !== DEFAULT_VLLM_LOCAL_TOKEN;
|
|
89
|
+
}
|
|
90
|
+
|
|
87
91
|
/** Provider override config (baseUrl, headers, apiKey, compat, transport) without custom models */
|
|
88
92
|
interface ProviderOverride {
|
|
89
93
|
baseUrl?: string;
|
|
@@ -104,9 +108,19 @@ interface ProviderOverride {
|
|
|
104
108
|
* `token-plan-sgp.xiaomimimo.com` at discovery time)
|
|
105
109
|
* 3. Existing bundled baseUrl (the host baked into `models.json`)
|
|
106
110
|
*
|
|
111
|
+
* `transport` resolution priority:
|
|
112
|
+
* 1. `providerOverride.transport` (e.g. `pi-native` for auth-gateway users)
|
|
113
|
+
* 2. `existing.transport` (carried over from boot-time override application)
|
|
114
|
+
* 3. `model.transport` (rarely set — discovery defaults omit it)
|
|
115
|
+
*
|
|
107
116
|
* Without (1), the user's override would lose to discovery; without (2)
|
|
108
117
|
* preferred over (3), the bundled `api.xiaomimimo.com` would shadow the
|
|
109
118
|
* tp- token-plan host and produce 401s on the first stream call.
|
|
119
|
+
* Without explicit transport propagation, an openrouter (or any) entry
|
|
120
|
+
* marked `transport: pi-native` in models.yml silently reverts to the
|
|
121
|
+
* default openai-completions transport after the background catalog
|
|
122
|
+
* refresh — so the first `/model` switch after boot hits the raw OpenAI
|
|
123
|
+
* chat-completions URL instead of the gateway's `/v1/pi/stream` (#2555).
|
|
110
124
|
* See `xiaomi-tp-discovery-merge.test.ts` and the `refresh()` baseUrl-override
|
|
111
125
|
* regression in `model-registry.test.ts`.
|
|
112
126
|
*/
|
|
@@ -120,6 +134,7 @@ export function mergeDiscoveredModel<TApi extends Api>(
|
|
|
120
134
|
...model,
|
|
121
135
|
baseUrl: providerOverride?.baseUrl ?? model.baseUrl ?? existing.baseUrl,
|
|
122
136
|
headers: existing.headers ? { ...existing.headers, ...model.headers } : model.headers,
|
|
137
|
+
transport: providerOverride?.transport ?? existing.transport ?? model.transport,
|
|
123
138
|
compat: model.compatConfig,
|
|
124
139
|
} as ModelSpec<TApi>);
|
|
125
140
|
}
|
|
@@ -530,9 +545,8 @@ function finalizeCustomModel(model: CustomModelOverlay, options: CustomModelBuil
|
|
|
530
545
|
thinking: resolvedModel.thinking ?? reference?.thinking,
|
|
531
546
|
input: input as ("text" | "image")[],
|
|
532
547
|
cost,
|
|
533
|
-
contextWindow:
|
|
534
|
-
|
|
535
|
-
maxTokens: resolvedModel.maxTokens ?? reference?.maxTokens ?? (options.useDefaults ? 16384 : undefined),
|
|
548
|
+
contextWindow: resolvedModel.contextWindow ?? reference?.contextWindow ?? (options.useDefaults ? 128000 : null),
|
|
549
|
+
maxTokens: resolvedModel.maxTokens ?? reference?.maxTokens ?? (options.useDefaults ? 16384 : null),
|
|
536
550
|
headers: resolvedModel.headers,
|
|
537
551
|
omitMaxOutputTokens: resolvedModel.omitMaxOutputTokens ?? reference?.omitMaxOutputTokens,
|
|
538
552
|
compat: mergeCompat(reference?.compatConfig, resolvedModel.compat),
|
|
@@ -866,11 +880,8 @@ export class ModelRegistry {
|
|
|
866
880
|
if (!existing) return replacementModel;
|
|
867
881
|
return {
|
|
868
882
|
...replacementModel,
|
|
869
|
-
contextWindow:
|
|
870
|
-
|
|
871
|
-
? existing.contextWindow
|
|
872
|
-
: replacementModel.contextWindow,
|
|
873
|
-
maxTokens: replacementModel.maxTokens === UNK_MAX_TOKENS ? existing.maxTokens : replacementModel.maxTokens,
|
|
883
|
+
contextWindow: replacementModel.contextWindow ?? existing.contextWindow,
|
|
884
|
+
maxTokens: replacementModel.maxTokens ?? existing.maxTokens,
|
|
874
885
|
};
|
|
875
886
|
});
|
|
876
887
|
}
|
|
@@ -895,6 +906,18 @@ export class ModelRegistry {
|
|
|
895
906
|
});
|
|
896
907
|
}
|
|
897
908
|
|
|
909
|
+
#resolveStartupModelCacheProviderId(providerId: string): string {
|
|
910
|
+
const descriptor = PROVIDER_DESCRIPTORS.find(candidate => candidate.providerId === providerId);
|
|
911
|
+
if (!descriptor) {
|
|
912
|
+
return providerId;
|
|
913
|
+
}
|
|
914
|
+
const baseUrl =
|
|
915
|
+
this.#runtimeProviderOverrides.get(providerId)?.baseUrl ??
|
|
916
|
+
this.#providerOverrides.get(providerId)?.baseUrl ??
|
|
917
|
+
this.getProviderBaseUrl(providerId);
|
|
918
|
+
return descriptor.createModelManagerOptions({ baseUrl, fetch: this.#fetch }).cacheProviderId ?? providerId;
|
|
919
|
+
}
|
|
920
|
+
|
|
898
921
|
#loadCachedStandardProviderModels(): { models: Model<Api>[]; authoritativeFreshProviders: Set<string> } {
|
|
899
922
|
const configuredDiscoveryProviders = new Set(this.#discoverableProviders.map(provider => provider.provider));
|
|
900
923
|
const cachedModels: Model<Api>[] = [];
|
|
@@ -903,7 +926,8 @@ export class ModelRegistry {
|
|
|
903
926
|
if (configuredDiscoveryProviders.has(providerId)) {
|
|
904
927
|
continue;
|
|
905
928
|
}
|
|
906
|
-
const
|
|
929
|
+
const cacheProviderId = this.#resolveStartupModelCacheProviderId(providerId);
|
|
930
|
+
const cache = readModelCache<Api>(cacheProviderId, 24 * 60 * 60 * 1000, Date.now, this.#cacheDbPath);
|
|
907
931
|
if (!cache) {
|
|
908
932
|
continue;
|
|
909
933
|
}
|
|
@@ -933,7 +957,12 @@ export class ModelRegistry {
|
|
|
933
957
|
#loadCachedDiscoverableModels(): Model<Api>[] {
|
|
934
958
|
const cachedModels: Model<Api>[] = [];
|
|
935
959
|
for (const providerConfig of this.#discoverableProviders) {
|
|
936
|
-
const cache = readModelCache<Api>(
|
|
960
|
+
const cache = readModelCache<Api>(
|
|
961
|
+
this.#configuredDiscoveryCacheProviderId(providerConfig),
|
|
962
|
+
24 * 60 * 60 * 1000,
|
|
963
|
+
Date.now,
|
|
964
|
+
this.#cacheDbPath,
|
|
965
|
+
);
|
|
937
966
|
if (!cache) {
|
|
938
967
|
this.#providerDiscoveryStates.set(providerConfig.provider, {
|
|
939
968
|
provider: providerConfig.provider,
|
|
@@ -1195,11 +1224,19 @@ export class ModelRegistry {
|
|
|
1195
1224
|
this.#rebuildCanonicalIndex();
|
|
1196
1225
|
}
|
|
1197
1226
|
|
|
1227
|
+
#configuredDiscoveryCacheProviderId(providerConfig: DiscoveryProviderConfig): string {
|
|
1228
|
+
if (providerConfig.discovery.type === "openai-models-list") {
|
|
1229
|
+
return `${providerConfig.provider}:openai-models-list-context-v2`;
|
|
1230
|
+
}
|
|
1231
|
+
return providerConfig.provider;
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1198
1234
|
async #discoverProviderModels(
|
|
1199
1235
|
providerConfig: DiscoveryProviderConfig,
|
|
1200
1236
|
strategy: ModelRefreshStrategy,
|
|
1201
1237
|
): Promise<Model<Api>[]> {
|
|
1202
|
-
const
|
|
1238
|
+
const cacheProviderId = this.#configuredDiscoveryCacheProviderId(providerConfig);
|
|
1239
|
+
const cached = readModelCache<Api>(cacheProviderId, 24 * 60 * 60 * 1000, Date.now, this.#cacheDbPath);
|
|
1203
1240
|
const requiresAuth = !this.#keylessProviders.has(providerConfig.provider);
|
|
1204
1241
|
if (requiresAuth) {
|
|
1205
1242
|
const apiKey = await this.#peekApiKeyForProvider(providerConfig.provider);
|
|
@@ -1237,6 +1274,7 @@ export class ModelRegistry {
|
|
|
1237
1274
|
providerId,
|
|
1238
1275
|
staticModels: [],
|
|
1239
1276
|
cacheDbPath: this.#cacheDbPath,
|
|
1277
|
+
cacheProviderId,
|
|
1240
1278
|
cacheTtlMs: 24 * 60 * 60 * 1000,
|
|
1241
1279
|
fetchDynamicModels,
|
|
1242
1280
|
});
|
|
@@ -1278,7 +1316,9 @@ export class ModelRegistry {
|
|
|
1278
1316
|
fetch: this.#fetch,
|
|
1279
1317
|
getBearerApiKeyResolver: async provider => {
|
|
1280
1318
|
const apiKey = await this.getApiKeyForProvider(provider);
|
|
1281
|
-
if (!apiKey
|
|
1319
|
+
if (!isDiscoveryBearerApiKey(apiKey)) {
|
|
1320
|
+
return undefined;
|
|
1321
|
+
}
|
|
1282
1322
|
return this.resolver(provider);
|
|
1283
1323
|
},
|
|
1284
1324
|
};
|
|
@@ -1383,11 +1423,20 @@ export class ModelRegistry {
|
|
|
1383
1423
|
for (let i = 0; i < standardProviderDescriptors.length; i++) {
|
|
1384
1424
|
const descriptor = standardProviderDescriptors[i];
|
|
1385
1425
|
const apiKey = standardProviderKeys[i];
|
|
1386
|
-
|
|
1426
|
+
const hasExplicitVllmConfig =
|
|
1427
|
+
descriptor.providerId === "vllm" &&
|
|
1428
|
+
(this.#runtimeProviderOverrides.has(descriptor.providerId) ||
|
|
1429
|
+
this.#providerOverrides.has(descriptor.providerId) ||
|
|
1430
|
+
this.#keylessProviders.has(descriptor.providerId));
|
|
1431
|
+
if (isAuthenticated(apiKey) || descriptor.allowUnauthenticated || hasExplicitVllmConfig) {
|
|
1432
|
+
const discoveryBaseUrl =
|
|
1433
|
+
this.#runtimeProviderOverrides.get(descriptor.providerId)?.baseUrl ??
|
|
1434
|
+
this.#providerOverrides.get(descriptor.providerId)?.baseUrl ??
|
|
1435
|
+
this.getProviderBaseUrl(descriptor.providerId);
|
|
1387
1436
|
options.push(
|
|
1388
1437
|
descriptor.createModelManagerOptions({
|
|
1389
|
-
apiKey:
|
|
1390
|
-
baseUrl:
|
|
1438
|
+
apiKey: isDiscoveryBearerApiKey(apiKey) ? apiKey : undefined,
|
|
1439
|
+
baseUrl: discoveryBaseUrl,
|
|
1391
1440
|
fetch: this.#fetch,
|
|
1392
1441
|
}),
|
|
1393
1442
|
);
|
|
@@ -1739,11 +1788,20 @@ export class ModelRegistry {
|
|
|
1739
1788
|
* paths that pre-flight auth before model resolution) can probe a model
|
|
1740
1789
|
* without resolving an API key. Returns true for keyless providers as well
|
|
1741
1790
|
* as providers with stored credentials. See issue #993.
|
|
1791
|
+
*
|
|
1792
|
+
* Side-effect-free and synchronous: a command-backed key (`!cmd`) counts as
|
|
1793
|
+
* configured by its presence alone — the program is NOT executed — and OAuth
|
|
1794
|
+
* tokens are NOT refreshed (`authStorage.hasAuth`). This is what keeps the
|
|
1795
|
+
* model-switch pre-flight off the event loop's hot path; the real key
|
|
1796
|
+
* (command execution + OAuth refresh) is resolved lazily per request via
|
|
1797
|
+
* {@link ModelRegistry.resolver}.
|
|
1742
1798
|
*/
|
|
1743
1799
|
hasConfiguredAuth(model: Model<Api>): boolean {
|
|
1744
|
-
const
|
|
1800
|
+
const keyConfig = this.#customProviderApiKeys.get(model.provider);
|
|
1745
1801
|
return (
|
|
1746
|
-
|
|
1802
|
+
isCommandConfigValue(keyConfig) ||
|
|
1803
|
+
this.#keylessProviders.has(model.provider) ||
|
|
1804
|
+
this.authStorage.hasAuth(model.provider)
|
|
1747
1805
|
);
|
|
1748
1806
|
}
|
|
1749
1807
|
|
|
@@ -1247,7 +1247,7 @@ export function resolveCliModel(options: {
|
|
|
1247
1247
|
model: undefined,
|
|
1248
1248
|
selector: undefined,
|
|
1249
1249
|
warning: undefined,
|
|
1250
|
-
error: `Unknown provider "${cliProvider}".
|
|
1250
|
+
error: `Unknown provider "${cliProvider}". Run "omp models" to see available providers/models.`,
|
|
1251
1251
|
};
|
|
1252
1252
|
}
|
|
1253
1253
|
|
|
@@ -1337,7 +1337,7 @@ export function resolveCliModel(options: {
|
|
|
1337
1337
|
selector: undefined,
|
|
1338
1338
|
thinkingLevel: undefined,
|
|
1339
1339
|
warning,
|
|
1340
|
-
error: `Model "${display}" not found.
|
|
1340
|
+
error: `Model "${display}" not found. Run "omp models" to see available models.`,
|
|
1341
1341
|
};
|
|
1342
1342
|
}
|
|
1343
1343
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
2
|
|
|
3
3
|
const OpenRouterRoutingSchema = z.object({
|
|
4
4
|
only: z.array(z.string()).optional(),
|
|
@@ -35,6 +35,7 @@ const OpenAICompatFieldsSchema = z.object({
|
|
|
35
35
|
allowsSyntheticReasoningContentForToolCalls: z.boolean().optional(),
|
|
36
36
|
requiresAssistantContentForToolCalls: z.boolean().optional(),
|
|
37
37
|
supportsToolChoice: z.boolean().optional(),
|
|
38
|
+
supportsForcedToolChoice: z.boolean().optional(),
|
|
38
39
|
disableReasoningOnForcedToolChoice: z.boolean().optional(),
|
|
39
40
|
disableReasoningOnToolChoice: z.boolean().optional(),
|
|
40
41
|
thinkingFormat: z.enum(["openai", "openrouter", "zai", "qwen", "qwen-chat-template"]).optional(),
|
|
@@ -44,7 +45,7 @@ const OpenAICompatFieldsSchema = z.object({
|
|
|
44
45
|
cacheControlFormat: z.enum(["anthropic"]).optional(),
|
|
45
46
|
supportsStrictMode: z.boolean().optional(),
|
|
46
47
|
toolStrictMode: z.enum(["all_strict", "none"]).optional(),
|
|
47
|
-
streamIdleTimeoutMs: z.number().
|
|
48
|
+
streamIdleTimeoutMs: z.number().nonnegative().optional(),
|
|
48
49
|
supportsLongPromptCacheRetention: z.boolean().optional(),
|
|
49
50
|
supportsReasoningParams: z.boolean().optional(),
|
|
50
51
|
alwaysSendMaxTokens: z.boolean().optional(),
|
|
@@ -124,6 +125,7 @@ const ModelDefinitionSchema = z.object({
|
|
|
124
125
|
"azure-openai-responses",
|
|
125
126
|
"anthropic-messages",
|
|
126
127
|
"google-generative-ai",
|
|
128
|
+
"google-gemini-cli",
|
|
127
129
|
"google-vertex",
|
|
128
130
|
])
|
|
129
131
|
.optional(),
|
|
@@ -192,6 +194,7 @@ const ProviderConfigSchema = z.object({
|
|
|
192
194
|
"azure-openai-responses",
|
|
193
195
|
"anthropic-messages",
|
|
194
196
|
"google-generative-ai",
|
|
197
|
+
"google-gemini-cli",
|
|
195
198
|
"google-vertex",
|
|
196
199
|
])
|
|
197
200
|
.optional(),
|
|
@@ -50,12 +50,13 @@ export function validateProviderConfiguration(
|
|
|
50
50
|
!config.headers &&
|
|
51
51
|
!config.compat &&
|
|
52
52
|
!config.apiKey &&
|
|
53
|
+
config.auth !== "none" &&
|
|
53
54
|
!config.disableStrictTools &&
|
|
54
55
|
!hasModelOverrides &&
|
|
55
56
|
!config.discovery
|
|
56
57
|
) {
|
|
57
58
|
throw new Error(
|
|
58
|
-
`Provider ${providerName}: must specify "baseUrl", "headers", "apiKey", "compat", "disableStrictTools", "modelOverrides", "discovery", or "models"`,
|
|
59
|
+
`Provider ${providerName}: must specify "baseUrl", "headers", "apiKey", "auth: none", "compat", "disableStrictTools", "modelOverrides", "discovery", or "models"`,
|
|
59
60
|
);
|
|
60
61
|
}
|
|
61
62
|
}
|