fix(opencode-go): route every responses-only model (incl. thinking variants) to /responses
Derive responses-only routing from the model registry's targetFormat instead of hardcoding model checks, and strip thinking suffixes when looking up models in providerModels so variants like gpt-5.6-luna(high) are routed correctly to /responses.
This commit is contained in:
@@ -27,11 +27,14 @@ const DOT_VERSION_PROVIDERS = new Set(["kr", "kiro"]);
|
|||||||
// ("claude-sonnet-4-5" ~= "claude-sonnet-4.5"). Other providers use exact match only.
|
// ("claude-sonnet-4-5" ~= "claude-sonnet-4.5"). Other providers use exact match only.
|
||||||
function findModel(models, modelId, aliasOrId) {
|
function findModel(models, modelId, aliasOrId) {
|
||||||
if (!models) return undefined;
|
if (!models) return undefined;
|
||||||
const found = models.find(m => m.id === modelId);
|
const baseModelId = typeof modelId === "string"
|
||||||
|
? modelId.replace(/\([^()]+\)\s*$/, "").trim()
|
||||||
|
: modelId;
|
||||||
|
const found = models.find(m => m.id === modelId || m.id === baseModelId);
|
||||||
if (found) return found;
|
if (found) return found;
|
||||||
if (!DOT_VERSION_PROVIDERS.has(aliasOrId)) return undefined;
|
if (!DOT_VERSION_PROVIDERS.has(aliasOrId)) return undefined;
|
||||||
const normalized = normalizeModelId(modelId);
|
const normalized = normalizeModelId(baseModelId);
|
||||||
if (normalized === modelId) return undefined;
|
if (normalized === baseModelId) return undefined;
|
||||||
return models.find(m => m.id === normalized);
|
return models.find(m => m.id === normalized);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import crypto from "node:crypto";
|
import crypto from "node:crypto";
|
||||||
import { DefaultExecutor } from "./default.js";
|
import { DefaultExecutor } from "./default.js";
|
||||||
import { resolveSessionId } from "../utils/sessionManager.js";
|
import { resolveSessionId } from "../utils/sessionManager.js";
|
||||||
import { isMuseSparkModel } from "../providers/models/helpers.js";
|
import { modelTargetFormat } from "../providers/models/schema.js";
|
||||||
|
import { getProviderModels } from "../config/providerModels.js";
|
||||||
import {
|
import {
|
||||||
normalizeResponsesInput,
|
normalizeResponsesInput,
|
||||||
clampResponsesCallId,
|
clampResponsesCallId,
|
||||||
@@ -45,8 +46,11 @@ function baseModelId(model) {
|
|||||||
return String(model || "").replace(/\([^()]+\)\s*$/, "").trim();
|
return String(model || "").replace(/\([^()]+\)\s*$/, "").trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Responses-only per the provider registry (grok-4.6, gpt-5.6-luna, muse-spark, …).
|
||||||
|
// Reading the registry keeps this in sync with config — never hardcode model ids here.
|
||||||
function isResponsesModel(model) {
|
function isResponsesModel(model) {
|
||||||
return isMuseSparkModel(baseModelId(model));
|
const entry = getProviderModels("opencode-go").find((m) => m.id === baseModelId(model));
|
||||||
|
return modelTargetFormat(entry) === "openai-responses";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flatten Chat Completions tool declarations into the Responses flat shape and
|
// Flatten Chat Completions tool declarations into the Responses flat shape and
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import { PROVIDER_MODELS, getModelSupportedFormats } from "../../open-sse/config/providerModels.js";
|
import { PROVIDER_MODELS, getModelSupportedFormats, getModelTargetFormat } from "../../open-sse/config/providerModels.js";
|
||||||
import { PROVIDERS } from "../../open-sse/config/providers.js";
|
import { PROVIDERS } from "../../open-sse/config/providers.js";
|
||||||
import { resolveTransport } from "../../open-sse/services/provider.js";
|
import { resolveTransport } from "../../open-sse/services/provider.js";
|
||||||
|
|
||||||
@@ -37,6 +37,18 @@ describe("OpenCode Go model catalog", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("OpenCode Go thinking-suffix model lookup", () => {
|
||||||
|
it("preserves Responses routing for gpt-5.6-luna thinking variants", () => {
|
||||||
|
expect(getModelSupportedFormats("opencode-go", "gpt-5.6-luna(high)")).toEqual(["openai-responses"]);
|
||||||
|
expect(getModelTargetFormat("opencode-go", "gpt-5.6-luna(high)")).toBe("openai-responses");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("preserves Responses routing for grok-4.6 thinking variants", () => {
|
||||||
|
expect(getModelSupportedFormats("opencode-go", "grok-4.6(high)")).toEqual(["openai-responses"]);
|
||||||
|
expect(getModelTargetFormat("opencode-go", "grok-4.6(high)")).toBe("openai-responses");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("OpenCode Go per-model supportedFormats", () => {
|
describe("OpenCode Go per-model supportedFormats", () => {
|
||||||
it("declares [openai, claude] for MiniMax + Qwen models", () => {
|
it("declares [openai, claude] for MiniMax + Qwen models", () => {
|
||||||
for (const m of CLAUDE_CAPABLE) {
|
for (const m of CLAUDE_CAPABLE) {
|
||||||
|
|||||||
@@ -48,6 +48,22 @@ describe("ocg/muse-spark-1.3-contributor catalog", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("OpenCodeGoExecutor routing + sanitization", () => {
|
describe("OpenCodeGoExecutor routing + sanitization", () => {
|
||||||
|
it("routes gpt-5.6-luna to /responses", () => {
|
||||||
|
const ex = new OpenCodeGoExecutor();
|
||||||
|
expect(ex.buildUrl("gpt-5.6-luna")).toBe("https://opencode.ai/zen/go/v1/responses");
|
||||||
|
expect(ex.buildUrl("gpt-5.6-luna(high)", true, 0, {
|
||||||
|
runtimeTransport: { baseUrl: "https://opencode.ai/zen/go/v1/chat/completions" },
|
||||||
|
})).toBe("https://opencode.ai/zen/go/v1/responses");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("routes every responses-only registry model (grok-4.6) to /responses", () => {
|
||||||
|
const ex = new OpenCodeGoExecutor();
|
||||||
|
expect(ex.buildUrl("grok-4.6")).toBe("https://opencode.ai/zen/go/v1/responses");
|
||||||
|
expect(ex.buildUrl("grok-4.6(high)", true, 0, {
|
||||||
|
runtimeTransport: { baseUrl: "https://opencode.ai/zen/go/v1/chat/completions" },
|
||||||
|
})).toBe("https://opencode.ai/zen/go/v1/responses");
|
||||||
|
});
|
||||||
|
|
||||||
it("is wired for opencode-go and routes muse-spark to /responses", () => {
|
it("is wired for opencode-go and routes muse-spark to /responses", () => {
|
||||||
expect(getExecutor("opencode-go")).toBeInstanceOf(OpenCodeGoExecutor);
|
expect(getExecutor("opencode-go")).toBeInstanceOf(OpenCodeGoExecutor);
|
||||||
const ex = new OpenCodeGoExecutor();
|
const ex = new OpenCodeGoExecutor();
|
||||||
|
|||||||
Reference in New Issue
Block a user