mirror of
https://github.com/Nezumi-2711/9router.git
synced 2026-09-22 13:38:31 +00:00
Merge remote-tracking branch 'upstream/master'
# Conflicts: # .gitignore # open-sse/handlers/chatCore.js
This commit is contained in:
@@ -4,6 +4,8 @@ import "./registerAll.js";
|
||||
import { translateRequest, translateResponse, initState } from "../../open-sse/translator/index.js";
|
||||
import { FORMATS } from "../../open-sse/translator/formats.js";
|
||||
import { AntigravityExecutor } from "../../open-sse/executors/antigravity.js";
|
||||
import { openaiToAntigravityRequest } from "../../open-sse/translator/request/openai-to-gemini.js";
|
||||
import { ANTIGRAVITY_DEFAULT_SYSTEM } from "../../open-sse/config/appConstants.js";
|
||||
|
||||
const AG2O = (req) =>
|
||||
translateRequest(FORMATS.ANTIGRAVITY, FORMATS.OPENAI, "m", { request: req }, true, null, null);
|
||||
@@ -106,4 +108,32 @@ describe("Antigravity executor", () => {
|
||||
const query = out.request.tools[0].functionDeclarations[0].parameters.properties.query;
|
||||
expect(query).toEqual({ type: "string", description: "Search query" });
|
||||
});
|
||||
|
||||
it("does not inject the legacy Antigravity default system prompt for Gemini-backed models", () => {
|
||||
const out = openaiToAntigravityRequest("gemini-3.5-flash-low", {
|
||||
messages: [
|
||||
{ role: "system", content: "USER_SYSTEM_PROMPT" },
|
||||
{ role: "user", content: "hello" },
|
||||
],
|
||||
}, true, { projectId: "project-1", connectionId: "conn-1" });
|
||||
|
||||
const system = JSON.stringify(out.request.systemInstruction);
|
||||
expect(system).toContain("USER_SYSTEM_PROMPT");
|
||||
expect(system).not.toContain(ANTIGRAVITY_DEFAULT_SYSTEM);
|
||||
expect(system).not.toContain("Please ignore the following [ignore]");
|
||||
});
|
||||
|
||||
it("does not inject the legacy Antigravity default system prompt for Claude-backed models", () => {
|
||||
const out = openaiToAntigravityRequest("claude-opus-4-6-thinking", {
|
||||
messages: [
|
||||
{ role: "system", content: "USER_SYSTEM_PROMPT" },
|
||||
{ role: "user", content: "hello" },
|
||||
],
|
||||
}, true, { projectId: "project-1", connectionId: "conn-1" });
|
||||
|
||||
const system = JSON.stringify(out.request.systemInstruction);
|
||||
expect(system).toContain("USER_SYSTEM_PROMPT");
|
||||
expect(system).not.toContain(ANTIGRAVITY_DEFAULT_SYSTEM);
|
||||
expect(system).not.toContain("Please ignore the following [ignore]");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -46,6 +46,20 @@ describe("Codex CLI Responses → OpenAI", () => {
|
||||
});
|
||||
|
||||
describe("OpenAI → Codex Responses (reverse)", () => {
|
||||
it("maps developer messages to Responses API instructions", () => {
|
||||
const out = O2R({
|
||||
messages: [
|
||||
{ role: "developer", content: "Follow the project rules." },
|
||||
{ role: "user", content: "Hello" },
|
||||
],
|
||||
});
|
||||
|
||||
expect(out.instructions).toBe("Follow the project rules.");
|
||||
expect(out.input).toEqual([
|
||||
{ type: "message", role: "user", content: [{ type: "input_text", text: "Hello" }] },
|
||||
]);
|
||||
});
|
||||
|
||||
// openai-responses.js:13 — clampCallId NOT applied on Responses→Chat; but here Chat→Responses must clamp
|
||||
it("call_id longer than 64 chars is clamped", () => {
|
||||
const longId = "call_" + "x".repeat(80);
|
||||
|
||||
@@ -67,6 +67,101 @@ describe("OpenAI → Claude context mapping", () => {
|
||||
expect(JSON.stringify(out), "remote image dropped").toContain("pic.png");
|
||||
});
|
||||
|
||||
// prepareClaudeRequest reconciles max_tokens vs thinking.budget_tokens.
|
||||
// applyThinking runs after adjustMaxTokens caps max_tokens, so a claude-budget
|
||||
// model at "max" effort (budget 128000) can exceed the clamped max_tokens and
|
||||
// trip Anthropic's "max_tokens > budget_tokens" rule (400). See claude.js.
|
||||
describe("max_tokens vs thinking.budget_tokens reconciliation", () => {
|
||||
// 64k-ceiling model (maxOutput 64000) + max-effort budget 128000: budget alone
|
||||
// exceeds the ceiling → cap max_tokens at 64000 and shrink budget below it.
|
||||
it("max effort budget on a 64k model → budget < max_tokens ≤ 64000", () => {
|
||||
const out = prepareClaudeRequest({
|
||||
model: "claude-opus-4-20250514",
|
||||
max_tokens: 64000,
|
||||
thinking: { type: "enabled", budget_tokens: 128000 },
|
||||
messages: [{ role: "user", content: "q" }],
|
||||
}, "anthropic");
|
||||
expect(out.max_tokens).toBe(64000);
|
||||
expect(out.thinking.budget_tokens).toBeLessThan(out.max_tokens);
|
||||
expect(out.thinking.budget_tokens).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
// Budget fits under the ceiling but exceeds a small client max_tokens →
|
||||
// raise max_tokens to fit, preserving the requested thinking depth.
|
||||
it("xhigh budget with a low client max_tokens → raise max_tokens, preserve budget", () => {
|
||||
const out = prepareClaudeRequest({
|
||||
model: "claude-opus-4-20250514",
|
||||
max_tokens: 16000,
|
||||
thinking: { type: "enabled", budget_tokens: 32768 },
|
||||
messages: [{ role: "user", content: "q" }],
|
||||
}, "anthropic");
|
||||
expect(out.thinking.budget_tokens).toBe(32768);
|
||||
expect(out.max_tokens).toBe(33792); // 32768 + 1024, under the 64000 ceiling
|
||||
});
|
||||
|
||||
// Budget already below max_tokens → nothing to reconcile.
|
||||
it("high budget under max_tokens → both unchanged", () => {
|
||||
const out = prepareClaudeRequest({
|
||||
model: "claude-opus-4-20250514",
|
||||
max_tokens: 64000,
|
||||
thinking: { type: "enabled", budget_tokens: 24576 },
|
||||
messages: [{ role: "user", content: "q" }],
|
||||
}, "anthropic");
|
||||
expect(out.max_tokens).toBe(64000);
|
||||
expect(out.thinking.budget_tokens).toBe(24576);
|
||||
});
|
||||
|
||||
// Non-budget thinking shapes (adaptive / disabled) carry no budget_tokens →
|
||||
// the reconciliation must never touch them.
|
||||
it("adaptive thinking (no budget_tokens) is left untouched", () => {
|
||||
const out = prepareClaudeRequest({
|
||||
model: "claude-opus-4-20250514",
|
||||
max_tokens: 64000,
|
||||
thinking: { type: "adaptive" },
|
||||
messages: [{ role: "user", content: "q" }],
|
||||
}, "anthropic");
|
||||
expect(out.max_tokens).toBe(64000);
|
||||
expect(out.thinking).toEqual({ type: "adaptive" });
|
||||
});
|
||||
|
||||
// Lifted ceiling: a claude-budget model whose caps declare maxOutput 128000
|
||||
// (e.g. fable) may use the full budget at max effort instead of being pinned
|
||||
// to the conservative 64000 default.
|
||||
it("max effort budget on a 128k model → max_tokens up to 128000, budget preserved just under", () => {
|
||||
const out = prepareClaudeRequest({
|
||||
model: "claude-fable-5",
|
||||
max_tokens: 64000,
|
||||
thinking: { type: "enabled", budget_tokens: 128000 },
|
||||
messages: [{ role: "user", content: "q" }],
|
||||
}, "anthropic");
|
||||
expect(out.max_tokens).toBe(128000);
|
||||
expect(out.thinking.budget_tokens).toBe(126976); // 128000 - 1024
|
||||
expect(out.thinking.budget_tokens).toBeLessThan(out.max_tokens);
|
||||
});
|
||||
|
||||
// Regression: a default 64k-ceiling model still clamps an over-large client
|
||||
// max_tokens down to 64000 (the lift is per-model, not global).
|
||||
it("over-large client max_tokens on a 64k model is still clamped to 64000", () => {
|
||||
const out = prepareClaudeRequest({
|
||||
model: "claude-opus-4-20250514",
|
||||
max_tokens: 120000,
|
||||
messages: [{ role: "user", content: "q" }],
|
||||
}, "anthropic");
|
||||
expect(out.max_tokens).toBe(64000);
|
||||
});
|
||||
|
||||
// Lifted ceiling for a 128k model: a large client max_tokens is now allowed
|
||||
// through instead of being clamped to 64000.
|
||||
it("large client max_tokens on a 128k model is allowed up to maxOutput", () => {
|
||||
const out = prepareClaudeRequest({
|
||||
model: "claude-fable-5",
|
||||
max_tokens: 100000,
|
||||
messages: [{ role: "user", content: "q" }],
|
||||
}, "anthropic");
|
||||
expect(out.max_tokens).toBe(100000);
|
||||
});
|
||||
});
|
||||
|
||||
it("DeepSeek Claude transport adds a thinking placeholder before tool_use in thinking mode", () => {
|
||||
const out = prepareClaudeRequest({
|
||||
model: "deepseek-v4-pro",
|
||||
|
||||
@@ -54,6 +54,45 @@ describe("GOLDEN request: OpenAI → Gemini", () => {
|
||||
const out = translateRequest(FORMATS.OPENAI, FORMATS.GEMINI, "gemini-3-pro", baseBody(), true, { apiKey: "k" }, "gemini");
|
||||
expect(clean(out)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("Gemini CLI tool requests include validated toolConfig and enough output for high thinking", () => {
|
||||
const body = {
|
||||
messages: [{ role: "user", content: "Call add with 7 and 35." }],
|
||||
tools: [
|
||||
{
|
||||
type: "function",
|
||||
function: {
|
||||
name: "add",
|
||||
description: "Add two numbers",
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: {
|
||||
a: { type: "number" },
|
||||
b: { type: "number" },
|
||||
},
|
||||
required: ["a", "b"],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
reasoning_effort: "high",
|
||||
max_tokens: 128,
|
||||
};
|
||||
const out = translateRequest(
|
||||
FORMATS.OPENAI,
|
||||
FORMATS.GEMINI_CLI,
|
||||
"gemini-3.1-pro-preview",
|
||||
body,
|
||||
true,
|
||||
{ accessToken: "t", projectId: "p" },
|
||||
"gemini-cli"
|
||||
);
|
||||
|
||||
expect(out.request.toolConfig).toEqual({ functionCallingConfig: { mode: "VALIDATED" } });
|
||||
expect(out.request.safetySettings).toBeDefined();
|
||||
expect(out.request.generationConfig.thinkingConfig).toEqual({ thinkingLevel: "high", includeThoughts: true });
|
||||
expect(out.request.generationConfig.maxOutputTokens).toBe(65535);
|
||||
});
|
||||
});
|
||||
|
||||
describe("GOLDEN request: OpenAI → Kiro", () => {
|
||||
|
||||
@@ -82,11 +82,27 @@ describe("applyThinking per provider format", () => {
|
||||
const out = apply("gemini", "gemini-3-pro", { reasoning_effort: "auto" }, "gemini");
|
||||
expect(out.generationConfig.thinkingConfig.thinkingLevel).toBe("high");
|
||||
});
|
||||
it("gemini-3 high thinking raises too-small maxOutputTokens", () => {
|
||||
const out = apply("gemini-cli", "gemini-3.1-pro-preview", {
|
||||
request: { generationConfig: { maxOutputTokens: 128 } },
|
||||
reasoning_effort: "high",
|
||||
}, "gemini-cli");
|
||||
expect(out.request.generationConfig.thinkingConfig).toEqual({ thinkingLevel: "high", includeThoughts: true });
|
||||
expect(out.request.generationConfig.maxOutputTokens).toBe(65535);
|
||||
});
|
||||
it("gemini-2.5 → thinkingBudget", () => {
|
||||
const out = apply("gemini", "gemini-2.5-flash", { reasoning_effort: "high" }, "gemini");
|
||||
expect(out.generationConfig.thinkingConfig.thinkingBudget).toBe(24576);
|
||||
expect(out.generationConfig.thinkingConfig.thinkingLevel).toBeUndefined();
|
||||
});
|
||||
it("gemini-2.5 budget thinking keeps enough room for answer tokens", () => {
|
||||
const out = apply("gemini-cli", "gemini-2.5-pro", {
|
||||
request: { generationConfig: { maxOutputTokens: 1024 } },
|
||||
reasoning_effort: "high",
|
||||
}, "gemini-cli");
|
||||
expect(out.request.generationConfig.thinkingConfig).toEqual({ thinkingBudget: 24576, includeThoughts: true });
|
||||
expect(out.request.generationConfig.maxOutputTokens).toBe(32768);
|
||||
});
|
||||
it("GLM off → enable_thinking:false (not thinking.disabled)", () => {
|
||||
const out = apply("openai", "glm-4.6", { reasoning_effort: "none" }, "glm");
|
||||
expect(out.enable_thinking).toBe(false);
|
||||
@@ -110,6 +126,16 @@ describe("applyThinking per provider format", () => {
|
||||
const out = apply("openai", "kimi-k2.6", { reasoning_effort: "high" }, "kimi");
|
||||
expect(out.reasoning_effort).toBe("high");
|
||||
});
|
||||
it("Kimi auto → supported reasoning_effort", () => {
|
||||
const out = apply("openai", "kimi-k2.7", { reasoning_effort: "auto" }, "kimchi");
|
||||
expect(out.reasoning_effort).toBe("high");
|
||||
});
|
||||
it("Kimi unsupported OpenAI levels → supported reasoning_effort", () => {
|
||||
const minimal = apply("openai", "kimi-k2.7", { reasoning_effort: "minimal" }, "kimchi");
|
||||
const xhigh = apply("openai", "kimi-k2.7", { reasoning_effort: "xhigh" }, "kimchi");
|
||||
expect(minimal.reasoning_effort).toBe("low");
|
||||
expect(xhigh.reasoning_effort).toBe("max");
|
||||
});
|
||||
it("MiniMax M3 → adaptive", () => {
|
||||
const out = apply("claude", "MiniMax-M3", { reasoning_effort: "high" }, "minimax");
|
||||
expect(out.thinking).toEqual({ type: "adaptive" });
|
||||
|
||||
Reference in New Issue
Block a user