mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-05-05 17:56:56 +00:00
351 lines
11 KiB
TypeScript
351 lines
11 KiB
TypeScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
const {
|
|
CLAUDE_OAUTH_TOOL_PREFIX,
|
|
normalizeContentToString,
|
|
openaiToClaudeRequest,
|
|
openaiToClaudeRequestForAntigravity,
|
|
stripEmptyTextBlocks,
|
|
} = await import("../../open-sse/translator/request/openai-to-claude.ts");
|
|
const { CLAUDE_SYSTEM_PROMPT } = await import("../../open-sse/config/constants.ts");
|
|
const { DEFAULT_THINKING_CLAUDE_SIGNATURE } =
|
|
await import("../../open-sse/config/defaultThinkingSignature.ts");
|
|
const { getModelsByProviderId } = await import("../../open-sse/config/providerModels.ts");
|
|
|
|
function getClaudeEffortFixtures() {
|
|
const claudeModels = getModelsByProviderId("claude");
|
|
const xhighModel = claudeModels.find((model) => model.supportsXHighEffort === true);
|
|
const standardModel = claudeModels.find((model) => model.supportsXHighEffort === false);
|
|
assert.ok(xhighModel, "expected at least one Claude model with xhigh support");
|
|
assert.ok(standardModel, "expected at least one Claude model without xhigh support");
|
|
return { xhighModel, standardModel };
|
|
}
|
|
|
|
test("OpenAI -> Claude helpers normalize array content and strip empty nested text blocks", () => {
|
|
const normalized = normalizeContentToString([
|
|
{ type: "text", text: "Line 1" },
|
|
{ type: "image_url", image_url: { url: "https://example.com/ignored.png" } },
|
|
{ type: "text", text: "Line 2" },
|
|
]);
|
|
|
|
assert.equal(normalized, "Line 1\nLine 2");
|
|
|
|
const stripped = stripEmptyTextBlocks([
|
|
{ type: "text", text: "" },
|
|
{ type: "text", text: "keep" },
|
|
{
|
|
type: "tool_result",
|
|
content: [
|
|
{ type: "text", text: "" },
|
|
{ type: "text", text: "nested" },
|
|
],
|
|
},
|
|
]);
|
|
|
|
assert.deepEqual(stripped, [
|
|
{ type: "text", text: "keep" },
|
|
{
|
|
type: "tool_result",
|
|
content: [{ type: "text", text: "nested" }],
|
|
},
|
|
]);
|
|
});
|
|
|
|
test("OpenAI -> Claude maps system messages, parameters and assistant cache markers", () => {
|
|
const result = openaiToClaudeRequest(
|
|
"claude-4-sonnet",
|
|
{
|
|
messages: [
|
|
{ role: "system", content: "Rule A" },
|
|
{
|
|
role: "system",
|
|
content: [
|
|
{ type: "text", text: "Rule B" },
|
|
{ type: "image_url", image_url: { url: "data:image/png;base64,abc" } },
|
|
{ type: "text", text: "Rule C" },
|
|
],
|
|
},
|
|
{ role: "user", content: "Hello" },
|
|
{ role: "assistant", content: "Hi there" },
|
|
],
|
|
max_completion_tokens: 33,
|
|
temperature: 0.25,
|
|
top_p: 0.8,
|
|
stop: ["DONE"],
|
|
},
|
|
true
|
|
);
|
|
|
|
assert.equal(result.model, "claude-4-sonnet");
|
|
assert.equal(result.stream, true);
|
|
assert.equal(result.max_tokens, 33);
|
|
assert.equal(result.temperature, 0.25);
|
|
assert.equal(result.top_p, 0.8);
|
|
assert.deepEqual(result.stop_sequences, ["DONE"]);
|
|
assert.equal(result.system[0].text, CLAUDE_SYSTEM_PROMPT);
|
|
assert.equal(result.system[1].text, "Rule A\nRule B\nRule C");
|
|
assert.equal(result.messages[0].role, "user");
|
|
assert.deepEqual(result.messages[0].content, [{ type: "text", text: "Hello" }]);
|
|
assert.equal(result.messages[1].role, "assistant");
|
|
assert.equal(result.messages[1].content[0].text, "Hi there");
|
|
assert.deepEqual(result.messages[1].content[0].cache_control, { type: "ephemeral" });
|
|
});
|
|
|
|
test("OpenAI -> Claude converts multimodal content, tool declarations, tool calls and tool results", () => {
|
|
const result = openaiToClaudeRequest(
|
|
"claude-4-sonnet",
|
|
{
|
|
messages: [
|
|
{
|
|
role: "user",
|
|
content: [
|
|
{ type: "text", text: "Inspect this" },
|
|
{ type: "image_url", image_url: { url: "data:image/png;base64,abc" } },
|
|
{ type: "image_url", image_url: { url: "https://example.com/cat.png" } },
|
|
],
|
|
},
|
|
{
|
|
role: "assistant",
|
|
reasoning_content: "Need a tool",
|
|
content: [{ type: "text", text: "Calling tool" }],
|
|
tool_calls: [
|
|
{
|
|
id: "call_weather",
|
|
type: "function",
|
|
function: {
|
|
name: "weather.get",
|
|
arguments: '{"city":"Tokyo"}',
|
|
},
|
|
},
|
|
{
|
|
id: "call_skip",
|
|
type: "function",
|
|
function: {
|
|
name: "",
|
|
arguments: "{}",
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
role: "tool",
|
|
tool_call_id: "call_weather",
|
|
content: [
|
|
{ type: "text", text: "" },
|
|
{ type: "text", text: "20C" },
|
|
],
|
|
},
|
|
],
|
|
tools: [
|
|
{
|
|
type: "function",
|
|
function: {
|
|
name: "weather.get",
|
|
description: "Read weather data",
|
|
parameters: { type: "object" },
|
|
},
|
|
},
|
|
{
|
|
type: "function",
|
|
function: {
|
|
name: "",
|
|
description: "skip me",
|
|
parameters: { type: "object" },
|
|
},
|
|
},
|
|
],
|
|
},
|
|
false
|
|
);
|
|
|
|
assert.equal(result.tools.length, 1);
|
|
assert.equal(result.tools[0].name, `${CLAUDE_OAUTH_TOOL_PREFIX}weather.get`);
|
|
assert.deepEqual(result.tools[0].input_schema, { type: "object", properties: {} });
|
|
assert.deepEqual(result.tools[0].cache_control, { type: "ephemeral", ttl: "1h" });
|
|
assert.equal(result._toolNameMap.get(`${CLAUDE_OAUTH_TOOL_PREFIX}weather.get`), "weather.get");
|
|
|
|
assert.equal(result.messages[0].role, "user");
|
|
assert.equal(result.messages[0].content.length, 3);
|
|
assert.deepEqual(result.messages[0].content[1], {
|
|
type: "image",
|
|
source: { type: "base64", media_type: "image/png", data: "abc" },
|
|
});
|
|
assert.deepEqual(result.messages[0].content[2], {
|
|
type: "image",
|
|
source: { type: "url", url: "https://example.com/cat.png" },
|
|
});
|
|
|
|
const assistantMessage = result.messages.find((message) => message.role === "assistant");
|
|
assert.ok(assistantMessage, "expected an assistant message");
|
|
assert.equal(assistantMessage.content[0].type, "thinking");
|
|
assert.equal(assistantMessage.content[0].thinking, "Need a tool");
|
|
assert.equal(assistantMessage.content[0].signature, DEFAULT_THINKING_CLAUDE_SIGNATURE);
|
|
assert.equal(assistantMessage.content[1].text, "Calling tool");
|
|
assert.equal(assistantMessage.content[2].type, "tool_use");
|
|
assert.equal(assistantMessage.content[2].name, `${CLAUDE_OAUTH_TOOL_PREFIX}weather.get`);
|
|
assert.deepEqual(assistantMessage.content[2].input, { city: "Tokyo" });
|
|
assert.deepEqual(assistantMessage.content[2].cache_control, { type: "ephemeral" });
|
|
|
|
const toolResultMessage = result.messages.find(
|
|
(message) =>
|
|
message.role === "user" && message.content.some((block) => block.type === "tool_result")
|
|
);
|
|
assert.ok(toolResultMessage, "expected a translated tool_result message");
|
|
assert.deepEqual(toolResultMessage.content[0], {
|
|
type: "tool_result",
|
|
tool_use_id: "call_weather",
|
|
content: [{ type: "text", text: "20C" }],
|
|
});
|
|
});
|
|
|
|
test("OpenAI -> Claude maps tool_choice and injects response_format instructions into system", () => {
|
|
const schemaResult = openaiToClaudeRequest(
|
|
"claude-4-sonnet",
|
|
{
|
|
messages: [{ role: "user", content: "Return JSON" }],
|
|
tool_choice: "required",
|
|
response_format: {
|
|
type: "json_schema",
|
|
json_schema: {
|
|
schema: {
|
|
type: "object",
|
|
properties: { answer: { type: "string" } },
|
|
required: ["answer"],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
false
|
|
);
|
|
|
|
assert.deepEqual(schemaResult.tool_choice, { type: "any" });
|
|
assert.match(schemaResult.system[1].text, /strictly follows this JSON schema/i);
|
|
assert.match(schemaResult.system[1].text, /"answer"/);
|
|
|
|
const jsonObjectResult = openaiToClaudeRequest(
|
|
"claude-4-sonnet",
|
|
{
|
|
messages: [{ role: "user", content: "Return JSON" }],
|
|
tool_choice: { function: { name: "emit_json" } },
|
|
response_format: { type: "json_object" },
|
|
},
|
|
false
|
|
);
|
|
|
|
assert.deepEqual(jsonObjectResult.tool_choice, { type: "tool", name: "emit_json" });
|
|
assert.match(jsonObjectResult.system[1].text, /Respond ONLY with a JSON object/i);
|
|
});
|
|
|
|
test("OpenAI -> Claude turns reasoning settings into thinking budgets and expands max tokens", () => {
|
|
const effortResult = openaiToClaudeRequest(
|
|
"claude-4-sonnet",
|
|
{
|
|
messages: [{ role: "user", content: "Think harder" }],
|
|
max_tokens: 10,
|
|
reasoning_effort: "low",
|
|
},
|
|
false
|
|
);
|
|
|
|
assert.deepEqual(effortResult.thinking, { type: "enabled", budget_tokens: 1024 });
|
|
assert.equal(effortResult.max_tokens, 9216);
|
|
|
|
const explicitThinkingResult = openaiToClaudeRequest(
|
|
"claude-4-sonnet",
|
|
{
|
|
messages: [{ role: "user", content: "Think harder" }],
|
|
max_completion_tokens: 1000,
|
|
thinking: { type: "enabled", budget_tokens: 2000, max_tokens: 3000 },
|
|
},
|
|
false
|
|
);
|
|
|
|
assert.deepEqual(explicitThinkingResult.thinking, {
|
|
type: "enabled",
|
|
budget_tokens: 2000,
|
|
max_tokens: 3000,
|
|
});
|
|
assert.equal(explicitThinkingResult.max_tokens, 10192);
|
|
});
|
|
|
|
test("OpenAI -> Claude preserves xhigh only for Claude models that expose it", () => {
|
|
const { xhighModel, standardModel } = getClaudeEffortFixtures();
|
|
const preserved = openaiToClaudeRequest(
|
|
xhighModel.id,
|
|
{
|
|
messages: [{ role: "user", content: "Think harder" }],
|
|
reasoning_effort: "xhigh",
|
|
},
|
|
false
|
|
);
|
|
const downgraded = openaiToClaudeRequest(
|
|
standardModel.id,
|
|
{
|
|
messages: [{ role: "user", content: "Think harder" }],
|
|
max_tokens: 10,
|
|
reasoning_effort: "xhigh",
|
|
},
|
|
false
|
|
);
|
|
|
|
assert.deepEqual(preserved.thinking, { type: "adaptive" });
|
|
assert.deepEqual(preserved.output_config, { effort: "xhigh" });
|
|
assert.deepEqual(downgraded.thinking, { type: "enabled", budget_tokens: 131072 });
|
|
assert.equal(downgraded.output_config, undefined);
|
|
assert.equal(downgraded.max_tokens, 139264);
|
|
});
|
|
|
|
test("OpenAI -> Claude can disable OAuth prefixes and Antigravity strips Claude-only prompting", () => {
|
|
const baseBody = {
|
|
messages: [
|
|
{ role: "system", content: "User rules" },
|
|
{ role: "user", content: "Run a tool" },
|
|
{
|
|
role: "assistant",
|
|
tool_calls: [
|
|
{
|
|
id: "call_1",
|
|
type: "function",
|
|
function: { name: "read_file", arguments: "{}" },
|
|
},
|
|
],
|
|
},
|
|
],
|
|
tools: [
|
|
{
|
|
type: "function",
|
|
function: {
|
|
name: "read_file",
|
|
description: "Read a file",
|
|
parameters: { type: "object", properties: {} },
|
|
},
|
|
},
|
|
],
|
|
};
|
|
|
|
const noPrefix = openaiToClaudeRequest(
|
|
"claude-4-sonnet",
|
|
{ ...baseBody, _disableToolPrefix: true },
|
|
false
|
|
);
|
|
|
|
assert.equal(noPrefix.tools[0].name, "read_file");
|
|
assert.equal(noPrefix._toolNameMap, undefined);
|
|
assert.equal(
|
|
noPrefix.messages[1].content.find((block) => block.type === "tool_use").name,
|
|
"read_file"
|
|
);
|
|
|
|
const antigravity = openaiToClaudeRequestForAntigravity("claude-4-sonnet", baseBody, false);
|
|
assert.equal(
|
|
antigravity.system.some((block) => String(block.text).includes("Claude Code")),
|
|
false
|
|
);
|
|
assert.equal(antigravity.system[0].text, "User rules");
|
|
assert.equal(antigravity.tools[0].name, "read_file");
|
|
assert.equal(
|
|
antigravity.messages[1].content.find((block) => block.type === "tool_use").name,
|
|
"read_file"
|
|
);
|
|
});
|