test(executors): restore the #10986 reasoning-only fallback guards (#12364)

The #10265 rewrite of command-code-executor.test.ts (b6412c6fe) deleted the two regression tests #10986 added for reasoning-only Command Code output, while the production fallback in createJsonResponse / createStreamResponse survived — leaving it unguarded. Both are restored, now routed through the /alpha/generate fallback that is the only way to reach the CLI translator since #10265, via a shared goPlanFallbackFetch() helper.

Validated in a combined worktree with all 25 PRs of this batch boarded together: typecheck:core clean, 443/443 node-runner tests plus 14/14 vitest across every test file the batch touches, and check-changelog-integrity, check:cycles (418 files), check:provider-consistency (272 REGISTRY entries, 355 canonical providers), check:docs-counts, check:docs-sync (42 locales) and check-file-size all green.

Thanks @pacocartones.
This commit is contained in:
Paco Cartones
2026-09-02 08:12:46 +02:00
committed by GitHub
parent 0389b07257
commit d337c5d30d

View File

@@ -485,6 +485,117 @@ test("Command Code executor falls back to /alpha/generate on 403 (Go plan) for n
assert.equal(usage.total_tokens, 5);
});
// Simulates a Go-plan key: /provider/v1/chat/completions answers 403 and the executor
// falls back to /alpha/generate, whose CLI SSE stream is built from `cliLines`.
function goPlanFallbackFetch(cliLines: unknown[]) {
const calls: string[] = [];
globalThis.fetch = async (url) => {
const urlStr = String(url);
calls.push(urlStr);
if (urlStr.includes("/provider/v1/chat/completions")) {
return new Response(
JSON.stringify({ error: { message: "upgrade_required", code: "upgrade_required" } }),
{ status: 403, headers: { "Content-Type": "application/json" } }
);
}
if (urlStr.includes("/alpha/generate")) {
const cliSse = cliLines.map((line) => `data: ${JSON.stringify(line)}\n\n`).join("");
return new Response(cliSse, {
status: 200,
headers: { "Content-Type": "text/event-stream" },
});
}
return new Response("Not found", { status: 404 });
};
return calls;
}
test("Command Code /alpha/generate fallback: reasoning-only output falls back to reasoning as content (non-stream) (#10986)", async () => {
const calls = goPlanFallbackFetch([
{ type: "reasoning-delta", text: "The user wants 79874+93658. " },
{ type: "reasoning-delta", text: "That equals 173532." },
{
type: "finish",
finishReason: "stop",
totalUsage: {
inputTokens: 20,
outputTokens: 64,
outputTokenDetails: { reasoningTokens: 61 },
},
},
]);
const { response, url } = await (
await getExecutor("command-code")
).execute({
model: "deepseek/deepseek-v4-flash",
stream: false,
credentials: { apiKey: "cc_go_plan_key" },
body: {
messages: [
{ role: "user", content: "Calculate 79874+93658, and reply with the result only." },
],
},
});
assert.equal(calls.length, 2, "probed /provider/v1 first, then fell back to /alpha/generate");
assert.ok(url.includes("/alpha/generate"));
const json = (await response.json()) as {
choices: Array<{
message: { content: string; reasoning_content?: string };
finish_reason: string;
}>;
usage: { completion_tokens_details: { reasoning_tokens: number } };
};
const message = json.choices[0].message;
// Regression #10986: when the model emits only reasoning-delta events (never a
// text-delta), content must fall back to the reasoning text instead of "" (which
// OpenAI-compatible clients treat as null/no answer).
assert.equal(message.content, "The user wants 79874+93658. That equals 173532.");
// reasoning_content must STAY populated for reasoning-aware clients.
assert.equal(message.reasoning_content, "The user wants 79874+93658. That equals 173532.");
assert.equal(json.choices[0].finish_reason, "stop");
assert.equal(json.usage.completion_tokens_details.reasoning_tokens, 61);
});
test("Command Code /alpha/generate fallback: reasoning-only output emits a content delta chunk when streaming (#10986)", async () => {
const calls = goPlanFallbackFetch([
{ type: "reasoning-delta", text: "The result is 173532." },
{ type: "finish", finishReason: "stop" },
]);
const { response, url } = await (
await getExecutor("command-code")
).execute({
model: "deepseek/deepseek-v4-flash",
stream: true,
credentials: { apiKey: "cc_go_plan_key" },
body: { messages: [{ role: "user", content: "Calcular 79874+93658" }] },
});
assert.equal(calls.length, 2, "probed /provider/v1 first, then fell back to /alpha/generate");
assert.ok(url.includes("/alpha/generate"));
const sse = await response.text();
assert.match(sse, /data: \[DONE\]/);
const chunks = parseSsePayloads(sse);
assert.equal(chunks[0].choices[0].delta.role, "assistant");
// Regression #10986: the reasoning-only stream must emit a content delta when it
// otherwise ends with no content. reasoning_content stays present too.
const contentChunks = chunks.filter((c) => c.choices[0]?.delta?.content !== undefined);
assert.equal(contentChunks.length, 1, "exactly one synthesized content delta");
assert.equal(contentChunks[0].choices[0].delta.content, "The result is 173532.");
const reasoningDelta = chunks.find((c) => c.choices[0]?.delta?.reasoning_content !== undefined);
assert.equal(reasoningDelta.choices[0].delta.reasoning_content, "The result is 173532.");
// The synthesized content lands after the reasoning delta and before the finish chunk.
const finishIndex = chunks.findIndex((c) => c.choices[0]?.finish_reason === "stop");
assert.ok(finishIndex > chunks.indexOf(contentChunks[0]));
assert.ok(chunks.indexOf(contentChunks[0]) > chunks.indexOf(reasoningDelta));
assert.equal(chunks[finishIndex].choices[0].finish_reason, "stop");
});
test("Command Code executor surfaces fallback error when both /provider/v1 and /alpha/generate fail", async () => {
globalThis.fetch = async (url) => {
const urlStr = String(url);