mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-07 15:52:52 +03:00
fix(command-code): pass reasoning/thinking fields through to params (#4473)
Thanks @adivekar-utexas! Rebuilt on release/v3.8.32 with just the command-code commits (the combo half landed via #4472). reasoning/thinking passthrough + body.model rewrite now ship.
This commit is contained in:
@@ -145,12 +145,46 @@ function clampMaxTokens(value: unknown): number {
|
||||
return Math.max(1, Math.min(Math.floor(numeric), MAX_COMMAND_CODE_TOKENS));
|
||||
}
|
||||
|
||||
// Reasoning/thinking fields that payload rules or clients may inject and that
|
||||
// CommandCode's upstream accepts inside `params`. Without this pass-through,
|
||||
// payload-rule overrides on these fields are silently dropped (#2986 follow-up).
|
||||
const COMMAND_CODE_PASSTHROUGH_FIELDS = [
|
||||
"reasoning_effort",
|
||||
"reasoning",
|
||||
"thinking",
|
||||
"effort",
|
||||
"output_config",
|
||||
"extra_body",
|
||||
] as const;
|
||||
|
||||
function buildCommandCodeBody(model: string, body: unknown, stream = false): JsonRecord {
|
||||
const input = isRecord(body) ? body : {};
|
||||
const converted = convertMessages(input.messages);
|
||||
const explicitSystem = typeof input.system === "string" ? input.system : "";
|
||||
const system = [converted.system, explicitSystem].filter(Boolean).join("\n\n");
|
||||
|
||||
// Payload rules may rewrite `body.model` (e.g. deepseek-v4-pro-max →
|
||||
// deepseek/deepseek-v4-pro for the command-code provider). Prefer the
|
||||
// rewritten value if present; fall back to the resolved combo model arg.
|
||||
const resolvedModel =
|
||||
typeof input.model === "string" && input.model.trim().length > 0 ? input.model : model;
|
||||
|
||||
const params: JsonRecord = {
|
||||
model: resolvedModel,
|
||||
messages: converted.messages,
|
||||
tools: convertTools(input.tools),
|
||||
system,
|
||||
max_tokens: clampMaxTokens(input.max_tokens ?? input.max_completion_tokens),
|
||||
stream: true,
|
||||
};
|
||||
|
||||
for (const field of COMMAND_CODE_PASSTHROUGH_FIELDS) {
|
||||
const value = input[field];
|
||||
if (value !== undefined && value !== null) {
|
||||
params[field] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
config: {
|
||||
workingDir: "/workspace",
|
||||
@@ -167,14 +201,7 @@ function buildCommandCodeBody(model: string, body: unknown, stream = false): Jso
|
||||
taste: "",
|
||||
skills: "",
|
||||
permissionMode: "standard",
|
||||
params: {
|
||||
model,
|
||||
messages: converted.messages,
|
||||
tools: convertTools(input.tools),
|
||||
system,
|
||||
max_tokens: clampMaxTokens(input.max_tokens ?? input.max_completion_tokens),
|
||||
stream: true,
|
||||
},
|
||||
params,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ function commandCodeStream(lines: unknown[], { sse = false } = {}) {
|
||||
return new Response(text, { status: 200, headers: { "Content-Type": "application/x-ndjson" } });
|
||||
}
|
||||
|
||||
function toPlainHeaders(headers: any) {
|
||||
function toPlainHeaders(headers: Headers | Record<string, string>) {
|
||||
if (headers instanceof Headers) return Object.fromEntries(headers.entries());
|
||||
return Object.fromEntries(Object.entries(headers).map(([key, value]) => [key, String(value)]));
|
||||
}
|
||||
@@ -90,8 +90,10 @@ test("getExecutor returns the specialized Command Code executor", () => {
|
||||
assert.ok(getExecutor("cmd") instanceof CommandCodeExecutor);
|
||||
});
|
||||
|
||||
type FetchCall = { url: string; init: Record<string, unknown>; body?: unknown };
|
||||
|
||||
test("Command Code executor posts wrapped body and required headers to /alpha/generate", async () => {
|
||||
const calls: any[] = [];
|
||||
const calls: FetchCall[] = [];
|
||||
globalThis.fetch = async (url, init = {}) => {
|
||||
calls.push({ url: String(url), init });
|
||||
return commandCodeStream([{ type: "text-delta", text: "hello" }, { type: "finish" }]);
|
||||
@@ -141,8 +143,66 @@ test("Command Code executor posts wrapped body and required headers to /alpha/ge
|
||||
assert.equal(json.choices[0].message.content, "hello");
|
||||
});
|
||||
|
||||
test("Command Code executor passes reasoning/thinking fields through to params (#2986 follow-up)", async () => {
|
||||
const calls: FetchCall[] = [];
|
||||
globalThis.fetch = async (url, init = {}) => {
|
||||
calls.push({ url: String(url), init });
|
||||
return commandCodeStream([{ type: "text-delta", text: "ok" }, { type: "finish" }]);
|
||||
};
|
||||
|
||||
await getExecutor("command-code").execute({
|
||||
model: "deepseek/deepseek-v4-pro",
|
||||
stream: false,
|
||||
credentials: { apiKey: "cc_test_key" },
|
||||
body: {
|
||||
stream: false,
|
||||
messages: [{ role: "user", content: "Hi" }],
|
||||
reasoning_effort: "high",
|
||||
thinking: { type: "enabled" },
|
||||
effort: "high",
|
||||
output_config: { effort: "high" },
|
||||
extra_body: { enable_thinking: true },
|
||||
},
|
||||
});
|
||||
|
||||
const posted = JSON.parse(String(calls[0].init.body));
|
||||
assert.equal(posted.params.reasoning_effort, "high");
|
||||
assert.deepEqual(posted.params.thinking, { type: "enabled" });
|
||||
assert.equal(posted.params.effort, "high");
|
||||
assert.deepEqual(posted.params.output_config, { effort: "high" });
|
||||
assert.deepEqual(posted.params.extra_body, { enable_thinking: true });
|
||||
});
|
||||
|
||||
test("Command Code executor honors body.model rewrite from payload rules", async () => {
|
||||
const calls: FetchCall[] = [];
|
||||
globalThis.fetch = async (url, init = {}) => {
|
||||
calls.push({ url: String(url), init });
|
||||
return commandCodeStream([{ type: "text-delta", text: "ok" }, { type: "finish" }]);
|
||||
};
|
||||
|
||||
// Simulate a payload-rule rewrite: combo resolves to "deepseek-v4-pro-max"
|
||||
// (passed as the execute() model arg), but the payload rule overwrites
|
||||
// body.model to "deepseek/deepseek-v4-pro" (the vendor-prefixed form
|
||||
// Command Code's API expects).
|
||||
await getExecutor("command-code").execute({
|
||||
model: "deepseek-v4-pro-max",
|
||||
stream: false,
|
||||
credentials: { apiKey: "cc_test_key" },
|
||||
body: {
|
||||
stream: false,
|
||||
model: "deepseek/deepseek-v4-pro",
|
||||
messages: [{ role: "user", content: "Hi" }],
|
||||
reasoning_effort: "max",
|
||||
},
|
||||
});
|
||||
|
||||
const posted = JSON.parse(String(calls[0].init.body));
|
||||
assert.equal(posted.params.model, "deepseek/deepseek-v4-pro");
|
||||
assert.equal(posted.params.reasoning_effort, "max");
|
||||
});
|
||||
|
||||
test("Command Code raw NDJSON stream becomes OpenAI chat SSE chunks", async () => {
|
||||
const calls: any[] = [];
|
||||
const calls: FetchCall[] = [];
|
||||
globalThis.fetch = async (url, init = {}) => {
|
||||
calls.push({ url: String(url), init, body: JSON.parse(String(init.body)) });
|
||||
return commandCodeStream([
|
||||
|
||||
Reference in New Issue
Block a user