Merge remote-tracking branch 'origin/master' into gitea/feature/end
Resolved conflicts taking origin/master (v0.5.55) as canonical, with local features re-applied: - runtime log level (LOG_LEVEL env + dashboard Settings → Logging, applied immediately and persisted across restarts) - free/noAuth provider enable/disable toggle via providerStrategies.enabled - parallel model testing (Test All Models / Test Selected Keys)
This commit is contained in:
@@ -118,6 +118,9 @@ exports[`GOLDEN request: OpenAI → Claude > reasoning_effort → adaptive outpu
|
||||
"type": "text",
|
||||
},
|
||||
],
|
||||
"thinking": {
|
||||
"type": "adaptive",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
|
||||
@@ -38,6 +38,25 @@ exports[`GOLDEN buildHeaders (default executor providers) > alicode-intl → hea
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > alims-intl → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
"nonStream": {
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
"oauth": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > anthropic → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
@@ -66,6 +85,31 @@ exports[`GOLDEN buildHeaders (default executor providers) > anthropic → header
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > api-airforce → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
"HTTP-Referer": "https://endpoint-proxy.local",
|
||||
"X-Title": "Endpoint Proxy",
|
||||
},
|
||||
"nonStream": {
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
"HTTP-Referer": "https://endpoint-proxy.local",
|
||||
"X-Title": "Endpoint Proxy",
|
||||
},
|
||||
"oauth": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
"HTTP-Referer": "https://endpoint-proxy.local",
|
||||
"X-Title": "Endpoint Proxy",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > assemblyai → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
@@ -85,6 +129,44 @@ exports[`GOLDEN buildHeaders (default executor providers) > assemblyai → heade
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > baidu → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
"nonStream": {
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
"oauth": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > bazaarlink → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
"nonStream": {
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
"oauth": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > blackbox → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
@@ -104,6 +186,25 @@ exports[`GOLDEN buildHeaders (default executor providers) > blackbox → headers
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > bluesminds → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
"nonStream": {
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
"oauth": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > byteplus → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
@@ -268,6 +369,52 @@ exports[`GOLDEN buildHeaders (default executor providers) > cline → headers (a
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > clinepass → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
"HTTP-Referer": "https://cline.bot",
|
||||
"User-Agent": "9Router/0.5.50",
|
||||
"X-CLIENT-TYPE": "9router",
|
||||
"X-CLIENT-VERSION": "0.5.50",
|
||||
"X-CORE-VERSION": "0.5.50",
|
||||
"X-IS-MULTIROOT": "false",
|
||||
"X-PLATFORM": "linux",
|
||||
"X-PLATFORM-VERSION": "v24.15.0",
|
||||
"X-Title": "Cline",
|
||||
},
|
||||
"nonStream": {
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
"HTTP-Referer": "https://cline.bot",
|
||||
"User-Agent": "9Router/0.5.50",
|
||||
"X-CLIENT-TYPE": "9router",
|
||||
"X-CLIENT-VERSION": "0.5.50",
|
||||
"X-CORE-VERSION": "0.5.50",
|
||||
"X-IS-MULTIROOT": "false",
|
||||
"X-PLATFORM": "linux",
|
||||
"X-PLATFORM-VERSION": "v24.15.0",
|
||||
"X-Title": "Cline",
|
||||
},
|
||||
"oauth": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
"HTTP-Referer": "https://cline.bot",
|
||||
"User-Agent": "9Router/0.5.50",
|
||||
"X-CLIENT-TYPE": "9router",
|
||||
"X-CLIENT-VERSION": "0.5.50",
|
||||
"X-CORE-VERSION": "0.5.50",
|
||||
"X-IS-MULTIROOT": "false",
|
||||
"X-PLATFORM": "linux",
|
||||
"X-PLATFORM-VERSION": "v24.15.0",
|
||||
"X-Title": "Cline",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > cloudflare-ai → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
@@ -324,6 +471,43 @@ exports[`GOLDEN buildHeaders (default executor providers) > codebuddy-cn → hea
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > codebuddy-intl → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": "IDE/2.108.1 CodeBuddy/2.108.1",
|
||||
"X-IDE-Name": "IDE",
|
||||
"X-IDE-Type": "IDE",
|
||||
"X-Product": "SaaS",
|
||||
"x-codebuddy-request": "1",
|
||||
"x-requested-with": "XMLHttpRequest",
|
||||
},
|
||||
"nonStream": {
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": "IDE/2.108.1 CodeBuddy/2.108.1",
|
||||
"X-IDE-Name": "IDE",
|
||||
"X-IDE-Type": "IDE",
|
||||
"X-Product": "SaaS",
|
||||
"x-codebuddy-request": "1",
|
||||
"x-requested-with": "XMLHttpRequest",
|
||||
},
|
||||
"oauth": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": "IDE/2.108.1 CodeBuddy/2.108.1",
|
||||
"X-IDE-Name": "IDE",
|
||||
"X-IDE-Type": "IDE",
|
||||
"X-Product": "SaaS",
|
||||
"x-codebuddy-request": "1",
|
||||
"x-requested-with": "XMLHttpRequest",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > cohere → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
@@ -381,6 +565,25 @@ exports[`GOLDEN buildHeaders (default executor providers) > deepseek → headers
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > featherless → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
"nonStream": {
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
"oauth": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > fireworks → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
@@ -482,6 +685,34 @@ exports[`GOLDEN buildHeaders (default executor providers) > glm-cn → headers (
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > grok-cli → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": "grok-shell/0.2.99 (linux; x86_64)",
|
||||
"x-grok-client-identifier": "grok-shell",
|
||||
"x-grok-client-version": "0.2.99",
|
||||
},
|
||||
"nonStream": {
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": "grok-shell/0.2.99 (linux; x86_64)",
|
||||
"x-grok-client-identifier": "grok-shell",
|
||||
"x-grok-client-version": "0.2.99",
|
||||
},
|
||||
"oauth": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": "grok-shell/0.2.99 (linux; x86_64)",
|
||||
"x-grok-client-identifier": "grok-shell",
|
||||
"x-grok-client-version": "0.2.99",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > groq → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
@@ -520,6 +751,25 @@ exports[`GOLDEN buildHeaders (default executor providers) > hyperbolic → heade
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > kilo-gateway → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
"nonStream": {
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
"oauth": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > kilocode → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
@@ -539,6 +789,28 @@ exports[`GOLDEN buildHeaders (default executor providers) > kilocode → headers
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > kimchi → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": "kimchi/0.1.50",
|
||||
},
|
||||
"nonStream": {
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": "kimchi/0.1.50",
|
||||
},
|
||||
"oauth": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": "kimchi/0.1.50",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > kimi → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
@@ -601,6 +873,25 @@ exports[`GOLDEN buildHeaders (default executor providers) > kimi-coding → head
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > llm7 → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
"nonStream": {
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
"oauth": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > minimax → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
@@ -689,6 +980,25 @@ exports[`GOLDEN buildHeaders (default executor providers) > mmf → headers (api
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > morph → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
"nonStream": {
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
"oauth": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > nanobanana → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
@@ -828,6 +1138,63 @@ exports[`GOLDEN buildHeaders (default executor providers) > perplexity → heade
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > perplexity-agent → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
"nonStream": {
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
"oauth": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > poolside → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
"nonStream": {
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
"oauth": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > sambanova → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
"nonStream": {
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
"oauth": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > siliconflow → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
@@ -847,6 +1214,25 @@ exports[`GOLDEN buildHeaders (default executor providers) > siliconflow → head
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > tencent → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
"nonStream": {
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
"oauth": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > together → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
@@ -866,6 +1252,44 @@ exports[`GOLDEN buildHeaders (default executor providers) > together → headers
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > tokenrouter → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
"nonStream": {
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
"oauth": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > venice → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
"nonStream": {
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
"oauth": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > vercel-ai-gateway → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
@@ -942,6 +1366,28 @@ exports[`GOLDEN buildHeaders (default executor providers) > xiaomi-mimo → head
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > zed → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "<CRED>",
|
||||
"Content-Type": "application/json",
|
||||
"content-type": "application/json",
|
||||
},
|
||||
"nonStream": {
|
||||
"Authorization": "<CRED>",
|
||||
"Content-Type": "application/json",
|
||||
"content-type": "application/json",
|
||||
},
|
||||
"oauth": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "<CRED>",
|
||||
"Content-Type": "application/json",
|
||||
"content-type": "application/json",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > alicode → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://coding.dashscope.aliyuncs.com/v1/chat/completions",
|
||||
@@ -956,6 +1402,13 @@ exports[`GOLDEN buildUrl (default executor providers) > alicode-intl → url (st
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > alims-intl → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://dashscope-intl.aliyuncs.com/compatible-mode/v1/chat/completions",
|
||||
"stream": "https://dashscope-intl.aliyuncs.com/compatible-mode/v1/chat/completions",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > anthropic → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://api.anthropic.com/v1/messages",
|
||||
@@ -963,6 +1416,13 @@ exports[`GOLDEN buildUrl (default executor providers) > anthropic → url (strea
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > api-airforce → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://api.airforce/v1/chat/completions",
|
||||
"stream": "https://api.airforce/v1/chat/completions",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > assemblyai → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://api.assemblyai.com/v1/audio/transcriptions",
|
||||
@@ -970,6 +1430,20 @@ exports[`GOLDEN buildUrl (default executor providers) > assemblyai → url (stre
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > baidu → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://qianfan.baidubce.com/v2/chat/completions",
|
||||
"stream": "https://qianfan.baidubce.com/v2/chat/completions",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > bazaarlink → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://bazaarlink.ai/api/v1/chat/completions",
|
||||
"stream": "https://bazaarlink.ai/api/v1/chat/completions",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > blackbox → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://api.blackbox.ai/chat/completions",
|
||||
@@ -977,6 +1451,13 @@ exports[`GOLDEN buildUrl (default executor providers) > blackbox → url (stream
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > bluesminds → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://api.bluesminds.com/v1/chat/completions",
|
||||
"stream": "https://api.bluesminds.com/v1/chat/completions",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > byteplus → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://ark.ap-southeast.bytepluses.com/api/coding/v3/chat/completions",
|
||||
@@ -1012,6 +1493,13 @@ exports[`GOLDEN buildUrl (default executor providers) > cline → url (stream +
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > clinepass → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://api.cline.bot/api/v1/chat/completions",
|
||||
"stream": "https://api.cline.bot/api/v1/chat/completions",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > cloudflare-ai → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://api.cloudflare.com/client/v4/accounts/ACC123/ai/v1/chat/completions",
|
||||
@@ -1026,6 +1514,13 @@ exports[`GOLDEN buildUrl (default executor providers) > codebuddy-cn → url (st
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > codebuddy-intl → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://www.codebuddy.ai/v2/chat/completions",
|
||||
"stream": "https://www.codebuddy.ai/v2/chat/completions",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > cohere → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://api.cohere.ai/v1/chat/completions",
|
||||
@@ -1047,6 +1542,13 @@ exports[`GOLDEN buildUrl (default executor providers) > deepseek → url (stream
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > featherless → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://api.featherless.ai/v1/chat/completions",
|
||||
"stream": "https://api.featherless.ai/v1/chat/completions",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > fireworks → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://api.fireworks.ai/inference/v1/chat/completions",
|
||||
@@ -1082,6 +1584,13 @@ exports[`GOLDEN buildUrl (default executor providers) > glm-cn → url (stream +
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > grok-cli → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://cli-chat-proxy.grok.com/v1/responses",
|
||||
"stream": "https://cli-chat-proxy.grok.com/v1/responses",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > groq → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://api.groq.com/openai/v1/chat/completions",
|
||||
@@ -1096,6 +1605,13 @@ exports[`GOLDEN buildUrl (default executor providers) > hyperbolic → url (stre
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > kilo-gateway → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://api.kilo.ai/api/gateway/chat/completions",
|
||||
"stream": "https://api.kilo.ai/api/gateway/chat/completions",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > kilocode → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://api.kilo.ai/api/openrouter/chat/completions",
|
||||
@@ -1103,6 +1619,13 @@ exports[`GOLDEN buildUrl (default executor providers) > kilocode → url (stream
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > kimchi → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://llm.kimchi.dev/openai/v1/chat/completions",
|
||||
"stream": "https://llm.kimchi.dev/openai/v1/chat/completions",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > kimi → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://api.kimi.com/coding/v1/messages?beta=true",
|
||||
@@ -1117,6 +1640,13 @@ exports[`GOLDEN buildUrl (default executor providers) > kimi-coding → url (str
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > llm7 → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://api.llm7.io/v1/chat/completions",
|
||||
"stream": "https://api.llm7.io/v1/chat/completions",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > minimax → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://api.minimax.io/anthropic/v1/messages?beta=true",
|
||||
@@ -1145,6 +1675,13 @@ exports[`GOLDEN buildUrl (default executor providers) > mmf → url (stream + no
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > morph → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://api.morphllm.com/v1/chat/completions",
|
||||
"stream": "https://api.morphllm.com/v1/chat/completions",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > nanobanana → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://api.nanobananaapi.ai/v1/chat/completions",
|
||||
@@ -1194,6 +1731,27 @@ exports[`GOLDEN buildUrl (default executor providers) > perplexity → url (stre
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > perplexity-agent → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://api.perplexity.ai/v1/responses",
|
||||
"stream": "https://api.perplexity.ai/v1/responses",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > poolside → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://inference.poolside.ai/v1/chat/completions",
|
||||
"stream": "https://inference.poolside.ai/v1/chat/completions",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > sambanova → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://api.sambanova.ai/v1/chat/completions",
|
||||
"stream": "https://api.sambanova.ai/v1/chat/completions",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > siliconflow → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://api.siliconflow.com/v1/chat/completions",
|
||||
@@ -1201,6 +1759,13 @@ exports[`GOLDEN buildUrl (default executor providers) > siliconflow → url (str
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > tencent → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://api.hunyuan.cloud.tencent.com/v1/chat/completions",
|
||||
"stream": "https://api.hunyuan.cloud.tencent.com/v1/chat/completions",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > together → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://api.together.xyz/v1/chat/completions",
|
||||
@@ -1208,6 +1773,20 @@ exports[`GOLDEN buildUrl (default executor providers) > together → url (stream
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > tokenrouter → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://api.tokenrouter.com/v1/chat/completions",
|
||||
"stream": "https://api.tokenrouter.com/v1/chat/completions",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > venice → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://api.venice.ai/api/v1/chat/completions",
|
||||
"stream": "https://api.venice.ai/api/v1/chat/completions",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > vercel-ai-gateway → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://ai-gateway.vercel.sh/v1/chat/completions",
|
||||
@@ -1235,3 +1814,10 @@ exports[`GOLDEN buildUrl (default executor providers) > xiaomi-mimo → url (str
|
||||
"stream": "https://api.xiaomimimo.com/v1/chat/completions",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > zed → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://cloud.zed.dev/completions",
|
||||
"stream": "https://cloud.zed.dev/completions",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -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]");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -20,9 +20,7 @@ describe("Codex CLI Responses → OpenAI", () => {
|
||||
expect(asst?.tool_calls?.length ?? 0, "empty tool_calls[] produced").toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
// openai-responses.js:109-110 — arguments passed through without ensuring string type
|
||||
// KNOWN BUG
|
||||
it.fails("function_call arguments end up as a string", () => {
|
||||
it("function_call arguments end up as a string", () => {
|
||||
const out = R2O({
|
||||
input: [{ type: "function_call", call_id: "c1", name: "f", arguments: { a: 1 } }],
|
||||
});
|
||||
@@ -46,6 +44,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);
|
||||
|
||||
@@ -5,8 +5,34 @@ import { translateRequest } from "../../open-sse/translator/index.js";
|
||||
import { FORMATS } from "../../open-sse/translator/formats.js";
|
||||
|
||||
const O2K = (body) => translateRequest(FORMATS.OPENAI, FORMATS.KIRO, "m", body, true, null, "kiro");
|
||||
const R2K = (model, body) => translateRequest(
|
||||
FORMATS.OPENAI_RESPONSES,
|
||||
FORMATS.KIRO,
|
||||
model,
|
||||
body,
|
||||
true,
|
||||
null,
|
||||
"kiro"
|
||||
);
|
||||
|
||||
describe("OpenAI → Kiro", () => {
|
||||
it.each([
|
||||
["high", "gpt-5.6-sol"],
|
||||
["medium", "gpt-5.6-terra"],
|
||||
["low", "gpt-5.6-luna"],
|
||||
])("preserves Responses reasoning.effort %s through the full Kiro route", (effort, model) => {
|
||||
const out = R2K(model, {
|
||||
input: "Use the requested effort",
|
||||
reasoning: { effort },
|
||||
});
|
||||
|
||||
expect(out.additionalModelRequestFields).toEqual({
|
||||
reasoning: { effort },
|
||||
});
|
||||
expect(out.systemPrompt || "").not.toContain("<thinking_mode>");
|
||||
expect(out.systemPrompt || "").not.toContain("<max_thinking_length>");
|
||||
});
|
||||
|
||||
// openai-to-kiro.js — safeJSONParse guards bad tool-call JSON (fixed in PR #1582)
|
||||
it("malformed tool arguments do not throw the whole request", () => {
|
||||
expect(() =>
|
||||
|
||||
@@ -67,6 +67,122 @@ describe("OpenAI → Claude context mapping", () => {
|
||||
expect(JSON.stringify(out), "remote image dropped").toContain("pic.png");
|
||||
});
|
||||
|
||||
// claude.js hasValidContent() — a user message whose content is only an
|
||||
// image (no text block) was filtered out by prepareClaudeRequest's
|
||||
// "drop empty messages" pass, so an image-only turn (e.g. a vision
|
||||
// describe request with no accompanying prompt text in the user message)
|
||||
// produced an empty `messages` array and Anthropic rejected the request
|
||||
// with "messages: at least one message is required".
|
||||
it("user message with only an image is not dropped as empty", () => {
|
||||
const out = T({
|
||||
messages: [
|
||||
{ role: "system", content: "Describe the image." },
|
||||
{ role: "user", content: [
|
||||
{ type: "image_url", image_url: { url: "data:image/png;base64,AAAA" } },
|
||||
] },
|
||||
],
|
||||
});
|
||||
expect(out.messages.length, "image-only user message was dropped").toBeGreaterThan(0);
|
||||
expect(out.messages[0].content).toEqual(
|
||||
expect.arrayContaining([expect.objectContaining({ type: "image" })])
|
||||
);
|
||||
});
|
||||
|
||||
// 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",
|
||||
|
||||
@@ -6,8 +6,8 @@ import "./registerAll.js";
|
||||
import { translateRequest, translateResponse } from "../../open-sse/translator/index.js";
|
||||
import { FORMATS } from "../../open-sse/translator/formats.js";
|
||||
|
||||
const C2K = (body) =>
|
||||
translateRequest(FORMATS.CLAUDE, FORMATS.KIRO, "claude-sonnet-4.5", body, true, null, "kiro");
|
||||
const C2K = (body, credentials = null, model = "claude-sonnet-4.5") =>
|
||||
translateRequest(FORMATS.CLAUDE, FORMATS.KIRO, model, body, true, credentials, "kiro");
|
||||
|
||||
describe("Claude → Kiro (direct route)", () => {
|
||||
it("produces a Kiro conversationState payload", () => {
|
||||
@@ -16,6 +16,27 @@ describe("Claude → Kiro (direct route)", () => {
|
||||
expect(out.conversationState.currentMessage.userInputMessage.content).toContain("hello");
|
||||
});
|
||||
|
||||
it("keeps conversationId stable from client session headers and replays frozen msg0", () => {
|
||||
const credentials = {
|
||||
rawHeaders: { "x-session-id": "hermes-session-123-claude-replay" },
|
||||
connectionId: "kiro-account-1",
|
||||
};
|
||||
const first = C2K({ messages: [{ role: "user", content: "first" }] }, credentials);
|
||||
const second = C2K({ messages: [{ role: "user", content: "second" }] }, credentials);
|
||||
|
||||
expect(first.conversationState.conversationId).toBe("hermes-session-123-claude-replay");
|
||||
expect(second.conversationState.conversationId).toBe("hermes-session-123-claude-replay");
|
||||
expect(first.conversationState.agentContinuationId).toBeTruthy();
|
||||
expect(second.conversationState.agentContinuationId).toBe(first.conversationState.agentContinuationId);
|
||||
expect(first.conversationState.agentTaskType).toBe("vibe");
|
||||
expect(second.conversationState.history[0].userInputMessage.content).toBe(
|
||||
first.conversationState.currentMessage.userInputMessage.content
|
||||
);
|
||||
expect(second.conversationState.history[0].userInputMessage.modelId).toBe("claude-sonnet-4.5");
|
||||
expect(second.conversationState.currentMessage.userInputMessage.content).toContain("Current time");
|
||||
expect(second.conversationState.currentMessage.userInputMessage.content).toContain("second");
|
||||
});
|
||||
|
||||
it("guard 1: with no tools, a dangling tool_result is flattened to text (no structured ref)", () => {
|
||||
// Client omitted `tools` but kept a tool_result after compaction.
|
||||
const out = C2K({
|
||||
@@ -60,20 +81,125 @@ describe("Claude → Kiro (direct route)", () => {
|
||||
null,
|
||||
"kiro"
|
||||
);
|
||||
expect(out.conversationState.currentMessage.userInputMessage.content).toContain(
|
||||
expect(out.systemPrompt).toContain(
|
||||
"<thinking_mode>enabled</thinking_mode>"
|
||||
);
|
||||
expect(out.agentMode).toBe("vibe");
|
||||
});
|
||||
|
||||
it("maps output_config.effort high to Kiro max_thinking_length 24576", () => {
|
||||
it("does not send additionalModelRequestFields for Kiro models without effort support", () => {
|
||||
const out = C2K({
|
||||
output_config: { effort: "high" },
|
||||
messages: [{ role: "user", content: "think with adaptive effort" }],
|
||||
});
|
||||
|
||||
expect(out.conversationState.currentMessage.userInputMessage.content).toContain(
|
||||
"<max_thinking_length>24576</max_thinking_length>"
|
||||
expect(out.additionalModelRequestFields).toBeUndefined();
|
||||
expect(out.thinking).toBeUndefined();
|
||||
expect(out.systemPrompt).toContain("<max_thinking_length>24576</max_thinking_length>");
|
||||
});
|
||||
|
||||
it("normalizes an unsupported Kiro intensity suffix while preserving agentic behavior", () => {
|
||||
const out = C2K(
|
||||
{ messages: [{ role: "user", content: "hello" }] },
|
||||
null,
|
||||
"claude-sonnet-4.5-thinking-agentic(high)",
|
||||
);
|
||||
|
||||
expect(out.conversationState.currentMessage.userInputMessage.modelId).toBe("claude-sonnet-4.5");
|
||||
expect(out.additionalModelRequestFields).toBeUndefined();
|
||||
expect(out.systemPrompt).toContain("CHUNKED WRITE PROTOCOL");
|
||||
});
|
||||
|
||||
it("maps output_config.effort high to Kiro CLI-style additionalModelRequestFields for effort models", () => {
|
||||
const out = C2K({
|
||||
output_config: { effort: "high" },
|
||||
messages: [{ role: "user", content: "think with adaptive effort" }],
|
||||
}, null, "claude-sonnet-5");
|
||||
|
||||
expect(out.additionalModelRequestFields).toEqual({
|
||||
thinking: { type: "adaptive", display: "summarized" },
|
||||
output_config: { effort: "high" },
|
||||
});
|
||||
expect(out.thinking).toBeUndefined();
|
||||
expect(out.systemPrompt).toContain("<max_thinking_length>24576</max_thinking_length>");
|
||||
});
|
||||
|
||||
it("maps Claude-format effort to GPT-5.6 reasoning fields without legacy prompt tags", () => {
|
||||
const out = C2K({
|
||||
output_config: { effort: "low" },
|
||||
messages: [{ role: "user", content: "think lightly" }],
|
||||
}, null, "gpt-5.6-sol");
|
||||
|
||||
expect(out.additionalModelRequestFields).toEqual({
|
||||
reasoning: { effort: "low" },
|
||||
});
|
||||
expect(out.systemPrompt || "").not.toContain("<thinking_mode>");
|
||||
expect(out.systemPrompt || "").not.toContain("<max_thinking_length>");
|
||||
});
|
||||
|
||||
it.each(["auto", "minimal", "ultra"])(
|
||||
"keeps the legacy thinking fallback for unsupported GPT-5.6 effort %s",
|
||||
(effort) => {
|
||||
const out = C2K({
|
||||
output_config: { effort },
|
||||
messages: [{ role: "user", content: "Use legacy thinking" }],
|
||||
}, null, "gpt-5.6-sol");
|
||||
|
||||
expect(out.additionalModelRequestFields).toBeUndefined();
|
||||
expect(out.systemPrompt).toContain("<thinking_mode>enabled</thinking_mode>");
|
||||
expect(out.systemPrompt).toContain("<max_thinking_length>");
|
||||
}
|
||||
);
|
||||
|
||||
it.each(["none", "off", "disabled"])(
|
||||
"keeps GPT-5.6 reasoning intentionally disabled for effort %s",
|
||||
(effort) => {
|
||||
const out = C2K({
|
||||
output_config: { effort },
|
||||
messages: [{ role: "user", content: "Do not reason" }],
|
||||
}, null, "gpt-5.6-sol");
|
||||
|
||||
expect(out.additionalModelRequestFields).toBeUndefined();
|
||||
expect(out.systemPrompt || "").not.toContain("<thinking_mode>");
|
||||
expect(out.systemPrompt || "").not.toContain("<max_thinking_length>");
|
||||
}
|
||||
);
|
||||
|
||||
it("keeps explicit Claude effort ahead of an injected OpenAI effort", () => {
|
||||
const out = C2K({
|
||||
output_config: { effort: "low" },
|
||||
reasoning_effort: "high",
|
||||
messages: [{ role: "user", content: "honor the client effort" }],
|
||||
}, null, "gpt-5.6-sol");
|
||||
|
||||
expect(out.additionalModelRequestFields).toEqual({
|
||||
reasoning: { effort: "low" },
|
||||
});
|
||||
});
|
||||
|
||||
it("sends Claude system as top-level systemPrompt and keeps a user-content fallback", () => {
|
||||
const out = C2K({
|
||||
system: "system-only instruction",
|
||||
messages: [{ role: "user", content: "hello" }],
|
||||
});
|
||||
|
||||
expect(out.systemPrompt).toContain("system-only instruction");
|
||||
expect(out.conversationState.currentMessage.userInputMessage.content).toContain("system-only instruction");
|
||||
});
|
||||
|
||||
it("keeps top-level systemPrompt stable across turns", () => {
|
||||
const first = C2K({
|
||||
system: "stable instruction",
|
||||
messages: [{ role: "user", content: "first" }],
|
||||
});
|
||||
const second = C2K({
|
||||
system: "stable instruction",
|
||||
messages: [{ role: "user", content: "second" }],
|
||||
});
|
||||
|
||||
expect(first.systemPrompt).toBe(second.systemPrompt);
|
||||
expect(first.systemPrompt).not.toContain("Current time");
|
||||
expect(first.conversationState.currentMessage.userInputMessage.content).toContain("Current time");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -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", () => {
|
||||
|
||||
@@ -18,7 +18,7 @@ const SPECIAL_CRED = {
|
||||
// Chúng được lock riêng ở 11-provider edge tests / unit test chuyên biệt.
|
||||
const SPECIALIZED = new Set([
|
||||
"antigravity", "azure", "gemini-cli", "github", "iflow", "qoder", "kiro",
|
||||
"codex", "cursor", "vertex", "vertex-partner", "qwen", "opencode",
|
||||
"codex", "cursor", "vertex", "vertex-partner", "opencode",
|
||||
"opencode-go", "grok-web", "perplexity-web", "ollama-local", "commandcode",
|
||||
"xiaomi-tokenplan", "mimo-free",
|
||||
]);
|
||||
|
||||
@@ -18,6 +18,12 @@ describe("parseSuffix", () => {
|
||||
it("parses level suffix", () => {
|
||||
expect(parseSuffix("gpt-5(high)")).toEqual({ cleanModel: "gpt-5", override: { mode: "level", level: "high" } });
|
||||
});
|
||||
it("parses ultra suffix", () => {
|
||||
expect(parseSuffix("gpt-5.6-sol(ultra)")).toEqual({
|
||||
cleanModel: "gpt-5.6-sol",
|
||||
override: { mode: "level", level: "ultra" },
|
||||
});
|
||||
});
|
||||
it("parses numeric budget suffix", () => {
|
||||
expect(parseSuffix("model(8192)")).toEqual({ cleanModel: "model", override: { mode: "budget", budget: 8192 } });
|
||||
});
|
||||
@@ -55,10 +61,14 @@ describe("extractThinking", () => {
|
||||
});
|
||||
|
||||
describe("applyThinking per provider format", () => {
|
||||
it("claude 4.6+ → adaptive output_config (no budget_tokens)", () => {
|
||||
it("claude 4.6+ → adaptive thinking + output_config (no budget_tokens)", () => {
|
||||
const out = apply("claude", "claude-opus-4.7", { reasoning_effort: "high" }, "claude");
|
||||
expect(out.output_config).toEqual({ effort: "high" });
|
||||
expect(out.thinking).toBeUndefined();
|
||||
// Anthropic: on Opus 4.6/4.7/4.8 and Sonnet 4.6 thinking stays OFF unless
|
||||
// thinking:{type:"adaptive"} is sent explicitly; output_config alone is not
|
||||
// enough (and Anthropic-compatible shims like Copilot default off even on
|
||||
// Sonnet 5). Both fields together are the documented adaptive shape.
|
||||
expect(out.thinking).toEqual({ type: "adaptive" });
|
||||
});
|
||||
it("claude haiku → enabled+budget", () => {
|
||||
const out = apply("claude", "claude-haiku-4.5", { reasoning_effort: "high" }, "claude");
|
||||
@@ -78,11 +88,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);
|
||||
@@ -106,6 +132,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" });
|
||||
@@ -127,6 +163,25 @@ describe("applyThinking per provider format", () => {
|
||||
const out = apply("openai", "gpt-5.3-codex", { reasoning_effort: "xhigh" }, "codex");
|
||||
expect(out.reasoning_effort).toBe("xhigh");
|
||||
});
|
||||
it.each([
|
||||
["gpt-5.6-sol", "max", "max"],
|
||||
["gpt-5.6-sol", "ultra", "ultra"],
|
||||
["gpt-5.6-terra", "max", "max"],
|
||||
["gpt-5.6-terra", "ultra", "ultra"],
|
||||
["gpt-5.6-luna", "max", "max"],
|
||||
["gpt-5.6-luna", "ultra", "max"],
|
||||
])("normalizes Codex %s effort %s to %s", (model, effort, expected) => {
|
||||
const out = apply("openai-responses", model, { reasoning: { effort } }, "codex");
|
||||
expect(out.reasoning_effort).toBe(expected);
|
||||
});
|
||||
it("applies a supported Codex Ultra suffix", () => {
|
||||
const out = apply("openai-responses", "gpt-5.6-sol(ultra)", {}, "codex");
|
||||
expect(out.reasoning_effort).toBe("ultra");
|
||||
});
|
||||
it("keeps Codex-only GPT-5.6 levels out of Kiro translation", () => {
|
||||
const out = apply("openai", "gpt-5.6-sol", { reasoning_effort: "max" }, "kiro");
|
||||
expect(out.reasoning_effort).toBe("xhigh");
|
||||
});
|
||||
});
|
||||
|
||||
describe("extractReasoningText (response shapes)", () => {
|
||||
|
||||
Reference in New Issue
Block a user