fix(providers/command-code): send required stream payload (#2271)

- Force skills: "" and params.stream: true in Command Code wrapper
- Align validation probe payload with upstream-required shape
- Default validation model to deepseek/deepseek-v4-flash

Co-authored-by: ddarkr <ddarkr@users.noreply.github.com>
This commit is contained in:
ddarkr
2026-05-15 03:25:22 -03:00
committed by diegosouzapw
parent 76c20240f1
commit 4f80be1f2f
4 changed files with 28 additions and 11 deletions

View File

@@ -142,7 +142,7 @@ function clampMaxTokens(value: unknown): number {
return Math.max(1, Math.min(Math.floor(numeric), MAX_COMMAND_CODE_TOKENS));
}
function buildCommandCodeBody(model: string, body: unknown, stream: boolean): JsonRecord {
function buildCommandCodeBody(model: string, body: unknown): JsonRecord {
const input = isRecord(body) ? body : {};
const converted = convertMessages(input.messages);
const explicitSystem = typeof input.system === "string" ? input.system : "";
@@ -162,6 +162,7 @@ function buildCommandCodeBody(model: string, body: unknown, stream: boolean): Js
},
memory: "",
taste: "",
skills: "",
permissionMode: "standard",
params: {
model,
@@ -169,7 +170,7 @@ function buildCommandCodeBody(model: string, body: unknown, stream: boolean): Js
tools: convertTools(input.tools),
system,
max_tokens: clampMaxTokens(input.max_tokens ?? input.max_completion_tokens),
stream,
stream: true,
},
};
}
@@ -512,7 +513,7 @@ export class CommandCodeExecutor extends BaseExecutor {
};
mergeUpstreamExtraHeaders(headers, upstreamExtraHeaders);
const transformedBody = buildCommandCodeBody(model, body, stream);
const transformedBody = buildCommandCodeBody(model, body);
const url = this.buildUrl();
const upstream = await fetch(url, {
method: "POST",

View File

@@ -404,6 +404,10 @@ export async function validateCommandCodeProvider({ apiKey, providerSpecificData
const baseUrl = normalizeBaseUrl(entry?.baseUrl || "https://api.commandcode.ai");
const chatPath = entry?.chatPath || "/alpha/generate";
const url = `${baseUrl}${chatPath.startsWith("/") ? chatPath : `/${chatPath}`}`;
const validationModelId =
providerSpecificData?.validationModelId ||
entry?.models?.find((model) => model.id === "deepseek/deepseek-v4-flash")?.id ||
"deepseek/deepseek-v4-flash";
return validateDirectChatProvider({
url,
@@ -432,17 +436,15 @@ export async function validateCommandCodeProvider({ apiKey, providerSpecificData
},
memory: "",
taste: "",
skills: "",
permissionMode: "standard",
params: {
model:
providerSpecificData?.validationModelId ||
entry?.models?.[0]?.id ||
"deepseek/deepseek-v4-flash",
model: validationModelId,
messages: [{ role: "user", content: "test" }],
tools: [],
system: "",
max_tokens: 1,
stream: false,
stream: true,
},
},
});

View File

@@ -126,11 +126,12 @@ test("Command Code executor posts wrapped body and required headers to alpha/gen
const posted = JSON.parse(String(calls[0].init.body));
assert.deepEqual(posted, transformedBody);
for (const key of ["config", "memory", "taste", "permissionMode", "params"]) {
for (const key of ["config", "memory", "taste", "skills", "permissionMode", "params"]) {
assert.ok(key in posted, `missing ${key}`);
}
assert.equal(posted.skills, "");
assert.equal(posted.params.model, "gpt-5.4-mini");
assert.equal(posted.params.stream, false);
assert.equal(posted.params.stream, true);
assert.equal(posted.params.system, "You are concise.");
assert.equal(posted.params.messages[0].role, "user");
assert.equal(posted.params.tools[0].name, "lookup");

View File

@@ -105,6 +105,18 @@ test("validateCommandCodeProvider ignores caller baseUrl and chatPath overrides"
assert.equal(result.valid, true);
});
test("validateCommandCodeProvider defaults probe model to DeepSeek flash", async () => {
globalThis.fetch = async (_url, init = {}) => {
const body = JSON.parse(String(init.body));
assert.equal(body.params.model, "deepseek/deepseek-v4-flash");
return new Response("", { status: 400 });
};
const result = await validateCommandCodeProvider({ apiKey: "cc-key" });
assert.deepEqual(result, { valid: true, error: null });
});
test("specialty providers surface network failures and non-auth upstream failures", async () => {
globalThis.fetch = async (url) => {
const target = String(url);
@@ -1940,8 +1952,9 @@ test("validateCommandCodeProvider sends Command Code probe URL, headers, and wra
assert.equal(typeof calls[0].headers["x-session-id"], "string");
assert.equal(calls[0].body.config.environment, "external");
assert.equal(calls[0].body.permissionMode, "standard");
assert.equal(calls[0].body.skills, "");
assert.equal(calls[0].body.params.model, "gpt-5.4-mini");
assert.equal(calls[0].body.params.stream, false);
assert.equal(calls[0].body.params.stream, true);
assert.equal(calls[0].body.params.max_tokens, 1);
});