mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-19 13:23:50 +03:00
fix(executors): strip invalid OpenCode stream options (#13819)
Co-authored-by: William Echo <175406538+qinghuanandejiangshi@users.noreply.github.com>
This commit is contained in:
@@ -1153,6 +1153,11 @@ export class OpencodeExecutor extends BaseExecutor {
|
||||
}
|
||||
if (modifiedBody && typeof modifiedBody === "object" && !Array.isArray(modifiedBody)) {
|
||||
const mb = modifiedBody as Record<string, unknown>;
|
||||
// OpenCode accepts stream_options only on streaming Chat Completions (#13699).
|
||||
const format = this._requestFormat ?? resolveOpencodeTargetFormat(this.provider, model);
|
||||
if (format !== "openai" || mb.stream !== true) {
|
||||
delete mb.stream_options;
|
||||
}
|
||||
const parsed = parseEffortLevel(model);
|
||||
if (parsed) {
|
||||
const deepseekFamily =
|
||||
|
||||
83
tests/unit/opencode-stream-options-13699.test.ts
Normal file
83
tests/unit/opencode-stream-options-13699.test.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { describe, it } from "node:test";
|
||||
import { OpencodeExecutor } from "../../open-sse/executors/opencode.ts";
|
||||
|
||||
describe("OpenCode stream_options (#13699)", () => {
|
||||
for (const provider of ["opencode-go", "opencode-zen"]) {
|
||||
for (const stream of [false, undefined, true]) {
|
||||
it(`${provider}: only streaming Chat Completions retains stream_options (${stream})`, () => {
|
||||
const executor = new OpencodeExecutor(provider);
|
||||
executor._requestFormat = "openai";
|
||||
const body = {
|
||||
model: "deepseek-v4.1-flash",
|
||||
messages: [{ role: "user", content: "hello" }],
|
||||
...(stream === undefined ? {} : { stream }),
|
||||
stream_options: { include_usage: true },
|
||||
};
|
||||
const original = structuredClone(body);
|
||||
const outgoing = executor.transformRequest(body.model, body, stream === true, {});
|
||||
assert.equal(Object.hasOwn(outgoing, "stream_options"), stream === true);
|
||||
if (stream) assert.deepEqual(outgoing.stream_options, { include_usage: true });
|
||||
assert.deepEqual(body, original, "must not mutate the caller's request");
|
||||
assert.deepEqual(outgoing.messages, body.messages);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for (const format of ["claude", "openai-responses"]) {
|
||||
it(`does not forward Chat Completions stream_options to ${format}`, () => {
|
||||
const executor = new OpencodeExecutor("opencode-zen");
|
||||
executor._requestFormat = format;
|
||||
const body = { model: "test-model", stream: true, stream_options: { include_usage: true } };
|
||||
const outgoing = executor.transformRequest(body.model, body, true, {});
|
||||
assert.equal(Object.hasOwn(outgoing, "stream_options"), false);
|
||||
assert.equal(outgoing.stream, true);
|
||||
assert.deepEqual(body.stream_options, { include_usage: true });
|
||||
});
|
||||
}
|
||||
|
||||
it("preserves streaming options when transformRequest resolves the format without execute", () => {
|
||||
const executor = new OpencodeExecutor("opencode-go");
|
||||
const body = {
|
||||
model: "deepseek-v4.1-flash",
|
||||
stream: true,
|
||||
stream_options: { include_usage: true },
|
||||
};
|
||||
assert.deepEqual(
|
||||
executor.transformRequest(body.model, body, true, {}).stream_options,
|
||||
body.stream_options
|
||||
);
|
||||
});
|
||||
|
||||
it("removes inherited options from the actual execute request body", async (t) => {
|
||||
const sent: Record<string, unknown>[] = [];
|
||||
t.mock.method(globalThis, "fetch", async (_url: unknown, init: RequestInit) => {
|
||||
const body = JSON.parse(String(init.body)) as Record<string, unknown>;
|
||||
sent.push(body);
|
||||
const invalid = body.stream !== true && Object.hasOwn(body, "stream_options");
|
||||
return new Response(
|
||||
JSON.stringify(invalid ? { error: "stream_options requires streaming" } : { choices: [] }),
|
||||
{
|
||||
status: invalid ? 400 : 200,
|
||||
headers: { "content-type": "application/json" },
|
||||
}
|
||||
);
|
||||
});
|
||||
const executor = new OpencodeExecutor("opencode-go");
|
||||
const result = await executor.execute({
|
||||
model: "deepseek-v4.1-flash",
|
||||
stream: false,
|
||||
credentials: { apiKey: "test-key" },
|
||||
body: {
|
||||
model: "deepseek-v4.1-flash",
|
||||
stream: false,
|
||||
stream_options: { include_usage: true },
|
||||
messages: [{ role: "user", content: "hello" }],
|
||||
},
|
||||
});
|
||||
assert.ok(result.url.endsWith("/chat/completions"));
|
||||
assert.equal(result.response.status, 200);
|
||||
assert.equal(sent.length, 1);
|
||||
assert.equal(Object.hasOwn(sent[0], "stream_options"), false);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user