diff --git a/src/adapters/command-code.ts b/src/adapters/command-code.ts index ce20edf33..8f504fde1 100644 --- a/src/adapters/command-code.ts +++ b/src/adapters/command-code.ts @@ -21,6 +21,10 @@ const COMMAND_CODE_MODEL_ALIASES: Readonly> = { "glm-5.2": "zai-org/GLM-5.2", }; +function canonicalCommandCodeModelId(modelId: string): string { + return Object.hasOwn(COMMAND_CODE_MODEL_ALIASES, modelId) ? COMMAND_CODE_MODEL_ALIASES[modelId]! : modelId; +} + /** Flatten tool-result content for the text-only wire output, keeping an `[image]` marker per image part in content order. */ function toolResultText(content: string | OcxContentPart[]): string { if (typeof content === "string") return content; @@ -318,7 +322,7 @@ function supportedCommandCodeEffort(provider: OcxProviderConfig, modelId: string // Compatibility ids (deepseek-v4-flash / glm-5.2) must resolve to their canonical // Command Code id before the effort lookup, or legacy requests silently lose the // reasoning effort because the official table is keyed by the canonical ids. - const canonicalId = COMMAND_CODE_MODEL_ALIASES[modelId] ?? modelId; + const canonicalId = canonicalCommandCodeModelId(modelId); const supported = commandCodeReasoningEfforts(canonicalId) ?? configuredReasoningEfforts(provider, canonicalId); if (!supported) return undefined; // Command Code's official profiles describe xhigh and ultra as the CLI labels that map to @@ -347,7 +351,7 @@ export function createCommandCodeAdapter(provider: OcxProviderConfig): ProviderA config: await commandCodeConfig(cwd), memory: "", taste: null, skills: null, permissionMode: "standard", mode: "agent", params: { - model: COMMAND_CODE_MODEL_ALIASES[parsed.modelId] ?? parsed.modelId, + model: canonicalCommandCodeModelId(parsed.modelId), messages: wireMessages(parsed.context.messages), tools: wireTools(tools), system, diff --git a/src/providers/command-code-efforts.ts b/src/providers/command-code-efforts.ts index 0f2b88eb9..e6e808e8b 100644 --- a/src/providers/command-code-efforts.ts +++ b/src/providers/command-code-efforts.ts @@ -31,7 +31,8 @@ function keyFor(modelId: string): string { export function commandCodeReasoningEfforts(modelId: string): readonly string[] | undefined { const key = keyFor(modelId); - return refreshedEfforts.get(key) ?? COMMAND_CODE_MODEL_REASONING_EFFORTS[key]; + return refreshedEfforts.get(key) + ?? (Object.hasOwn(COMMAND_CODE_MODEL_REASONING_EFFORTS, key) ? COMMAND_CODE_MODEL_REASONING_EFFORTS[key] : undefined); } function parsedProfileEfforts(page: string): string[] | undefined { @@ -59,7 +60,9 @@ export async function refreshCommandCodeReasoningEfforts( fetchFn: typeof globalThis.fetch = globalThis.fetch, ): Promise { const key = keyFor(modelId); - const profile = COMMAND_CODE_MODEL_EFFORTS[key as keyof typeof COMMAND_CODE_MODEL_EFFORTS]; + const profile = Object.hasOwn(COMMAND_CODE_MODEL_EFFORTS, key) + ? COMMAND_CODE_MODEL_EFFORTS[key as keyof typeof COMMAND_CODE_MODEL_EFFORTS] + : undefined; if (!profile) return undefined; try { const response = await fetchFn(profile.profileUrl, { diff --git a/tests/command-code-provider.test.ts b/tests/command-code-provider.test.ts index 4220cbcbd..23d5fee5b 100644 --- a/tests/command-code-provider.test.ts +++ b/tests/command-code-provider.test.ts @@ -214,6 +214,15 @@ describe("Command Code provider", () => { expect(JSON.parse(legacy.body).params.reasoning_effort).toBe("high"); }); + test("treats prototype property names as literal model ids", async () => { + for (const modelId of ["__proto__", "constructor", "toString"]) { + const built = await builtRequest(parsed(modelId)); + const params = JSON.parse(built.body).params; + expect(params.model).toBe(modelId); + expect(params).not.toHaveProperty("reasoning_effort"); + } + }); + test("filters tool declarations when tool_choice disables tools", async () => { const built = await builtRequest({ ...parsed(), options: { toolChoice: "none" } }); expect(JSON.parse(built.body).params.tools).toEqual([]);