feat(opencode-go): complete Go catalog (40 models) with auto-fetch + family endpoint regex

- Add 12 missing models from live /zen/go/v1/models (glm-5, kimi-k2.5,
  mimo v2/v2.6 line, qwen3.5-plus, grok-4.5/4.7, omen-alpha, ...)
- modelsFetcher + passthroughModels + "opencode-go" suggested-models filter
- Family regex fallback (opencodeFamilyFormats) keeps unknown/passthrough ids
  on the right endpoint lane (/responses, /messages, /chat/completions);
  curated registry entries always win
- isResponsesModel now routes passthrough grok/gpt ids to /responses

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
decolua
2026-09-23 11:45:34 +07:00
parent 39e36d3d0c
commit 2aa99d9f39
6 changed files with 100 additions and 26 deletions

View File

@@ -4,11 +4,12 @@ import { PROVIDERS } from "../../open-sse/config/providers.js";
import { resolveTransport } from "../../open-sse/services/provider.js";
// Chat-only models (no /messages, no /responses support on opencode-go)
const CHAT_ONLY = ["glm-5.3", "glm-5.2", "glm-5.1", "kimi-k2.7-code", "kimi-k2.6", "kimi-k3",
"deepseek-flash", "longcat-2.0", "mimo-v2.5", "mimo-v2.5-pro", "hy4-preview", "hy3"];
const CHAT_ONLY = ["glm-5.3", "glm-5.2", "glm-5.1", "glm-5", "kimi-k2.7-code", "kimi-k2.6", "kimi-k2.5", "kimi-k3",
"deepseek-flash", "deepseek-v4.1-flash", "longcat-2.0", "mimo-v2.6-flash", "mimo-v2.6-pro",
"mimo-v2.5", "mimo-v2.5-pro", "mimo-v2-pro", "mimo-v2-omni", "hy4-preview", "hy3", "hy3-preview", "omen-alpha"];
// Models that also expose the Anthropic /messages endpoint
const CLAUDE_CAPABLE = ["minimax-m3", "minimax-m2.7", "minimax-m2.5",
"qwen3.8-max", "qwen3.8-flash", "qwen3.7-max", "qwen3.7-plus", "qwen3.6-plus"];
"qwen3.8-max", "qwen3.8-flash", "qwen3.7-max", "qwen3.7-plus", "qwen3.6-plus", "qwen3.5-plus"];
// Models that also expose the OpenAI /responses endpoint
const RESPONSES_CAPABLE = ["deepseek-v4-pro", "deepseek-v4-flash"];
@@ -25,18 +26,42 @@ describe("OpenCode Go model catalog", () => {
const ids = (PROVIDER_MODELS["opencode-go"] || []).map((m) => m.id);
expect(ids).toEqual([
"deepseek-flash",
"glm-5.3-flash", "glm-5.3", "glm-5.2", "glm-5.1", "kimi-k2.7-code", "kimi-k2.6", "kimi-k3",
"deepseek-v4-pro", "deepseek-v4-flash", "deepseek-v4-flash-vision-exp",
"longcat-2.0", "mimo-v2.5", "mimo-v2.5-pro",
"glm-5.3-flash", "glm-5.3", "glm-5.2", "glm-5.1", "glm-5", "kimi-k2.7-code", "kimi-k2.6", "kimi-k2.5", "kimi-k3",
"deepseek-v4-pro", "deepseek-v4-flash", "deepseek-v4-flash-vision-exp", "deepseek-v4.1-flash",
"longcat-2.0", "mimo-v2.6-flash", "mimo-v2.6-pro", "mimo-v2.5", "mimo-v2.5-pro", "mimo-v2-pro", "mimo-v2-omni",
"minimax-m3", "minimax-m2.7", "minimax-m2.5",
"qwen3.8-max", "qwen3.8-flash", "qwen3.7-max", "qwen3.7-plus", "qwen3.6-plus",
"hy4-preview", "hy3",
"grok-4.6", "gpt-5.6-luna",
"qwen3.8-max", "qwen3.8-flash", "qwen3.7-max", "qwen3.7-plus", "qwen3.6-plus", "qwen3.5-plus",
"hy4-preview", "hy3", "hy3-preview", "omen-alpha",
"grok-4.7", "grok-4.6", "grok-4.5", "gpt-5.6-luna",
"muse-spark-1.2-contributor", "muse-spark-1.3-contributor",
]);
});
});
describe("OpenCode Go family fallback (unknown/passthrough ids)", () => {
it("routes unknown grok/gpt ids to the responses lane", () => {
expect(getModelSupportedFormats("opencode-go", "grok-4.8")).toEqual(["openai-responses"]);
expect(getModelTargetFormat("opencode-go", "gpt-6-foo")).toBe("openai-responses");
});
it("gives unknown chat-family ids the chat-only lane, never /messages", () => {
for (const m of ["kimi-k4", "glm-6", "mimo-v3", "omen-beta"]) {
expect(getModelSupportedFormats("opencode-go", m)).toEqual(["openai"]);
}
});
it("keeps unknown minimax/qwen ids on the /messages lane too", () => {
for (const m of ["minimax-m9", "qwen4-max"]) {
expect(getModelSupportedFormats("opencode-go", m)).toEqual(["openai", "claude"]);
}
});
it("curated entries win over the family regex", () => {
expect(getModelSupportedFormats("opencode-go", "deepseek-v4.1-flash")).toEqual(["openai"]);
expect(getModelSupportedFormats("opencode-go", "deepseek-v4-pro")).toEqual(["openai", "claude", "openai-responses"]);
});
});
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"]);
@@ -108,7 +133,7 @@ describe("OpenCode Go per-model transport guard (chatCore logic)", () => {
});
it("routes Muse Spark (responses-only) to /responses, never to /messages", () => {
for (const m of ["muse-spark-1.2-contributor", "muse-spark-1.3-contributor", "grok-4.6", "gpt-5.6-luna"]) {
for (const m of ["muse-spark-1.2-contributor", "muse-spark-1.3-contributor", "grok-4.7", "grok-4.6", "grok-4.5", "gpt-5.6-luna"]) {
expect(getModelSupportedFormats("opencode-go", m)).toEqual(["openai-responses"]);
expect(pickTransport("opencode-go", "openai-responses", "opencode-go", m)?.baseUrl).toBe("https://opencode.ai/zen/go/v1/responses");
expect(pickTransport("opencode-go", "claude", "opencode-go", m)).toBeNull();