Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 36 additions & 9 deletions src/providers/command-code-efforts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,31 @@ const COMMAND_CODE_MODEL_EFFORTS = {
efforts: ["high", "max"],
profileUrl: "https://commandcode.ai/models/deepseek-v4-flash",
},
"zai-org/glm-5.3": {
efforts: ["low", "high", "max"],
profileUrl: "https://commandcode.ai/models/glm-5-3",
// Keys must match the EXACT upstream /provider/v1/models ids (GLM ships as
// `zai-org/GLM-5.3`, not `zai-org/glm-5.3`). The table doubles as the router's
// known-ids decode source (via `knownModelIdsForProvider`), so a case mismatch
// makes the Codex-facing slug `commandcode/zai-org-GLM-5.3` pass through
// undecoded and upstream rejects it with `unsupported_model`.
"zai-org/GLM-5": {
efforts: ["high", "max"],
profileUrl: "https://commandcode.ai/models/glm-5",
},
"zai-org/glm-5.2": {
"zai-org/GLM-5.1": {
efforts: ["high", "max"],
profileUrl: "https://commandcode.ai/models/glm-5-1",
},
"zai-org/GLM-5.2": {
efforts: ["high", "max"],
profileUrl: "https://commandcode.ai/models/glm-5-2",
},
"zai-org/GLM-5.2-Fast": {
efforts: ["high", "max"],
profileUrl: "https://commandcode.ai/models/glm-5-2-fast",
},
"zai-org/GLM-5.3": {
efforts: ["low", "high", "max"],
profileUrl: "https://commandcode.ai/models/glm-5-3",
},
// Muse Spark: CLI currently prints "has no adjustable reasoning effort" and
// blocks --effort locally, but the upstream /alpha/generate endpoint accepts
// reasoning_effort low..max for meta/muse-spark-1.2-contributor (verified
Expand Down Expand Up @@ -53,8 +70,14 @@ function keyFor(modelId: string): string {

export function commandCodeReasoningEfforts(modelId: string): readonly string[] | undefined {
const key = keyFor(modelId);
return refreshedEfforts.get(key)
?? (Object.hasOwn(COMMAND_CODE_MODEL_REASONING_EFFORTS, key) ? COMMAND_CODE_MODEL_REASONING_EFFORTS[key] : undefined);
const refreshed = refreshedEfforts.get(key);
if (refreshed !== undefined) return refreshed;
// Case-insensitive: the table keys match the EXACT upstream ids (e.g. `zai-org/GLM-5.3`),
// but callers may pass either case.
for (const [id, efforts] of Object.entries(COMMAND_CODE_MODEL_REASONING_EFFORTS)) {
if (keyFor(id) === key) return efforts;
}
return undefined;
}

function parsedProfileEfforts(page: string): string[] | undefined {
Expand Down Expand Up @@ -82,9 +105,13 @@ export async function refreshCommandCodeReasoningEfforts(
fetchFn: typeof globalThis.fetch = globalThis.fetch,
): Promise<readonly string[] | undefined> {
const key = keyFor(modelId);
const profile = Object.hasOwn(COMMAND_CODE_MODEL_EFFORTS, key)
? COMMAND_CODE_MODEL_EFFORTS[key as keyof typeof COMMAND_CODE_MODEL_EFFORTS]
: undefined;
let profile: { efforts: readonly string[]; profileUrl: string } | undefined;
for (const [id, row] of Object.entries(COMMAND_CODE_MODEL_EFFORTS)) {
if (keyFor(id) === key) {
profile = row;
break;
}
}
if (!profile) return undefined;
try {
const response = await fetchFn(profile.profileUrl, {
Expand Down
6 changes: 6 additions & 0 deletions src/providers/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1730,6 +1730,12 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [
apiKeyValidation: "unknown",
// The public catalog reports ids/context windows only; no trustworthy reasoning contract.
reasoningEfforts: [],
// Official Command Code model-profile reasoning facts (shared with the OAuth
// `command-code` entry). Without them the API-key preset never advertises a
// reasoning picker, and the router's known-ids decode source misses the native
// slash ids — so a Codex-facing slug like `commandcode/deepseek-deepseek-v4-pro`
// is sent upstream verbatim and rejected with `unsupported_model`.
modelReasoningEfforts: COMMAND_CODE_MODEL_REASONING_EFFORTS,
modelDiscovery: {
path: "models",
maxResponseBytes: 256 * 1024,
Expand Down
25 changes: 24 additions & 1 deletion tests/command-code-provider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ describe("Command Code provider", () => {
expect(registry?.models).toBeUndefined();
expect(registry?.modelReasoningEfforts).toMatchObject({
"deepseek/deepseek-v4-flash": ["high", "max"],
"zai-org/glm-5.2": ["high", "max"],
"zai-org/GLM-5.2": ["high", "max"],
});
expect(OAUTH_PROVIDERS["command-code"]?.providerConfig).toMatchObject({
adapter: "command-code",
Expand All @@ -60,6 +60,29 @@ describe("Command Code provider", () => {
});
});

test("API-key preset shares the official reasoning-facts table with the OAuth entry", () => {
const oauth = PROVIDER_REGISTRY.find(row => row.id === "command-code");
const apiKey = PROVIDER_REGISTRY.find(row => row.id === "commandcode");
expect(apiKey).toMatchObject({
adapter: "openai-chat",
authKind: "key",
baseUrl: "https://api.commandcode.ai/provider/v1",
liveModels: true,
});
// Without this the API-key preset never advertises a reasoning picker, and the
// router's known-ids decode source misses the native slash ids — the Codex-facing
// slug `commandcode/deepseek-deepseek-v4-pro` is then sent upstream verbatim and
// rejected with `unsupported_model`.
expect(apiKey?.modelReasoningEfforts).toEqual(oauth?.modelReasoningEfforts);
expect(apiKey?.modelReasoningEfforts).toMatchObject({
"deepseek/deepseek-v4-pro": ["high", "max"],
"zai-org/GLM-5": ["high", "max"],
"zai-org/GLM-5.1": ["high", "max"],
"zai-org/GLM-5.2-Fast": ["high", "max"],
"zai-org/GLM-5.3": ["low", "high", "max"],
});
});

test("validates callback shape and state without exposing the key", () => {
const secret = "super-secret-callback-key";
const parsedCallback = parseCommandCodeCallback({ apiKey: secret, state: "state", userId: "u", userName: "name", keyName: "cli" }, "state");
Expand Down
20 changes: 20 additions & 0 deletions tests/slug-codec.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,26 @@ describe("routeModel decode (proxy layer)", () => {
expect(ids).toContain("moonshotai/kimi-k3-free");
expect(ids).toContain("moonshotai/kimi-k3");
});

test("commandcode API-key preset decodes its native slash ids from the registry effort table", () => {
// Regression: the `commandcode` (API-key) registry entry must share the official
// reasoning-facts table with the OAuth `command-code` entry. Without it the router's
// known-ids source misses `deepseek/deepseek-v4-pro` / `zai-org/GLM-5.3`, so the
// Codex-facing slugs (`commandcode/deepseek-deepseek-v4-pro`) pass through unchanged
// and upstream rejects them with `unsupported_model`.
const prov = {
adapter: "openai-chat",
baseUrl: "https://api.commandcode.ai/provider/v1",
authMode: "key" as const,
models: ["deepseek/deepseek-v4-flash"],
liveModels: true,
};
const ids = knownModelIdsForProvider("commandcode", prov);
expect(ids).toContain("deepseek/deepseek-v4-pro");
expect(ids).toContain("zai-org/GLM-5.3");
expect(decodeRoutedModelId("deepseek-deepseek-v4-pro", ids)).toBe("deepseek/deepseek-v4-pro");
expect(decodeRoutedModelId("zai-org-GLM-5.3", ids)).toBe("zai-org/GLM-5.3");
});
});

describe("catalog emission (Codex-facing)", () => {
Expand Down
Loading