mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
fix(ai): move OpenCode providers to inference endpoints
- Use opencode.ai/inference and opencode.ai/inference/go base URLs; /zen/go has no Gemini route (404) - Add google-generative-ai support to the OpenCode Go provider - Use Anthropic Messages for OpenCode Go minimax-m2.7; openai-completions now returns ModelProtocolUnsupported - Remove test for opencode-go deepseek-v4-flash, which is no longer listed
This commit is contained in:
parent
39294a5e95
commit
195120a915
5 changed files with 17 additions and 24 deletions
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
- Fixed tool-call argument parsing dropping fields when a string contains an invalid `\u` escape such as `\usepackage` ([#10868](https://github.com/earendil-works/pi/issues/10868))
|
||||
- Fixed Anthropic requests failing with a 400 when an error tool result contains images; the images are now replaced with a text note ([#10794](https://github.com/earendil-works/pi/issues/10794))
|
||||
- Fixed OpenCode Go Gemini models failing with a 404 by moving OpenCode Zen and OpenCode Go to the `opencode.ai/inference` endpoints, and added Google Generative AI support to the OpenCode Go provider
|
||||
- Fixed OpenCode Go MiniMax M2.7 failing with "Model does not support this protocol" by using the Anthropic Messages API
|
||||
|
||||
## [1.2.0] - 2026-10-12
|
||||
|
||||
|
|
|
|||
|
|
@ -2159,8 +2159,8 @@ async function loadModelsDevData(): Promise<Model<any>[]> {
|
|||
// - @ai-sdk/google → google-generative-ai
|
||||
// - null/undefined/@ai-sdk/openai-compatible → openai-completions
|
||||
const opencodeVariants = [
|
||||
{ key: "opencode", provider: "opencode", basePath: "https://opencode.ai/zen" },
|
||||
{ key: "opencode-go", provider: "opencode-go", basePath: "https://opencode.ai/zen/go" },
|
||||
{ key: "opencode", provider: "opencode", basePath: "https://opencode.ai/inference" },
|
||||
{ key: "opencode-go", provider: "opencode-go", basePath: "https://opencode.ai/inference/go" },
|
||||
] as const;
|
||||
|
||||
for (const variant of opencodeVariants) {
|
||||
|
|
@ -2209,16 +2209,9 @@ async function loadModelsDevData(): Promise<Model<any>[]> {
|
|||
|
||||
// Fix known mismatches between models.dev npm data and actual
|
||||
// OpenCode Go endpoint behaviour. models.dev reports these models
|
||||
// as @ai-sdk/anthropic, but the OpenCode Go endpoints either don't
|
||||
// accept Anthropic SDK auth (MiniMax M2.7) or are served through
|
||||
// the OpenAI-compatible /v1/chat/completions path (Qwen 3.5/3.6).
|
||||
// Switch them to openai-completions so requests use Bearer auth
|
||||
// and the standard /v1/chat/completions endpoint.
|
||||
// as @ai-sdk/anthropic, but OpenCode Go serves them through the
|
||||
// OpenAI-compatible /v1/chat/completions path.
|
||||
if (variant.provider === "opencode-go") {
|
||||
if (modelId === "minimax-m2.7") {
|
||||
api = "openai-completions";
|
||||
baseUrl = `${variant.basePath}/v1`;
|
||||
}
|
||||
if (modelId === "qwen3.5-plus" || modelId === "qwen3.6-plus") {
|
||||
api = "openai-completions";
|
||||
baseUrl = `${variant.basePath}/v1`;
|
||||
|
|
@ -2619,7 +2612,7 @@ async function loadModelsDevClassifierModels(): Promise<ClassifierModel<"typesaf
|
|||
// System One models yet. Cloudflare publishes pricing only in the dashboard.
|
||||
// https://developers.cloudflare.com/ai/models/typesafe/jev/
|
||||
// OpenCode Zen serves Jev through its TypeSafe-compatible System One endpoint.
|
||||
// Neither its /zen/v1/models listing nor models.dev carries metadata for it.
|
||||
// Neither its /inference/v1/models listing nor models.dev carries metadata for it.
|
||||
// https://opencode.ai/docs/zen
|
||||
const OPENCODE_CLASSIFIER_MODELS: ClassifierModel<"typesafe-system-one">[] = [
|
||||
{
|
||||
|
|
@ -2628,7 +2621,7 @@ const OPENCODE_CLASSIFIER_MODELS: ClassifierModel<"typesafe-system-one">[] = [
|
|||
name: "Jev 1.13",
|
||||
api: "typesafe-system-one",
|
||||
provider: "opencode",
|
||||
baseUrl: "https://opencode.ai/zen/v1",
|
||||
baseUrl: "https://opencode.ai/inference/v1",
|
||||
input: ["text"],
|
||||
cost: { input: 0.042, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: 32000,
|
||||
|
|
@ -2639,7 +2632,7 @@ const OPENCODE_CLASSIFIER_MODELS: ClassifierModel<"typesafe-system-one">[] = [
|
|||
name: "Jev 1.13 Free",
|
||||
api: "typesafe-system-one",
|
||||
provider: "opencode",
|
||||
baseUrl: "https://opencode.ai/zen/v1",
|
||||
baseUrl: "https://opencode.ai/inference/v1",
|
||||
input: ["text"],
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: 32000,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { anthropicMessagesApi } from "../api/anthropic-messages.lazy.ts";
|
||||
import { googleGenerativeAIApi } from "../api/google-generative-ai.lazy.ts";
|
||||
import { openAICompletionsApi } from "../api/openai-completions.lazy.ts";
|
||||
import { openAIResponsesApi } from "../api/openai-responses.lazy.ts";
|
||||
import { envApiKeyAuth } from "../auth/helpers.ts";
|
||||
|
|
@ -6,14 +7,17 @@ import { createProvider, type Provider } from "../models.ts";
|
|||
import { OPENCODE_GO_MODELS } from "./opencode-go.models.ts";
|
||||
import { withOpenCodeSessionHeader } from "./opencode-headers.ts";
|
||||
|
||||
export function opencodeGoProvider(): Provider<"anthropic-messages" | "openai-completions" | "openai-responses"> {
|
||||
return createProvider<"anthropic-messages" | "openai-completions" | "openai-responses">({
|
||||
type OpenCodeGoApi = "anthropic-messages" | "google-generative-ai" | "openai-completions" | "openai-responses";
|
||||
|
||||
export function opencodeGoProvider(): Provider<OpenCodeGoApi> {
|
||||
return createProvider<OpenCodeGoApi>({
|
||||
id: "opencode-go",
|
||||
name: "OpenCode Go",
|
||||
auth: { apiKey: envApiKeyAuth("OpenCode API key", ["OPENCODE_API_KEY"]) },
|
||||
models: Object.values(OPENCODE_GO_MODELS),
|
||||
api: {
|
||||
"anthropic-messages": withOpenCodeSessionHeader(anthropicMessagesApi()),
|
||||
"google-generative-ai": withOpenCodeSessionHeader(googleGenerativeAIApi()),
|
||||
"openai-completions": withOpenCodeSessionHeader(openAICompletionsApi()),
|
||||
"openai-responses": withOpenCodeSessionHeader(openAIResponsesApi()),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -130,8 +130,8 @@ describe("Models with classifier models", () => {
|
|||
|
||||
it.each([
|
||||
["vercel-ai-gateway", "typesafe-ai/jev", "https://ai-gateway.vercel.sh/typesafe/v1/systemone"],
|
||||
["opencode", "jev-1.13", "https://opencode.ai/zen/v1/systemone"],
|
||||
["opencode", "jev-1.13-free", "https://opencode.ai/zen/v1/systemone"],
|
||||
["opencode", "jev-1.13", "https://opencode.ai/inference/v1/systemone"],
|
||||
["opencode", "jev-1.13-free", "https://opencode.ai/inference/v1/systemone"],
|
||||
])("routes %s Jev (%s) to its TypeSafe-compatible endpoint", async (provider, id, url) => {
|
||||
const models = builtinModels();
|
||||
const jev = models.getModelOfType("classifier", provider, id);
|
||||
|
|
|
|||
|
|
@ -175,12 +175,6 @@ describe("getSupportedThinkingLevels", () => {
|
|||
expect(getSupportedThinkingLevels(model!)).toEqual(["off", "low", "high", "max"]);
|
||||
});
|
||||
|
||||
it("includes low/high/max plus off for DeepSeek V4 Flash on opencode-go", () => {
|
||||
const model = getModel("opencode-go", "deepseek-v4-flash");
|
||||
expect(model).toBeDefined();
|
||||
expect(getSupportedThinkingLevels(model!)).toEqual(["off", "low", "high", "max"]);
|
||||
});
|
||||
|
||||
it("preserves low/high/max metadata for DeepSeek V4.1 Flash on OpenRouter", () => {
|
||||
const model = getModel("openrouter", "deepseek/deepseek-v4.1-flash");
|
||||
expect(model).toBeDefined();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue