mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-05 06:42:12 +03:00
fix: avoid OpenAI stream options for Anthropic-compatible providers (#1654)
Integrated into release/v3.7.2
This commit is contained in:
@@ -9,7 +9,11 @@ import {
|
||||
} from "../services/claudeCodeCompatible.ts";
|
||||
import { getGigachatAccessToken } from "../services/gigachatAuth.ts";
|
||||
import { applyProviderRequestDefaults } from "../services/providerRequestDefaults.ts";
|
||||
import { getOpenAICompatibleType, isClaudeCodeCompatible } from "../services/provider.ts";
|
||||
import {
|
||||
getOpenAICompatibleType,
|
||||
getTargetFormat,
|
||||
isClaudeCodeCompatible,
|
||||
} from "../services/provider.ts";
|
||||
import { sanitizeQwenThinkingToolChoice } from "../services/qwenThinking.ts";
|
||||
import { buildDataRobotChatUrl } from "../config/datarobot.ts";
|
||||
import { buildAzureAiChatUrl } from "../config/azureAi.ts";
|
||||
@@ -343,19 +347,30 @@ export class DefaultExecutor extends BaseExecutor {
|
||||
*/
|
||||
transformRequest(model, body, stream, credentials) {
|
||||
void model;
|
||||
void credentials;
|
||||
const withDefaults = applyProviderRequestDefaults(body, this.config.requestDefaults);
|
||||
let withDefaults = applyProviderRequestDefaults(body, this.config.requestDefaults);
|
||||
|
||||
if (stream && this.config.format === "openai") {
|
||||
if (typeof withDefaults === "object" && withDefaults !== null) {
|
||||
withDefaults.stream_options = {
|
||||
...(withDefaults.stream_options || {}),
|
||||
include_usage: true,
|
||||
if (typeof withDefaults === "object" && withDefaults !== null && !Array.isArray(withDefaults)) {
|
||||
if (this.provider?.startsWith?.("anthropic-compatible-")) {
|
||||
if (Object.prototype.hasOwnProperty.call(withDefaults, "stream_options")) {
|
||||
const { stream_options, ...withoutStreamOptions } = withDefaults;
|
||||
void stream_options;
|
||||
withDefaults = withoutStreamOptions;
|
||||
}
|
||||
} else if (
|
||||
stream &&
|
||||
getTargetFormat(this.provider, credentials?.providerSpecificData) === "openai"
|
||||
) {
|
||||
withDefaults = {
|
||||
...withDefaults,
|
||||
stream_options: {
|
||||
...(withDefaults.stream_options || {}),
|
||||
include_usage: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (this.provider === "qwen" && typeof body === "object" && body !== null) {
|
||||
if (this.provider === "qwen" && typeof withDefaults === "object" && withDefaults !== null) {
|
||||
return sanitizeQwenThinkingToolChoice(withDefaults, "QwenExecutor");
|
||||
}
|
||||
return withDefaults;
|
||||
|
||||
@@ -557,6 +557,7 @@ test("handleChatCore forces SSE upstream for CC compatible providers while retur
|
||||
assert.equal(calls.length, 1);
|
||||
assert.equal(calls[0].headers.Accept, "application/json");
|
||||
assert.equal(calls[0].body.stream, true);
|
||||
assert.equal(calls[0].body.stream_options, undefined);
|
||||
assert.equal(JSON.stringify(calls[0].body).includes('"cache_control"'), false);
|
||||
|
||||
const payload = (await result.response.json()) as any;
|
||||
|
||||
@@ -582,13 +582,62 @@ test("DefaultExecutor.execute only injects adaptive thinking defaults for Claude
|
||||
assert.equal((requestBodies[1] as any).output_config, undefined);
|
||||
});
|
||||
|
||||
test("DefaultExecutor.transformRequest is a passthrough and preserves model ids with slashes", () => {
|
||||
test("DefaultExecutor.transformRequest injects OpenAI stream usage and preserves model ids with slashes", () => {
|
||||
const executor = new DefaultExecutor("openai");
|
||||
const body = { model: "zai-org/GLM-5-FP8", messages: [{ role: "user", content: "hi" }] };
|
||||
const result = executor.transformRequest("zai-org/GLM-5-FP8", body, true, {});
|
||||
|
||||
assert.equal(result, body);
|
||||
assert.notEqual(result, body);
|
||||
assert.equal(result.model, "zai-org/GLM-5-FP8");
|
||||
assert.deepEqual((result as any).stream_options, { include_usage: true });
|
||||
assert.equal((body as any).stream_options, undefined);
|
||||
});
|
||||
|
||||
test("DefaultExecutor.transformRequest only injects stream usage for OpenAI chat targets", () => {
|
||||
const openAICompat = new DefaultExecutor("openai-compatible-test");
|
||||
const openAIResponsesCompat = new DefaultExecutor("openai-compatible-responses-test");
|
||||
|
||||
const chatBody = { model: "gpt-4.1", messages: [{ role: "user", content: "hi" }] };
|
||||
const responsesBody = { model: "gpt-4.1", input: "hi" };
|
||||
|
||||
const chatResult = openAICompat.transformRequest("gpt-4.1", chatBody, true, {
|
||||
providerSpecificData: { baseUrl: "https://proxy.example/v1" },
|
||||
});
|
||||
const responsesResult = openAIResponsesCompat.transformRequest("gpt-4.1", responsesBody, true, {
|
||||
providerSpecificData: { baseUrl: "https://proxy.example/v1" },
|
||||
});
|
||||
|
||||
assert.deepEqual((chatResult as any).stream_options, { include_usage: true });
|
||||
assert.equal((responsesResult as any).stream_options, undefined);
|
||||
});
|
||||
|
||||
test("DefaultExecutor.transformRequest strips stream_options from Anthropic-compatible targets", () => {
|
||||
const anthropicCompat = new DefaultExecutor("anthropic-compatible-test");
|
||||
const anthropicCcCompat = new DefaultExecutor("anthropic-compatible-cc-test");
|
||||
|
||||
const anthropicBody = {
|
||||
model: "claude-sonnet-4-6",
|
||||
messages: [{ role: "user", content: "hi" }],
|
||||
max_tokens: 1,
|
||||
stream_options: { include_usage: true },
|
||||
};
|
||||
const ccBody = {
|
||||
model: "claude-sonnet-4-6",
|
||||
messages: [{ role: "user", content: "hi" }],
|
||||
max_tokens: 1,
|
||||
};
|
||||
|
||||
const anthropicResult = anthropicCompat.transformRequest(
|
||||
"claude-sonnet-4-6",
|
||||
anthropicBody,
|
||||
true,
|
||||
{}
|
||||
);
|
||||
const ccResult = anthropicCcCompat.transformRequest("claude-sonnet-4-6", ccBody, true, {});
|
||||
|
||||
assert.notEqual(anthropicResult, anthropicBody);
|
||||
assert.equal((anthropicResult as any).stream_options, undefined);
|
||||
assert.equal((ccResult as any).stream_options, undefined);
|
||||
});
|
||||
|
||||
test("DefaultExecutor.transformRequest neutralizes incompatible tool_choice for Qwen thinking", () => {
|
||||
|
||||
Reference in New Issue
Block a user