@oh-my-pi/pi-coding-agent 15.12.4 → 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 +304 -6
- package/dist/cli.js +1015 -881
- 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/types.d.ts +1 -1
- package/dist/types/cli/args.d.ts +19 -1
- 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/say.d.ts +24 -0
- package/dist/types/config/keybindings.d.ts +3 -3
- package/dist/types/config/model-registry.d.ts +10 -0
- package/dist/types/config/models-config-schema.d.ts +12 -0
- package/dist/types/config/models-config.d.ts +8 -2
- package/dist/types/config/settings-schema.d.ts +261 -58
- package/dist/types/export/html/index.d.ts +2 -1
- 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 +47 -1
- package/dist/types/extensibility/hooks/index.d.ts +2 -1
- 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/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/main.d.ts +4 -3
- 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 +4 -4
- 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/session-selector.d.ts +1 -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/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 -3
- 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 -2
- 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 +14 -2
- package/dist/types/session/indexed-session-storage.d.ts +3 -4
- 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 +82 -474
- 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 -12
- 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/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 +36 -0
- package/dist/types/tools/bash.d.ts +2 -2
- package/dist/types/tools/eval-render.d.ts +1 -1
- package/dist/types/tools/index.d.ts +11 -1
- package/dist/types/tools/irc.d.ts +1 -0
- package/dist/types/tools/learn.d.ts +51 -0
- package/dist/types/tools/manage-skill.d.ts +40 -0
- package/dist/types/tools/plan-mode-guard.d.ts +10 -0
- package/dist/types/tools/renderers.d.ts +7 -11
- package/dist/types/tools/ssh.d.ts +1 -1
- package/dist/types/tools/todo.d.ts +1 -1
- package/dist/types/tools/tts.d.ts +25 -0
- package/dist/types/tools/write.d.ts +1 -1
- 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/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/package.json +15 -14
- 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/types.ts +1 -1
- package/src/cli/args.ts +56 -2
- 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 +1 -0
- package/src/cli.ts +45 -13
- package/src/collab/host.ts +1 -1
- package/src/collab/protocol.ts +1 -1
- package/src/commands/say.ts +102 -0
- package/src/commands/setup.ts +1 -1
- package/src/commit/agentic/tools/analyze-file.ts +3 -0
- package/src/config/keybindings.ts +2 -2
- package/src/config/model-discovery.ts +11 -5
- package/src/config/model-registry.ts +64 -9
- package/src/config/models-config-schema.ts +4 -1
- package/src/config/models-config.ts +2 -1
- package/src/config/settings-schema.ts +248 -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/eval/__tests__/budget-bridge.test.ts +1 -1
- package/src/eval/js/shared/prelude.txt +69 -17
- package/src/export/html/index.ts +3 -6
- package/src/extensibility/extensions/model-api.ts +41 -0
- package/src/extensibility/extensions/runner.ts +4 -0
- package/src/extensibility/extensions/types.ts +52 -1
- package/src/extensibility/extensions/wrapper.ts +41 -5
- package/src/extensibility/hooks/index.ts +2 -1
- 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 +96 -15
- package/src/goals/guided-setup.ts +133 -0
- package/src/goals/state.ts +1 -1
- package/src/hindsight/transcript.ts +1 -1
- package/src/index.ts +5 -0
- package/src/internal-urls/docs-index.generated.ts +10 -10
- package/src/internal-urls/history-protocol.ts +1 -1
- package/src/internal-urls/local-protocol.ts +29 -7
- package/src/main.ts +27 -7
- package/src/mcp/startup-events.ts +21 -0
- package/src/mcp/transports/stdio.ts +2 -1
- package/src/memories/index.ts +146 -11
- package/src/memory-backend/local-backend.ts +11 -5
- package/src/mnemopi/backend.ts +1 -0
- package/src/mnemopi/config.ts +26 -10
- package/src/modes/acp/acp-agent.ts +3 -5
- package/src/modes/components/agent-hub.ts +49 -4
- package/src/modes/components/assistant-message.ts +4 -37
- 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/session-selector.ts +1 -1
- package/src/modes/components/settings-defs.ts +7 -0
- 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 -4
- package/src/modes/controllers/event-controller.ts +78 -11
- package/src/modes/controllers/extension-ui-controller.ts +6 -0
- package/src/modes/controllers/input-controller.ts +258 -27
- package/src/modes/controllers/selector-controller.ts +12 -2
- package/src/modes/gradient-highlight.ts +21 -9
- package/src/modes/image-references.ts +20 -0
- package/src/modes/interactive-mode.ts +286 -40
- 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 +98 -50
- package/src/modes/types.ts +6 -2
- package/src/modes/utils/hotkeys-markdown.ts +1 -1
- package/src/modes/utils/ui-helpers.ts +34 -6
- 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/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 +88 -24
- package/src/secrets/obfuscator.ts +1 -1
- package/src/session/agent-session.ts +209 -87
- package/src/session/history-storage.ts +2 -2
- package/src/session/indexed-session-storage.ts +7 -17
- package/src/session/session-context.ts +352 -0
- 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 +933 -3145
- 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 -50
- 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 +25 -3
- 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 +53 -0
- package/src/tools/ask.ts +8 -0
- package/src/tools/bash.ts +4 -3
- package/src/tools/eval-render.ts +4 -3
- package/src/tools/index.ts +40 -4
- package/src/tools/irc.ts +10 -2
- package/src/tools/job.ts +14 -2
- package/src/tools/learn.ts +144 -0
- package/src/tools/manage-skill.ts +104 -0
- package/src/tools/plan-mode-guard.ts +53 -19
- package/src/tools/renderers.ts +7 -11
- package/src/tools/ssh.ts +4 -3
- package/src/tools/todo.ts +1 -1
- package/src/tools/tts.ts +203 -92
- package/src/tools/write.ts +18 -2
- 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/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 +13 -0
- package/src/web/search/providers/searxng.ts +13 -1
- package/dist/types/stt/setup.d.ts +0 -18
- package/src/stt/setup.ts +0 -52
- package/src/stt/transcribe.py +0 -70
package/src/cli-commands.ts
CHANGED
|
@@ -29,6 +29,7 @@ export const commands: CommandEntry[] = [
|
|
|
29
29
|
{ name: "join", load: () => import("./commands/join").then(m => m.default) },
|
|
30
30
|
{ name: "models", load: () => import("./commands/models").then(m => m.default) },
|
|
31
31
|
{ name: "plugin", load: () => import("./commands/plugin").then(m => m.default) },
|
|
32
|
+
{ name: "say", load: () => import("./commands/say").then(m => m.default) },
|
|
32
33
|
{ name: "setup", load: () => import("./commands/setup").then(m => m.default) },
|
|
33
34
|
{ name: "shell", load: () => import("./commands/shell").then(m => m.default) },
|
|
34
35
|
{ name: "read", load: () => import("./commands/read").then(m => m.default) },
|
package/src/cli.ts
CHANGED
|
@@ -56,6 +56,8 @@ async function showHelp(config: CliConfig): Promise<void> {
|
|
|
56
56
|
async function runSmokeTest(): Promise<void> {
|
|
57
57
|
const { smokeTestSyncWorker, startServer } = await import("@oh-my-pi/omp-stats");
|
|
58
58
|
const { smokeTestTinyTitleWorker } = await import("./tiny/title-client");
|
|
59
|
+
const { smokeTestSttWorker } = await import("./stt/asr-client");
|
|
60
|
+
const { smokeTestTtsWorker } = await import("./tts/tts-client");
|
|
59
61
|
await smokeTestSyncWorker();
|
|
60
62
|
|
|
61
63
|
const statsServer = await startServer(0);
|
|
@@ -71,6 +73,8 @@ async function runSmokeTest(): Promise<void> {
|
|
|
71
73
|
}
|
|
72
74
|
|
|
73
75
|
await smokeTestTinyTitleWorker();
|
|
76
|
+
await smokeTestSttWorker();
|
|
77
|
+
await smokeTestTtsWorker();
|
|
74
78
|
process.stdout.write("smoke-test: ok\n");
|
|
75
79
|
}
|
|
76
80
|
|
|
@@ -78,6 +82,8 @@ const TINY_WORKER_ARGS = new Set(["--tiny-worker", "__tiny_worker"]);
|
|
|
78
82
|
const STATS_SYNC_WORKER_ARG = "__omp_stats_sync_worker";
|
|
79
83
|
const TAB_WORKER_ARG = "__omp_tab_worker";
|
|
80
84
|
const JS_EVAL_WORKER_ARG = "__omp_js_eval_worker";
|
|
85
|
+
const STT_WORKER_ARG = "__omp_stt_worker";
|
|
86
|
+
const TTS_WORKER_ARG = "__omp_tts_worker";
|
|
81
87
|
|
|
82
88
|
async function runWorkerEntrypoint(arg: string | undefined): Promise<boolean> {
|
|
83
89
|
if (arg === STATS_SYNC_WORKER_ARG) {
|
|
@@ -110,21 +116,34 @@ async function runWorkerEntrypoint(arg: string | undefined): Promise<boolean> {
|
|
|
110
116
|
await import("./eval/js/worker-entry");
|
|
111
117
|
return true;
|
|
112
118
|
}
|
|
119
|
+
if (arg === STT_WORKER_ARG) {
|
|
120
|
+
const { startSttWorker } = await import("./stt/asr-worker");
|
|
121
|
+
await runIpcSubprocessWorker(startSttWorker);
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
if (arg === TTS_WORKER_ARG) {
|
|
125
|
+
const { startTtsWorker } = await import("./tts/tts-worker");
|
|
126
|
+
await runIpcSubprocessWorker(startTtsWorker);
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
113
129
|
return false;
|
|
114
130
|
}
|
|
115
131
|
|
|
116
132
|
/**
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
* `@huggingface/transformers`)
|
|
121
|
-
*
|
|
122
|
-
*
|
|
133
|
+
* Boot a subprocess-isolated transformers.js worker over the parent's IPC
|
|
134
|
+
* channel and block until the parent disconnects. The tiny-model, STT, and TTS
|
|
135
|
+
* workers each run `onnxruntime-node` (loaded transitively by
|
|
136
|
+
* `@huggingface/transformers`) in a child address space because its NAPI
|
|
137
|
+
* finalizer segfaults Bun on shutdown (issue #1606); the parent `SIGKILL`s the
|
|
138
|
+
* child so that finalizer never runs in either process. This wires `process`
|
|
139
|
+
* IPC to the worker's typed transport, keeps the event loop alive while the
|
|
140
|
+
* worker is idle, and hard-kills the process on parent `disconnect`.
|
|
123
141
|
*/
|
|
124
|
-
async function
|
|
125
|
-
|
|
142
|
+
async function runIpcSubprocessWorker<In, Out>(
|
|
143
|
+
start: (transport: { send(message: Out): void; onMessage(handler: (message: In) => void): () => void }) => void,
|
|
144
|
+
): Promise<void> {
|
|
126
145
|
const { promise: shuttingDown, resolve: shutdown } = Promise.withResolvers<void>();
|
|
127
|
-
const send = (message:
|
|
146
|
+
const send = (message: Out): void => {
|
|
128
147
|
// `process.send` only exists when spawned with an IPC channel; the
|
|
129
148
|
// parent always spawns us that way. If it's missing, the parent
|
|
130
149
|
// vanished and there's no one to talk to.
|
|
@@ -139,10 +158,10 @@ async function runTinyWorker(): Promise<void> {
|
|
|
139
158
|
shutdown();
|
|
140
159
|
}
|
|
141
160
|
};
|
|
142
|
-
|
|
161
|
+
start({
|
|
143
162
|
send,
|
|
144
163
|
onMessage(handler) {
|
|
145
|
-
const wrap = (data: unknown): void => handler(data as
|
|
164
|
+
const wrap = (data: unknown): void => handler(data as In);
|
|
146
165
|
process.on("message", wrap);
|
|
147
166
|
return () => {
|
|
148
167
|
process.off("message", wrap);
|
|
@@ -151,8 +170,8 @@ async function runTinyWorker(): Promise<void> {
|
|
|
151
170
|
});
|
|
152
171
|
const keepalive = setInterval(() => {}, 2 ** 30);
|
|
153
172
|
// Parent went away (crashed, SIGKILL, etc.) — commit suicide so we don't
|
|
154
|
-
// linger as an orphan. SIGKILL via `process.kill` keeps us symmetrical
|
|
155
|
-
//
|
|
173
|
+
// linger as an orphan. SIGKILL via `process.kill` keeps us symmetrical with
|
|
174
|
+
// the parent's hard-kill on shutdown: skip every JS/native finalizer.
|
|
156
175
|
process.on("disconnect", () => shutdown());
|
|
157
176
|
try {
|
|
158
177
|
await shuttingDown;
|
|
@@ -162,6 +181,19 @@ async function runTinyWorker(): Promise<void> {
|
|
|
162
181
|
process.kill(process.pid, "SIGKILL");
|
|
163
182
|
}
|
|
164
183
|
|
|
184
|
+
/**
|
|
185
|
+
* Hidden subcommand that boots the tiny-model worker inside this process over
|
|
186
|
+
* the parent's IPC channel. The agent's main process spawns the same binary
|
|
187
|
+
* with this flag so `onnxruntime-node` (loaded transitively by
|
|
188
|
+
* `@huggingface/transformers`) lives in a child address space. The parent
|
|
189
|
+
* `SIGKILL`s the child on shutdown so the NAPI finalizer never runs in either
|
|
190
|
+
* process — that finalizer segfaults Bun on Windows (issue #1606).
|
|
191
|
+
*/
|
|
192
|
+
async function runTinyWorker(): Promise<void> {
|
|
193
|
+
const { startTinyTitleWorker } = await import("./tiny/worker");
|
|
194
|
+
await runIpcSubprocessWorker(startTinyTitleWorker);
|
|
195
|
+
}
|
|
196
|
+
|
|
165
197
|
/** Run the CLI with the given argv (no `process.argv` prefix). */
|
|
166
198
|
export async function runCli(argv: string[]): Promise<void> {
|
|
167
199
|
if (argv[0] === "--smoke-test") {
|
package/src/collab/host.ts
CHANGED
|
@@ -20,7 +20,7 @@ import { AgentLifecycleManager } from "../registry/agent-lifecycle";
|
|
|
20
20
|
import { AgentRegistry } from "../registry/agent-registry";
|
|
21
21
|
import type { AgentSessionEvent } from "../session/agent-session";
|
|
22
22
|
import { stripImagesFromMessage, USER_INTERRUPT_LABEL } from "../session/messages";
|
|
23
|
-
import type { SessionEntry as StoredSessionEntry } from "../session/session-
|
|
23
|
+
import type { SessionEntry as StoredSessionEntry } from "../session/session-entries";
|
|
24
24
|
import { TASK_SUBAGENT_LIFECYCLE_CHANNEL, TASK_SUBAGENT_PROGRESS_CHANNEL } from "../task";
|
|
25
25
|
import { generateRoomKey, generateWriteToken, importRoomKey } from "./crypto";
|
|
26
26
|
import {
|
package/src/collab/protocol.ts
CHANGED
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
} from "@oh-my-pi/pi-wire";
|
|
26
26
|
import type { ContextUsage } from "../extensibility/extensions/types";
|
|
27
27
|
import type { AgentSessionEvent } from "../session/agent-session";
|
|
28
|
-
import type { SessionEntry, SessionHeader } from "../session/session-
|
|
28
|
+
import type { SessionEntry, SessionHeader } from "../session/session-entries";
|
|
29
29
|
|
|
30
30
|
export type {
|
|
31
31
|
CollabPromptDetails,
|
|
@@ -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;
|
|
@@ -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,
|
|
@@ -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
|
|
@@ -24,9 +24,11 @@ import {
|
|
|
24
24
|
resolveVariantAlias,
|
|
25
25
|
} from "@oh-my-pi/pi-catalog/variant-collapse";
|
|
26
26
|
|
|
27
|
-
//
|
|
28
|
-
//
|
|
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.
|
|
29
30
|
const DEFAULT_LOCAL_TOKEN = "lm-studio-local";
|
|
31
|
+
const DEFAULT_VLLM_LOCAL_TOKEN = "vllm-local";
|
|
30
32
|
|
|
31
33
|
const SPECIAL_MODEL_MANAGER_PROVIDER_IDS: readonly string[] = [
|
|
32
34
|
"google-antigravity",
|
|
@@ -82,6 +84,10 @@ export function isAuthenticated(apiKey: string | undefined | null): apiKey is st
|
|
|
82
84
|
return Boolean(apiKey) && apiKey !== kNoAuth;
|
|
83
85
|
}
|
|
84
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
|
+
|
|
85
91
|
/** Provider override config (baseUrl, headers, apiKey, compat, transport) without custom models */
|
|
86
92
|
interface ProviderOverride {
|
|
87
93
|
baseUrl?: string;
|
|
@@ -102,9 +108,19 @@ interface ProviderOverride {
|
|
|
102
108
|
* `token-plan-sgp.xiaomimimo.com` at discovery time)
|
|
103
109
|
* 3. Existing bundled baseUrl (the host baked into `models.json`)
|
|
104
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
|
+
*
|
|
105
116
|
* Without (1), the user's override would lose to discovery; without (2)
|
|
106
117
|
* preferred over (3), the bundled `api.xiaomimimo.com` would shadow the
|
|
107
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).
|
|
108
124
|
* See `xiaomi-tp-discovery-merge.test.ts` and the `refresh()` baseUrl-override
|
|
109
125
|
* regression in `model-registry.test.ts`.
|
|
110
126
|
*/
|
|
@@ -118,6 +134,7 @@ export function mergeDiscoveredModel<TApi extends Api>(
|
|
|
118
134
|
...model,
|
|
119
135
|
baseUrl: providerOverride?.baseUrl ?? model.baseUrl ?? existing.baseUrl,
|
|
120
136
|
headers: existing.headers ? { ...existing.headers, ...model.headers } : model.headers,
|
|
137
|
+
transport: providerOverride?.transport ?? existing.transport ?? model.transport,
|
|
121
138
|
compat: model.compatConfig,
|
|
122
139
|
} as ModelSpec<TApi>);
|
|
123
140
|
}
|
|
@@ -889,6 +906,18 @@ export class ModelRegistry {
|
|
|
889
906
|
});
|
|
890
907
|
}
|
|
891
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
|
+
|
|
892
921
|
#loadCachedStandardProviderModels(): { models: Model<Api>[]; authoritativeFreshProviders: Set<string> } {
|
|
893
922
|
const configuredDiscoveryProviders = new Set(this.#discoverableProviders.map(provider => provider.provider));
|
|
894
923
|
const cachedModels: Model<Api>[] = [];
|
|
@@ -897,7 +926,8 @@ export class ModelRegistry {
|
|
|
897
926
|
if (configuredDiscoveryProviders.has(providerId)) {
|
|
898
927
|
continue;
|
|
899
928
|
}
|
|
900
|
-
const
|
|
929
|
+
const cacheProviderId = this.#resolveStartupModelCacheProviderId(providerId);
|
|
930
|
+
const cache = readModelCache<Api>(cacheProviderId, 24 * 60 * 60 * 1000, Date.now, this.#cacheDbPath);
|
|
901
931
|
if (!cache) {
|
|
902
932
|
continue;
|
|
903
933
|
}
|
|
@@ -927,7 +957,12 @@ export class ModelRegistry {
|
|
|
927
957
|
#loadCachedDiscoverableModels(): Model<Api>[] {
|
|
928
958
|
const cachedModels: Model<Api>[] = [];
|
|
929
959
|
for (const providerConfig of this.#discoverableProviders) {
|
|
930
|
-
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
|
+
);
|
|
931
966
|
if (!cache) {
|
|
932
967
|
this.#providerDiscoveryStates.set(providerConfig.provider, {
|
|
933
968
|
provider: providerConfig.provider,
|
|
@@ -1189,11 +1224,19 @@ export class ModelRegistry {
|
|
|
1189
1224
|
this.#rebuildCanonicalIndex();
|
|
1190
1225
|
}
|
|
1191
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
|
+
|
|
1192
1234
|
async #discoverProviderModels(
|
|
1193
1235
|
providerConfig: DiscoveryProviderConfig,
|
|
1194
1236
|
strategy: ModelRefreshStrategy,
|
|
1195
1237
|
): Promise<Model<Api>[]> {
|
|
1196
|
-
const
|
|
1238
|
+
const cacheProviderId = this.#configuredDiscoveryCacheProviderId(providerConfig);
|
|
1239
|
+
const cached = readModelCache<Api>(cacheProviderId, 24 * 60 * 60 * 1000, Date.now, this.#cacheDbPath);
|
|
1197
1240
|
const requiresAuth = !this.#keylessProviders.has(providerConfig.provider);
|
|
1198
1241
|
if (requiresAuth) {
|
|
1199
1242
|
const apiKey = await this.#peekApiKeyForProvider(providerConfig.provider);
|
|
@@ -1231,6 +1274,7 @@ export class ModelRegistry {
|
|
|
1231
1274
|
providerId,
|
|
1232
1275
|
staticModels: [],
|
|
1233
1276
|
cacheDbPath: this.#cacheDbPath,
|
|
1277
|
+
cacheProviderId,
|
|
1234
1278
|
cacheTtlMs: 24 * 60 * 60 * 1000,
|
|
1235
1279
|
fetchDynamicModels,
|
|
1236
1280
|
});
|
|
@@ -1272,7 +1316,9 @@ export class ModelRegistry {
|
|
|
1272
1316
|
fetch: this.#fetch,
|
|
1273
1317
|
getBearerApiKeyResolver: async provider => {
|
|
1274
1318
|
const apiKey = await this.getApiKeyForProvider(provider);
|
|
1275
|
-
if (!apiKey
|
|
1319
|
+
if (!isDiscoveryBearerApiKey(apiKey)) {
|
|
1320
|
+
return undefined;
|
|
1321
|
+
}
|
|
1276
1322
|
return this.resolver(provider);
|
|
1277
1323
|
},
|
|
1278
1324
|
};
|
|
@@ -1377,11 +1423,20 @@ export class ModelRegistry {
|
|
|
1377
1423
|
for (let i = 0; i < standardProviderDescriptors.length; i++) {
|
|
1378
1424
|
const descriptor = standardProviderDescriptors[i];
|
|
1379
1425
|
const apiKey = standardProviderKeys[i];
|
|
1380
|
-
|
|
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);
|
|
1381
1436
|
options.push(
|
|
1382
1437
|
descriptor.createModelManagerOptions({
|
|
1383
|
-
apiKey:
|
|
1384
|
-
baseUrl:
|
|
1438
|
+
apiKey: isDiscoveryBearerApiKey(apiKey) ? apiKey : undefined,
|
|
1439
|
+
baseUrl: discoveryBaseUrl,
|
|
1385
1440
|
fetch: this.#fetch,
|
|
1386
1441
|
}),
|
|
1387
1442
|
);
|
|
@@ -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
|
}
|