@phi-code-admin/phi-code 0.76.14 → 0.76.16
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/extensions/phi/init.ts
CHANGED
|
@@ -23,6 +23,7 @@ import { join, resolve } from "node:path";
|
|
|
23
23
|
import { homedir } from "node:os";
|
|
24
24
|
import { existsSync } from "node:fs";
|
|
25
25
|
import { fetchLiveModels, pingProvider, toPersistedModel } from "./providers/live-models.js";
|
|
26
|
+
import { isOpenCodeGoAnthropicModel, OPENCODE_GO_ANTHROPIC_BASE_URL } from "./providers/opencode-go.js";
|
|
26
27
|
|
|
27
28
|
// ─── Types ───────────────────────────────────────────────────────────────
|
|
28
29
|
|
|
@@ -387,6 +388,24 @@ _Edit this file to customize Phi Code's behavior for your project._
|
|
|
387
388
|
await writeModelsConfig(config);
|
|
388
389
|
}
|
|
389
390
|
|
|
391
|
+
// OpenCode Go's Qwen/MiniMax models must be persisted under a separate
|
|
392
|
+
// Anthropic-compatible provider (the OpenAI shim 401s them).
|
|
393
|
+
async function persistOpenCodeGoAnthropic(
|
|
394
|
+
apiKey: string,
|
|
395
|
+
models: ReturnType<typeof toPersistedModel>[],
|
|
396
|
+
): Promise<void> {
|
|
397
|
+
const config = await readModelsConfig();
|
|
398
|
+
const existing = config.providers["opencode-go-anthropic"] ?? {};
|
|
399
|
+
config.providers["opencode-go-anthropic"] = {
|
|
400
|
+
...existing,
|
|
401
|
+
baseUrl: OPENCODE_GO_ANTHROPIC_BASE_URL,
|
|
402
|
+
api: "anthropic-messages",
|
|
403
|
+
apiKey,
|
|
404
|
+
models,
|
|
405
|
+
};
|
|
406
|
+
await writeModelsConfig(config);
|
|
407
|
+
}
|
|
408
|
+
|
|
390
409
|
// ─── Manual model assignment (one model per orchestration role) ─────
|
|
391
410
|
//
|
|
392
411
|
// As of 0.75.6, `/phi-init` ONLY configures orchestration role models
|
|
@@ -519,7 +538,24 @@ _Edit this file to customize Phi Code's behavior for your project._
|
|
|
519
538
|
|
|
520
539
|
const persistedModels = live.models.map(toPersistedModel);
|
|
521
540
|
try {
|
|
522
|
-
|
|
541
|
+
if (provider.id === "opencode-go") {
|
|
542
|
+
// Qwen/MiniMax are only served via the Anthropic-compatible endpoint;
|
|
543
|
+
// GLM/Kimi/DeepSeek/Mimo/Hy3 use the OpenAI shim. Persist them as two
|
|
544
|
+
// providers so neither family hits a "not supported for format" 401.
|
|
545
|
+
const openaiModels = persistedModels.filter((m) => !isOpenCodeGoAnthropicModel(m.id));
|
|
546
|
+
const anthropicModels = persistedModels.filter((m) => isOpenCodeGoAnthropicModel(m.id));
|
|
547
|
+
provider.models = openaiModels.map((m) => m.id);
|
|
548
|
+
await persistProviderModels(provider, openaiModels);
|
|
549
|
+
if (anthropicModels.length > 0) {
|
|
550
|
+
await persistOpenCodeGoAnthropic(trimmed, anthropicModels);
|
|
551
|
+
ctx.ui.notify(
|
|
552
|
+
`OpenCode Go: ${anthropicModels.length} Qwen/MiniMax model(s) routed via the Anthropic-compatible provider \`opencode-go-anthropic\` (assign them with \`/plan-models\` or \`/model\`).`,
|
|
553
|
+
"info",
|
|
554
|
+
);
|
|
555
|
+
}
|
|
556
|
+
} else {
|
|
557
|
+
await persistProviderModels(provider, persistedModels);
|
|
558
|
+
}
|
|
523
559
|
} catch (err) {
|
|
524
560
|
ctx.ui.notify(
|
|
525
561
|
`Failed to write provider models to ${modelsJsonPath}: ${err instanceof Error ? err.message : String(err)}`,
|
|
@@ -23,6 +23,10 @@ export const OPENCODE_GO_AUTH_URL = "https://opencode.ai/auth";
|
|
|
23
23
|
export const OPENCODE_GO_MODELS_URL = "https://opencode.ai/zen/go/v1/models";
|
|
24
24
|
export const OPENCODE_GO_OPENAI_URL = "https://opencode.ai/zen/go/v1/chat/completions";
|
|
25
25
|
export const OPENCODE_GO_ANTHROPIC_URL = "https://opencode.ai/zen/go/v1/messages";
|
|
26
|
+
// Base URL for the Anthropic SDK (which appends "/v1/messages"). Qwen and
|
|
27
|
+
// MiniMax models on OpenCode Go are ONLY served via this Anthropic-compatible
|
|
28
|
+
// endpoint; the OpenAI shim returns 401 "not supported for format oa-compat".
|
|
29
|
+
export const OPENCODE_GO_ANTHROPIC_BASE_URL = "https://opencode.ai/zen/go";
|
|
26
30
|
|
|
27
31
|
export interface OpenCodeGoModel {
|
|
28
32
|
id: string;
|
|
@@ -184,19 +188,50 @@ export async function pingOpenCodeGo(apiKey: string, timeoutMs = 5_000): Promise
|
|
|
184
188
|
* when the user wants to override defaults (e.g., add a new model
|
|
185
189
|
* not yet in models.generated.ts).
|
|
186
190
|
*/
|
|
191
|
+
/**
|
|
192
|
+
* On OpenCode Go, Qwen and MiniMax models are only served via the Anthropic-
|
|
193
|
+
* compatible Messages endpoint (/v1/messages); GLM, Kimi, DeepSeek, Mimo and Hy3
|
|
194
|
+
* use the OpenAI-compatible shim (/v1/chat/completions). Calling a Qwen/MiniMax
|
|
195
|
+
* model through the OpenAI format yields a 401 "not supported for format oa-compat".
|
|
196
|
+
*/
|
|
197
|
+
export function isOpenCodeGoAnthropicModel(id: string): boolean {
|
|
198
|
+
return /^(qwen|minimax)/i.test(id);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function toPersistedOpenCodeGoModel(m: OpenCodeGoModel) {
|
|
202
|
+
return {
|
|
203
|
+
id: m.id,
|
|
204
|
+
name: m.name ?? m.id,
|
|
205
|
+
reasoning: true,
|
|
206
|
+
input: ["text"] as const,
|
|
207
|
+
contextWindow: m.contextWindow ?? 128_000,
|
|
208
|
+
maxTokens: m.maxTokens ?? 16_384,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* OpenAI-compatible provider entry (GLM / Kimi / DeepSeek / Mimo / Hy3).
|
|
214
|
+
* Qwen/MiniMax are intentionally excluded — see buildOpenCodeGoAnthropicProviderConfig.
|
|
215
|
+
*/
|
|
187
216
|
export function buildOpenCodeGoProviderConfig(apiKey: string, models: OpenCodeGoModel[]) {
|
|
188
217
|
return {
|
|
189
218
|
baseUrl: "https://opencode.ai/zen/go/v1",
|
|
190
219
|
api: "openai-completions" as const,
|
|
191
220
|
apiKey,
|
|
192
|
-
models: models.
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
221
|
+
models: models.filter((m) => !isOpenCodeGoAnthropicModel(m.id)).map(toPersistedOpenCodeGoModel),
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Anthropic-compatible provider entry for OpenCode Go's Qwen / MiniMax models.
|
|
227
|
+
* `models` is empty when the list contains none.
|
|
228
|
+
*/
|
|
229
|
+
export function buildOpenCodeGoAnthropicProviderConfig(apiKey: string, models: OpenCodeGoModel[]) {
|
|
230
|
+
return {
|
|
231
|
+
baseUrl: OPENCODE_GO_ANTHROPIC_BASE_URL,
|
|
232
|
+
api: "anthropic-messages" as const,
|
|
233
|
+
apiKey,
|
|
234
|
+
models: models.filter((m) => isOpenCodeGoAnthropicModel(m.id)).map(toPersistedOpenCodeGoModel),
|
|
200
235
|
};
|
|
201
236
|
}
|
|
202
237
|
|
package/extensions/phi/setup.ts
CHANGED
|
@@ -35,6 +35,7 @@ import {
|
|
|
35
35
|
import {
|
|
36
36
|
OPENCODE_GO_AUTH_URL,
|
|
37
37
|
OPENCODE_GO_ENV_VAR,
|
|
38
|
+
buildOpenCodeGoAnthropicProviderConfig,
|
|
38
39
|
buildOpenCodeGoProviderConfig,
|
|
39
40
|
getOpenCodeGoModels,
|
|
40
41
|
pingOpenCodeGo,
|
|
@@ -385,8 +386,20 @@ async function configureOpenCodeGo(
|
|
|
385
386
|
models: config.models,
|
|
386
387
|
});
|
|
387
388
|
|
|
389
|
+
// Qwen / MiniMax are only served via the Anthropic-compatible endpoint on
|
|
390
|
+
// OpenCode Go, so they go to a separate provider (the OpenAI shim 401s them).
|
|
391
|
+
const anthConfig = buildOpenCodeGoAnthropicProviderConfig(trimmed, models);
|
|
392
|
+
if (anthConfig.models.length > 0) {
|
|
393
|
+
store.setKey("opencode-go-anthropic", trimmed, {
|
|
394
|
+
baseUrl: anthConfig.baseUrl,
|
|
395
|
+
api: anthConfig.api,
|
|
396
|
+
models: anthConfig.models,
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
|
|
388
400
|
ui.notify(
|
|
389
|
-
`OpenCode Go configured: \`${maskKeyForDisplay(trimmed)}\`
|
|
401
|
+
`OpenCode Go configured: \`${maskKeyForDisplay(trimmed)}\` ` +
|
|
402
|
+
`(${config.models.length} OpenAI-compat + ${anthConfig.models.length} Anthropic-compat models)`,
|
|
390
403
|
"info",
|
|
391
404
|
);
|
|
392
405
|
return { providerId: "opencode-go", modelCount: models.length };
|