Merge branch 'feat/opencode-go-models'
feat(opencode-go): add newly published Go models fix(codex): restore Version header and single-source the CLI version
This commit is contained in:
@@ -7,6 +7,9 @@ import { createRequire } from "module";
|
|||||||
export const GEMINI_CLI_VERSION = PROVIDERS["gemini-cli"]?.cliVersion;
|
export const GEMINI_CLI_VERSION = PROVIDERS["gemini-cli"]?.cliVersion;
|
||||||
export const GEMINI_CLI_API_CLIENT = PROVIDERS["gemini-cli"]?.apiClient;
|
export const GEMINI_CLI_API_CLIENT = PROVIDERS["gemini-cli"]?.apiClient;
|
||||||
|
|
||||||
|
// === Codex CLI === derive từ registry codex.transport
|
||||||
|
export const CODEX_CLI_VERSION = PROVIDERS["codex"]?.cliVersion;
|
||||||
|
|
||||||
// Map Node arch to Gemini CLI arch string (x64/x86/arm64/...)
|
// Map Node arch to Gemini CLI arch string (x64/x86/arm64/...)
|
||||||
function geminiCLIArch() {
|
function geminiCLIArch() {
|
||||||
const a = arch();
|
const a = arch();
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
import { randomUUID } from "node:crypto";
|
import { randomUUID } from "node:crypto";
|
||||||
import { nowSec } from "./_base.js";
|
import { nowSec } from "./_base.js";
|
||||||
import { PROVIDERS } from "../../config/providers.js";
|
import { PROVIDERS } from "../../config/providers.js";
|
||||||
|
import { CODEX_CLI_VERSION } from "../../config/appConstants.js";
|
||||||
|
|
||||||
const CODEX_RESPONSES_URL = PROVIDERS["codex"].baseUrl;
|
const CODEX_RESPONSES_URL = PROVIDERS["codex"].baseUrl;
|
||||||
const CODEX_USER_AGENT = "codex_cli_rs/0.136.0";
|
const CODEX_USER_AGENT = `codex_cli_rs/${CODEX_CLI_VERSION}`;
|
||||||
const CODEX_VERSION = "0.136.0";
|
|
||||||
const CODEX_ORIGINATOR = "codex_cli_rs";
|
const CODEX_ORIGINATOR = "codex_cli_rs";
|
||||||
const CODEX_MODEL_SUFFIX = "-image";
|
const CODEX_MODEL_SUFFIX = "-image";
|
||||||
const CODEX_REF_DETAIL = "high";
|
const CODEX_REF_DETAIL = "high";
|
||||||
@@ -157,7 +157,7 @@ export default {
|
|||||||
"originator": CODEX_ORIGINATOR,
|
"originator": CODEX_ORIGINATOR,
|
||||||
"session_id": randomUUID(),
|
"session_id": randomUUID(),
|
||||||
"user-agent": CODEX_USER_AGENT,
|
"user-agent": CODEX_USER_AGENT,
|
||||||
"version": CODEX_VERSION,
|
"version": CODEX_CLI_VERSION,
|
||||||
"x-client-request-id": randomUUID(),
|
"x-client-request-id": randomUUID(),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
import { withCodexReviewModels } from "../models/helpers.js";
|
import { withCodexReviewModels } from "../models/helpers.js";
|
||||||
|
|
||||||
|
// Codex CLI version seen by OpenAI's backend — single source for the Version /
|
||||||
|
// User-Agent identity headers. Bump when the installed codex CLI is upgraded.
|
||||||
|
const CODEX_CLI_VERSION = "0.154.0";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
id: "codex",
|
id: "codex",
|
||||||
priority: 30,
|
priority: 30,
|
||||||
@@ -34,9 +38,10 @@ export default {
|
|||||||
baseUrl: "https://chatgpt.com/backend-api/codex/responses",
|
baseUrl: "https://chatgpt.com/backend-api/codex/responses",
|
||||||
format: "openai-responses",
|
format: "openai-responses",
|
||||||
forceStream: true,
|
forceStream: true,
|
||||||
|
cliVersion: CODEX_CLI_VERSION,
|
||||||
headers: {
|
headers: {
|
||||||
originator: "codex_cli_rs",
|
originator: "codex_cli_rs",
|
||||||
"User-Agent": "codex_cli_rs/0.136.0",
|
"User-Agent": `codex_cli_rs/${CODEX_CLI_VERSION}`,
|
||||||
},
|
},
|
||||||
usage: {
|
usage: {
|
||||||
url: "https://chatgpt.com/backend-api/wham/usage",
|
url: "https://chatgpt.com/backend-api/wham/usage",
|
||||||
|
|||||||
@@ -33,25 +33,36 @@ export default {
|
|||||||
{ format: "claude", baseUrl: "https://opencode.ai/zen/go/v1/messages", auth: { combined: true, header: "x-api-key", scheme: "raw", anthropicVersion: true } },
|
{ format: "claude", baseUrl: "https://opencode.ai/zen/go/v1/messages", auth: { combined: true, header: "x-api-key", scheme: "raw", anthropicVersion: true } },
|
||||||
{ format: "openai-responses", baseUrl: "https://opencode.ai/zen/go/v1/responses", auth: { combined: true, header: "Authorization", scheme: "bearer" } },
|
{ format: "openai-responses", baseUrl: "https://opencode.ai/zen/go/v1/responses", auth: { combined: true, header: "Authorization", scheme: "bearer" } },
|
||||||
],
|
],
|
||||||
|
// supportedFormats follow the endpoint table in https://opencode.ai/docs/go/
|
||||||
models: [
|
models: [
|
||||||
{ id: "glm-5.3-flash", name: "GLM 5.3 Flash (Vision)", supportedFormats: ["openai"] },
|
{ id: "glm-5.3-flash", name: "GLM 5.3 Flash (Vision)", supportedFormats: ["openai"] },
|
||||||
|
{ id: "glm-5.3", name: "GLM 5.3", supportedFormats: ["openai"] },
|
||||||
{ id: "glm-5.2", name: "GLM 5.2", supportedFormats: ["openai"] },
|
{ id: "glm-5.2", name: "GLM 5.2", supportedFormats: ["openai"] },
|
||||||
{ id: "glm-5.1", name: "GLM 5.1", supportedFormats: ["openai"] },
|
{ id: "glm-5.1", name: "GLM 5.1", supportedFormats: ["openai"] },
|
||||||
{ id: "kimi-k2.7-code", name: "Kimi K2.7 Code", supportedFormats: ["openai"] },
|
{ id: "kimi-k2.7-code", name: "Kimi K2.7 Code", supportedFormats: ["openai"] },
|
||||||
{ id: "kimi-k2.6", name: "Kimi K2.6", supportedFormats: ["openai"] },
|
{ id: "kimi-k2.6", name: "Kimi K2.6", supportedFormats: ["openai"] },
|
||||||
|
{ id: "kimi-k3", name: "Kimi K3", supportedFormats: ["openai"] },
|
||||||
{ id: "deepseek-v4-pro", name: "DeepSeek V4 Pro", supportedFormats: ["openai", "claude", "openai-responses"] },
|
{ id: "deepseek-v4-pro", name: "DeepSeek V4 Pro", supportedFormats: ["openai", "claude", "openai-responses"] },
|
||||||
{ id: "deepseek-v4-flash", name: "DeepSeek V4 Flash", supportedFormats: ["openai", "claude", "openai-responses"] },
|
{ id: "deepseek-v4-flash", name: "DeepSeek V4 Flash", supportedFormats: ["openai", "claude", "openai-responses"] },
|
||||||
{ id: "deepseek-v4-flash-vision-exp", name: "DeepSeek V4 Flash Vision (Exp)", supportedFormats: ["openai", "claude", "openai-responses"] },
|
{ id: "deepseek-v4-flash-vision-exp", name: "DeepSeek V4 Flash Vision (Exp)", supportedFormats: ["openai", "claude", "openai-responses"] },
|
||||||
|
{ id: "deepseek-flash", name: "DeepSeek V4.1 Flash", supportedFormats: ["openai"] },
|
||||||
|
{ id: "longcat-2.0", name: "LongCat 2.0", supportedFormats: ["openai"] },
|
||||||
{ id: "mimo-v2.5", name: "MiMo V2.5", supportedFormats: ["openai"] },
|
{ id: "mimo-v2.5", name: "MiMo V2.5", supportedFormats: ["openai"] },
|
||||||
{ id: "mimo-v2.5-pro", name: "MiMo V2.5 Pro", supportedFormats: ["openai"] },
|
{ id: "mimo-v2.5-pro", name: "MiMo V2.5 Pro", supportedFormats: ["openai"] },
|
||||||
{ id: "minimax-m3", name: "MiniMax M3", supportedFormats: ["openai", "claude"] },
|
{ id: "minimax-m3", name: "MiniMax M3", supportedFormats: ["openai", "claude"] },
|
||||||
{ id: "minimax-m2.7", name: "MiniMax M2.7", supportedFormats: ["openai", "claude"] },
|
{ id: "minimax-m2.7", name: "MiniMax M2.7", supportedFormats: ["openai", "claude"] },
|
||||||
{ id: "minimax-m2.5", name: "MiniMax M2.5", supportedFormats: ["openai", "claude"] },
|
{ id: "minimax-m2.5", name: "MiniMax M2.5", supportedFormats: ["openai", "claude"] },
|
||||||
|
{ id: "qwen3.8-max", name: "Qwen 3.8 Max", supportedFormats: ["openai", "claude"] },
|
||||||
|
{ id: "qwen3.8-flash", name: "Qwen 3.8 Flash", supportedFormats: ["openai", "claude"] },
|
||||||
{ id: "qwen3.7-max", name: "Qwen 3.7 Max", supportedFormats: ["openai", "claude"] },
|
{ id: "qwen3.7-max", name: "Qwen 3.7 Max", supportedFormats: ["openai", "claude"] },
|
||||||
{ id: "qwen3.7-plus", name: "Qwen 3.7 Plus", supportedFormats: ["openai", "claude"] },
|
{ id: "qwen3.7-plus", name: "Qwen 3.7 Plus", supportedFormats: ["openai", "claude"] },
|
||||||
{ id: "qwen3.6-plus", name: "Qwen 3.6 Plus", supportedFormats: ["openai", "claude"] },
|
{ id: "qwen3.6-plus", name: "Qwen 3.6 Plus", supportedFormats: ["openai", "claude"] },
|
||||||
// Muse Spark is served by /zen/go/v1/responses only — responses-only entry forces
|
{ id: "hy4-preview", name: "Hy4 Preview", supportedFormats: ["openai"] },
|
||||||
// chatCore past the sourceFormat-matched transports into translation (see chatCore guard).
|
{ id: "hy3", name: "Hy3", supportedFormats: ["openai"] },
|
||||||
|
// Served by /zen/go/v1/responses only — the responses-only entry forces chatCore
|
||||||
|
// past the sourceFormat-matched transports into translation (see chatCore guard).
|
||||||
|
{ id: "grok-4.6", name: "Grok 4.6", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] },
|
||||||
|
{ id: "gpt-5.6-luna", name: "GPT 5.6 Luna", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] },
|
||||||
{ id: "muse-spark-1.2-contributor", name: "Muse Spark 1.2 Contributor", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] },
|
{ id: "muse-spark-1.2-contributor", name: "Muse Spark 1.2 Contributor", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] },
|
||||||
{ id: "muse-spark-1.3-contributor", name: "Muse Spark 1.3 Contributor", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] },
|
{ id: "muse-spark-1.3-contributor", name: "Muse Spark 1.3 Contributor", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] },
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { testProxyUrl } from "@/lib/network/proxyTest";
|
|||||||
import { isOpenAICompatibleProvider, isAnthropicCompatibleProvider } from "@/shared/constants/providers";
|
import { isOpenAICompatibleProvider, isAnthropicCompatibleProvider } from "@/shared/constants/providers";
|
||||||
import { getDefaultModel } from "open-sse/config/providerModels.js";
|
import { getDefaultModel } from "open-sse/config/providerModels.js";
|
||||||
import { resolveOllamaLocalHost, PROVIDERS } from "open-sse/config/providers.js";
|
import { resolveOllamaLocalHost, PROVIDERS } from "open-sse/config/providers.js";
|
||||||
|
import { CODEX_CLI_VERSION } from "open-sse/config/appConstants.js";
|
||||||
import {
|
import {
|
||||||
refreshProviderCredentials,
|
refreshProviderCredentials,
|
||||||
shouldRefreshCredentials,
|
shouldRefreshCredentials,
|
||||||
@@ -27,7 +28,7 @@ const OAUTH_TEST_CONFIG = {
|
|||||||
method: "POST",
|
method: "POST",
|
||||||
authHeader: "Authorization",
|
authHeader: "Authorization",
|
||||||
authPrefix: "Bearer ",
|
authPrefix: "Bearer ",
|
||||||
extraHeaders: { "Content-Type": "application/json", "originator": "codex_cli_rs", "User-Agent": "codex_cli_rs/0.136.0" },
|
extraHeaders: { "Content-Type": "application/json", "originator": "codex_cli_rs", "User-Agent": `codex_cli_rs/${CODEX_CLI_VERSION}` },
|
||||||
// Minimal invalid body — triggers fast 400 without consuming quota
|
// Minimal invalid body — triggers fast 400 without consuming quota
|
||||||
body: JSON.stringify({ model: "gpt-5.3-codex", input: [], stream: false, store: false }),
|
body: JSON.stringify({ model: "gpt-5.3-codex", input: [], stream: false, store: false }),
|
||||||
// 400 (bad request) means auth succeeded; only 401/403 means token is bad
|
// 400 (bad request) means auth succeeded; only 401/403 means token is bad
|
||||||
|
|||||||
@@ -192,9 +192,10 @@
|
|||||||
"baseUrl": "https://chatgpt.com/backend-api/codex/responses",
|
"baseUrl": "https://chatgpt.com/backend-api/codex/responses",
|
||||||
"format": "openai-responses",
|
"format": "openai-responses",
|
||||||
"forceStream": true,
|
"forceStream": true,
|
||||||
|
"cliVersion": "0.154.0",
|
||||||
"headers": {
|
"headers": {
|
||||||
"originator": "codex_cli_rs",
|
"originator": "codex_cli_rs",
|
||||||
"User-Agent": "codex_cli_rs/0.136.0"
|
"User-Agent": "codex_cli_rs/0.154.0"
|
||||||
},
|
},
|
||||||
"usage": {
|
"usage": {
|
||||||
"url": "https://chatgpt.com/backend-api/wham/usage",
|
"url": "https://chatgpt.com/backend-api/wham/usage",
|
||||||
|
|||||||
@@ -351,7 +351,7 @@ describe("handleImageGenerationCore", () => {
|
|||||||
headers: expect.objectContaining({
|
headers: expect.objectContaining({
|
||||||
authorization: "Bearer codex-token",
|
authorization: "Bearer codex-token",
|
||||||
"chatgpt-account-id": "account-123",
|
"chatgpt-account-id": "account-123",
|
||||||
version: "0.136.0",
|
version: "0.154.0",
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -4,9 +4,11 @@ import { PROVIDERS } from "../../open-sse/config/providers.js";
|
|||||||
import { resolveTransport } from "../../open-sse/services/provider.js";
|
import { resolveTransport } from "../../open-sse/services/provider.js";
|
||||||
|
|
||||||
// Chat-only models (no /messages, no /responses support on opencode-go)
|
// Chat-only models (no /messages, no /responses support on opencode-go)
|
||||||
const CHAT_ONLY = ["glm-5.2", "glm-5.1", "kimi-k2.7-code", "kimi-k2.6", "mimo-v2.5", "mimo-v2.5-pro"];
|
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"];
|
||||||
// Models that also expose the Anthropic /messages endpoint
|
// Models that also expose the Anthropic /messages endpoint
|
||||||
const CLAUDE_CAPABLE = ["minimax-m3", "minimax-m2.7", "minimax-m2.5", "qwen3.7-max", "qwen3.7-plus", "qwen3.6-plus"];
|
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"];
|
||||||
// Models that also expose the OpenAI /responses endpoint
|
// Models that also expose the OpenAI /responses endpoint
|
||||||
const RESPONSES_CAPABLE = ["deepseek-v4-pro", "deepseek-v4-flash"];
|
const RESPONSES_CAPABLE = ["deepseek-v4-pro", "deepseek-v4-flash"];
|
||||||
|
|
||||||
@@ -22,11 +24,13 @@ describe("OpenCode Go model catalog", () => {
|
|||||||
it("matches the documented model IDs", () => {
|
it("matches the documented model IDs", () => {
|
||||||
const ids = (PROVIDER_MODELS["opencode-go"] || []).map((m) => m.id);
|
const ids = (PROVIDER_MODELS["opencode-go"] || []).map((m) => m.id);
|
||||||
expect(ids).toEqual([
|
expect(ids).toEqual([
|
||||||
"glm-5.3-flash", "glm-5.2", "glm-5.1", "kimi-k2.7-code", "kimi-k2.6",
|
"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",
|
"deepseek-v4-pro", "deepseek-v4-flash", "deepseek-v4-flash-vision-exp", "deepseek-flash",
|
||||||
"mimo-v2.5", "mimo-v2.5-pro",
|
"longcat-2.0", "mimo-v2.5", "mimo-v2.5-pro",
|
||||||
"minimax-m3", "minimax-m2.7", "minimax-m2.5",
|
"minimax-m3", "minimax-m2.7", "minimax-m2.5",
|
||||||
"qwen3.7-max", "qwen3.7-plus", "qwen3.6-plus",
|
"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",
|
||||||
"muse-spark-1.2-contributor", "muse-spark-1.3-contributor",
|
"muse-spark-1.2-contributor", "muse-spark-1.3-contributor",
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
@@ -91,7 +95,7 @@ describe("OpenCode Go per-model transport guard (chatCore logic)", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("routes Muse Spark (responses-only) to /responses, never to /messages", () => {
|
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"]) {
|
for (const m of ["muse-spark-1.2-contributor", "muse-spark-1.3-contributor", "grok-4.6", "gpt-5.6-luna"]) {
|
||||||
expect(getModelSupportedFormats("opencode-go", m)).toEqual(["openai-responses"]);
|
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", "openai-responses", "opencode-go", m)?.baseUrl).toBe("https://opencode.ai/zen/go/v1/responses");
|
||||||
expect(pickTransport("opencode-go", "claude", "opencode-go", m)).toBeNull();
|
expect(pickTransport("opencode-go", "claude", "opencode-go", m)).toBeNull();
|
||||||
|
|||||||
Reference in New Issue
Block a user