mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-11 17:52:31 +03:00
* fix(sse): apply Azure request-param rules on the azure-ai wire path
Azure rejects several stock Chat Completions params on its newer deployments
and returns HTTP 400 rather than ignoring them:
max_tokens -> 'max_tokens' is not supported with this model.
Use 'max_completion_tokens' instead.
reasoning_effort -> Function tools with reasoning_effort are not supported.
Those rules lived inline in AzureOpenAIExecutor, so they only covered the
azure-openai provider. azure-ai (Azure AI Foundry) had no executor entry and
fell through to the bare DefaultExecutor, so the SAME Azure deployment
succeeded on one connection and 400'd on the other. Every agentic client sends
tools on every turn, so azure-ai failed on the first request.
Extract the rules to open-sse/executors/azureParamRules.ts, add an
AzureAiExecutor that inherits DefaultExecutor's azure-ai URL/header/apiType
handling unchanged and applies the shared rules, and register it for azure-ai.
Also widen the deployment pattern to cover gpt-chat-latest: it is a moving
alias that resolves to a GPT-5-era model and rejects max_tokens, but carries no
version number for the token-boundary pattern to key on. Verified against the
base regex - gpt-chat-latest did not match, which is exactly the observed 400.
Regression guard: tests/unit/azure-param-rules.test.ts, including an assertion
that getExecutor("azure-ai") no longer resolves to a bare DefaultExecutor.
* fix(sse): clamp Azure gpt-4o-mini completion tokens to its 16384 ceiling
Azure gpt-4o-mini deployments accept at most 16384 completion tokens and 400 on
anything larger:
max_tokens is too large: 32000. This model supports at most 16384 completion
tokens, whereas you provided 32000.
The 32000 is OmniRoute's own doing: adjustMaxTokens raises any smaller
max_tokens to DEFAULT_MIN_TOKENS (32000) whenever tools are present, to avoid
truncated tool arguments. That floor has no upper bound, so an agentic client
asking for far less still trips the model ceiling on its first turn.
Add scoped maxOutputCap rules in paramSupport.ts for both Azure wire paths.
PROVIDER_MAX_TOKENS is the wrong lever here - it is provider-wide, and the same
Azure resource also serves GPT-5 deployments with a much higher ceiling.
Regression guard: tests/unit/azure-max-output-clamp.test.ts, which also pins
that the clamp does not leak to gpt-5.1 or to gpt-4o-mini on other providers.
---------
Co-authored-by: Mihaly Bodo <michael@proton-quantum.com>
305 lines
14 KiB
TypeScript
305 lines
14 KiB
TypeScript
import { AntigravityExecutor } from "./antigravity.ts";
|
|
import { GithubExecutor } from "./github.ts";
|
|
import { GheCopilotExecutor } from "./ghe-copilot.ts";
|
|
import { QoderExecutor } from "./qoder.ts";
|
|
import { KiroExecutor } from "./kiro.ts";
|
|
import { CodexExecutor } from "./codex.ts";
|
|
import { CursorExecutor } from "./cursor.ts";
|
|
import { TraeExecutor } from "./trae.ts";
|
|
import { DefaultExecutor } from "./default.ts";
|
|
import { BedrockExecutor } from "./bedrock.ts";
|
|
import { GlmExecutor } from "./glm.ts";
|
|
import { PollinationsExecutor } from "./pollinations.ts";
|
|
import { CloudflareAIExecutor } from "./cloudflare-ai.ts";
|
|
import { OpencodeExecutor } from "./opencode.ts";
|
|
import { PuterExecutor } from "./puter.ts";
|
|
import { VertexExecutor } from "./vertex.ts";
|
|
import { CliproxyapiExecutor } from "./cliproxyapi.ts";
|
|
import { DarioExecutor } from "./dario.ts";
|
|
import { NineRouterExecutor } from "./ninerouter.ts";
|
|
import { PerplexityWebExecutor } from "./perplexity-web.ts";
|
|
import { GrokWebExecutor } from "./grok-web.ts";
|
|
import { GeminiWebExecutor } from "./gemini-web.ts";
|
|
import { GeminiBusinessExecutor } from "./gemini-business.ts";
|
|
import { ChatGptWebExecutor } from "./chatgpt-web.ts";
|
|
import { BlackboxWebExecutor } from "./blackbox-web.ts";
|
|
import { MuseSparkWebExecutor } from "./muse-spark-web.ts";
|
|
import { AzureOpenAIExecutor } from "./azure-openai.ts";
|
|
import { AzureAiExecutor } from "./azure-ai.ts";
|
|
import { CommandCodeExecutor } from "./commandCode.ts";
|
|
import { GitlabExecutor } from "./gitlab.ts";
|
|
import { NlpCloudExecutor } from "./nlpcloud.ts";
|
|
import { WindsurfExecutor } from "./windsurf.ts";
|
|
import { ZedHostedExecutor } from "./zed-hosted.ts";
|
|
import { DevinCliExecutor } from "./devin-cli.ts";
|
|
import { DevinCliAgenticExecutor } from "./devin-cli-agentic.ts";
|
|
import { AuggieExecutor } from "./auggie.ts";
|
|
import { DeepSeekWebExecutor } from "./deepseek-web.ts";
|
|
import { DeepSeekWebWithAutoRefreshExecutor } from "./deepseek-web-with-auto-refresh.ts";
|
|
import { AdaptaWebExecutor } from "./adapta-web.ts";
|
|
import { CopilotWebExecutor } from "./copilot-web.ts";
|
|
import { CopilotM365WebExecutor } from "./copilot-m365-web.ts";
|
|
import { MicrosoftDesignerWebExecutor } from "./microsoft-designer-web.ts";
|
|
import { AdobeFireflyExecutor } from "./adobe-firefly.ts";
|
|
import { VeoAIFreeWebExecutor } from "./veoaifree-web.ts";
|
|
import { DuckDuckGoWebExecutor } from "./duckduckgo-web.ts";
|
|
import { FeloWebExecutor } from "./felo-web.ts";
|
|
import { T3ChatWebExecutor } from "./t3-chat-web.ts";
|
|
import { ClaudeWebExecutor } from "./claude-web.ts";
|
|
import { InnerAiExecutor } from "./inner-ai.ts";
|
|
import { HuggingChatExecutor } from "./huggingchat.ts";
|
|
import { YuanbaoWebExecutor } from "./yuanbao-web.ts";
|
|
import { PoeWebExecutor } from "./poe-web.ts";
|
|
import { VeniceWebExecutor } from "./venice-web.ts";
|
|
import { NotionWebExecutor } from "./notion-web.ts";
|
|
import { V0VercelWebExecutor } from "./v0-vercel-web.ts";
|
|
import { CheaperInferenceExecutor } from "./cheaperinference.ts";
|
|
import { KimiWebExecutor } from "./kimi-web.ts";
|
|
import { DoubaoWebExecutor } from "./doubao-web.ts";
|
|
import { QwenWebExecutor } from "./qwen-web.ts";
|
|
import { RaycastExecutor } from "./raycast.ts";
|
|
import { HailuoWebExecutor } from "./hailuo-web.ts";
|
|
import { ZaiWebExecutor } from "./zai-web.ts";
|
|
import { KimiExecutor } from "./kimi.ts";
|
|
import { MoonshotExecutor } from "./moonshot.ts";
|
|
import { TheOldLlmExecutor } from "./theoldllm.ts";
|
|
import { ChipotleExecutor } from "./chipotle.ts";
|
|
import { LMArenaExecutor } from "./lmarena.ts";
|
|
import { MimocodeExecutor } from "./mimocode.ts";
|
|
import { GrokCliExecutor } from "./grok-cli.ts";
|
|
import { CodeBuddyCnExecutor } from "./codebuddy-cn.ts";
|
|
import { ZenmuxFreeExecutor } from "./zenmux-free.ts";
|
|
import { HyperAgentExecutor } from "./hyperagent.ts";
|
|
import { XaiExecutor } from "./xai.ts";
|
|
import { PromptQlExecutor } from "./promptql.ts";
|
|
|
|
const executors = {
|
|
antigravity: new AntigravityExecutor(),
|
|
agy: new AntigravityExecutor(),
|
|
github: new GithubExecutor(),
|
|
"ghe-copilot": new GheCopilotExecutor(),
|
|
qoder: new QoderExecutor(),
|
|
kiro: new KiroExecutor(),
|
|
"amazon-q": new KiroExecutor("amazon-q"),
|
|
bedrock: new BedrockExecutor(),
|
|
codex: new CodexExecutor(),
|
|
cursor: new CursorExecutor(),
|
|
trae: new TraeExecutor(),
|
|
glm: new GlmExecutor("glm"),
|
|
"glm-cn": new GlmExecutor("glm-cn"),
|
|
glmt: new GlmExecutor("glmt"),
|
|
cu: new CursorExecutor(), // Alias for cursor
|
|
"azure-openai": new AzureOpenAIExecutor(),
|
|
"azure-ai": new AzureAiExecutor(),
|
|
"command-code": new CommandCodeExecutor(),
|
|
cmd: new CommandCodeExecutor(), // Alias
|
|
gitlab: new GitlabExecutor(),
|
|
"gitlab-duo": new GitlabExecutor("gitlab-duo"),
|
|
nlpcloud: new NlpCloudExecutor(),
|
|
pollinations: new PollinationsExecutor(),
|
|
pol: new PollinationsExecutor(), // Alias
|
|
"cloudflare-ai": new CloudflareAIExecutor(),
|
|
cf: new CloudflareAIExecutor(), // Alias
|
|
"opencode-zen": new OpencodeExecutor("opencode-zen"),
|
|
"opencode-go": new OpencodeExecutor("opencode-go"),
|
|
opencode: new OpencodeExecutor("opencode-zen"), // Alias for opencode-zen
|
|
puter: new PuterExecutor(),
|
|
pu: new PuterExecutor(), // Alias
|
|
vertex: new VertexExecutor(),
|
|
"vertex-partner": new VertexExecutor(),
|
|
cliproxyapi: new CliproxyapiExecutor(),
|
|
cpa: new CliproxyapiExecutor(), // Alias
|
|
dario: new DarioExecutor(),
|
|
dr: new DarioExecutor(), // Alias
|
|
"9router": new NineRouterExecutor(),
|
|
nr: new NineRouterExecutor(), // Alias
|
|
"perplexity-web": new PerplexityWebExecutor(),
|
|
"pplx-web": new PerplexityWebExecutor(), // Alias
|
|
"grok-web": new GrokWebExecutor(),
|
|
"claude-web": new ClaudeWebExecutor(),
|
|
"cw-web": new ClaudeWebExecutor(), // Alias
|
|
"gemini-web": new GeminiWebExecutor(),
|
|
gweb: new GeminiWebExecutor(), // Alias
|
|
"gemini-business": new GeminiBusinessExecutor(),
|
|
gembiz: new GeminiBusinessExecutor(), // Alias
|
|
"chatgpt-web": new ChatGptWebExecutor(),
|
|
"cgpt-web": new ChatGptWebExecutor(), // Alias
|
|
"blackbox-web": new BlackboxWebExecutor(),
|
|
"bb-web": new BlackboxWebExecutor(), // Alias
|
|
"muse-spark-web": new MuseSparkWebExecutor(),
|
|
"ms-web": new MuseSparkWebExecutor(), // Alias
|
|
windsurf: new WindsurfExecutor(),
|
|
ws: new WindsurfExecutor(), // Alias
|
|
"zed-hosted": new ZedHostedExecutor(),
|
|
"devin-cli": new DevinCliExecutor(),
|
|
"devin-cli-agentic": new DevinCliAgenticExecutor(),
|
|
devin: new DevinCliExecutor(), // Alias
|
|
"deepseek-web": new DeepSeekWebWithAutoRefreshExecutor(),
|
|
"ds-web": new DeepSeekWebWithAutoRefreshExecutor(), // Alias
|
|
"adapta-web": new AdaptaWebExecutor(),
|
|
"adp-web": new AdaptaWebExecutor(), // Alias
|
|
"copilot-web": new CopilotWebExecutor(),
|
|
"copilot-m365-web": new CopilotM365WebExecutor(),
|
|
copilot: new CopilotWebExecutor(), // Alias
|
|
"microsoft-designer-web": new MicrosoftDesignerWebExecutor(),
|
|
msdesigner: new MicrosoftDesignerWebExecutor(), // Alias
|
|
"adobe-firefly": new AdobeFireflyExecutor(),
|
|
firefly: new AdobeFireflyExecutor(), // Alias
|
|
"veoaifree-web": new VeoAIFreeWebExecutor(),
|
|
"veo-free": new VeoAIFreeWebExecutor(), // Alias
|
|
"duckduckgo-web": new DuckDuckGoWebExecutor(),
|
|
ddgw: new DuckDuckGoWebExecutor(), // Alias
|
|
"felo-web": new FeloWebExecutor(),
|
|
felo: new FeloWebExecutor(), // Alias
|
|
"t3-web": new T3ChatWebExecutor(),
|
|
t3chat: new T3ChatWebExecutor(), // Alias
|
|
"inner-ai": new InnerAiExecutor(),
|
|
"in-ai": new InnerAiExecutor(), // Alias
|
|
huggingchat: new HuggingChatExecutor(),
|
|
hc: new HuggingChatExecutor(), // Alias
|
|
"yuanbao-web": new YuanbaoWebExecutor(),
|
|
ybw: new YuanbaoWebExecutor(), // Alias
|
|
"poe-web": new PoeWebExecutor(),
|
|
// #8969: do NOT alias canonical `poe` (API-key / api.poe.com) to PoeWebExecutor.
|
|
// Registry declares executor:"default"; the hard-coded map previously won and
|
|
// routed API-key traffic to GraphQL /api/gql_POST → HTTP 405.
|
|
"venice-web": new VeniceWebExecutor(),
|
|
ven: new VeniceWebExecutor(), // Alias
|
|
"notion-web": new NotionWebExecutor(),
|
|
nw: new NotionWebExecutor(), // Alias
|
|
promptql: new PromptQlExecutor(),
|
|
pql: new PromptQlExecutor(), // Alias
|
|
"v0-vercel-web": new V0VercelWebExecutor(),
|
|
v0: new V0VercelWebExecutor(), // Alias
|
|
"kimi-web": new KimiWebExecutor(),
|
|
"kimi-coding-apikey": new KimiExecutor("kimi-coding-apikey"), // Legacy alias
|
|
"kimi-coding": new KimiExecutor(), // Alias
|
|
moonshot: new MoonshotExecutor(),
|
|
kimi: new MoonshotExecutor("kimi"), // Hidden legacy Moonshot provider id
|
|
cheaperinference: new CheaperInferenceExecutor(),
|
|
cinf: new CheaperInferenceExecutor("cheaperinference"), // Alias
|
|
"doubao-web": new DoubaoWebExecutor(),
|
|
db: new DoubaoWebExecutor(), // Alias
|
|
"qwen-web": new QwenWebExecutor(),
|
|
raycast: new RaycastExecutor(),
|
|
rc: new RaycastExecutor(), // Alias
|
|
"hailuo-web": new HailuoWebExecutor(),
|
|
"zai-web": new ZaiWebExecutor(),
|
|
zw: new ZaiWebExecutor(), // Alias
|
|
theoldllm: new TheOldLlmExecutor(),
|
|
tllm: new TheOldLlmExecutor(), // Alias
|
|
chipotle: new ChipotleExecutor(),
|
|
pepper: new ChipotleExecutor(), // Alias
|
|
lmarena: new LMArenaExecutor(),
|
|
lma: new LMArenaExecutor(), // Alias
|
|
mimocode: new MimocodeExecutor(),
|
|
mcode: new MimocodeExecutor(), // Alias
|
|
"grok-cli": new GrokCliExecutor(),
|
|
gc: new GrokCliExecutor(), // Alias
|
|
"codebuddy-cn": new CodeBuddyCnExecutor(),
|
|
cbcn: new CodeBuddyCnExecutor(), // Alias for codebuddy-cn
|
|
"zenmux-free": new ZenmuxFreeExecutor(),
|
|
hyperagent: new HyperAgentExecutor(),
|
|
ha: new HyperAgentExecutor(), // Alias
|
|
zmf: new ZenmuxFreeExecutor(), // Alias for zenmux-free
|
|
auggie: new AuggieExecutor(),
|
|
xai: new XaiExecutor(),
|
|
"xai-oauth": new XaiExecutor("xai-oauth"),
|
|
xao: new XaiExecutor("xai-oauth"),
|
|
};
|
|
|
|
const defaultCache = new Map();
|
|
|
|
// #6699 — providers that exist ONLY as Cloud Agent task-API entries
|
|
// (CLOUD_AGENT_PROVIDERS / staticModels "Available Models" catalog) and have no
|
|
// chat-completions REGISTRY entry anywhere in open-sse/. Without this guard,
|
|
// getExecutor() silently falls through to DefaultExecutor's
|
|
// `PROVIDERS[provider] || PROVIDERS.openai` fallback, sending the user's real
|
|
// provider key to OpenAI's endpoint (mislabeled as coming from the provider the
|
|
// user actually selected). Starting with just "jules" (the reported case);
|
|
// "devin" and "codex-cloud" share the same structural gap and are left for a
|
|
// follow-up once their own chat-routing behavior is confirmed.
|
|
const CHAT_UNSUPPORTED_CLOUD_AGENT_PROVIDERS = new Set(["jules"]);
|
|
|
|
export function getExecutor(provider) {
|
|
if (executors[provider]) return executors[provider];
|
|
if (CHAT_UNSUPPORTED_CLOUD_AGENT_PROVIDERS.has(provider)) {
|
|
const err = new Error(
|
|
`Provider "${provider}" is a cloud-agent provider and does not support direct chat completions; use the Cloud Agents task API instead.`
|
|
);
|
|
(err as Error & { status?: number }).status = 400;
|
|
throw err;
|
|
}
|
|
if (!defaultCache.has(provider)) defaultCache.set(provider, new DefaultExecutor(provider));
|
|
return defaultCache.get(provider);
|
|
}
|
|
|
|
export function hasSpecializedExecutor(provider) {
|
|
return !!executors[provider];
|
|
}
|
|
|
|
export { BaseExecutor } from "./base.ts";
|
|
export { AntigravityExecutor } from "./antigravity.ts";
|
|
export { GithubExecutor } from "./github.ts";
|
|
export { QoderExecutor } from "./qoder.ts";
|
|
export { KiroExecutor } from "./kiro.ts";
|
|
export { CodexExecutor } from "./codex.ts";
|
|
export { CursorExecutor } from "./cursor.ts";
|
|
export { TraeExecutor } from "./trae.ts";
|
|
export { DefaultExecutor } from "./default.ts";
|
|
export { BedrockExecutor } from "./bedrock.ts";
|
|
export { GlmExecutor } from "./glm.ts";
|
|
export { PollinationsExecutor } from "./pollinations.ts";
|
|
export { CloudflareAIExecutor } from "./cloudflare-ai.ts";
|
|
export { OpencodeExecutor } from "./opencode.ts";
|
|
export { PuterExecutor } from "./puter.ts";
|
|
export { CliproxyapiExecutor } from "./cliproxyapi.ts";
|
|
export { DarioExecutor } from "./dario.ts";
|
|
export { NineRouterExecutor } from "./ninerouter.ts";
|
|
export { VertexExecutor } from "./vertex.ts";
|
|
export { PerplexityWebExecutor } from "./perplexity-web.ts";
|
|
export { GrokWebExecutor } from "./grok-web.ts";
|
|
export { GeminiWebExecutor } from "./gemini-web.ts";
|
|
export { KieExecutor } from "./kie.ts";
|
|
export { ChatGptWebExecutor } from "./chatgpt-web.ts";
|
|
export { BlackboxWebExecutor } from "./blackbox-web.ts";
|
|
export { MuseSparkWebExecutor } from "./muse-spark-web.ts";
|
|
export { AzureOpenAIExecutor } from "./azure-openai.ts";
|
|
export { AzureAiExecutor } from "./azure-ai.ts";
|
|
export { CommandCodeExecutor } from "./commandCode.ts";
|
|
export { GitlabExecutor } from "./gitlab.ts";
|
|
export { NlpCloudExecutor } from "./nlpcloud.ts";
|
|
export { WindsurfExecutor } from "./windsurf.ts";
|
|
export { ZedHostedExecutor } from "./zed-hosted.ts";
|
|
export { DevinCliExecutor } from "./devin-cli.ts";
|
|
export { DevinCliAgenticExecutor } from "./devin-cli-agentic.ts";
|
|
export { AuggieExecutor } from "./auggie.ts";
|
|
export { CopilotWebExecutor } from "./copilot-web.ts";
|
|
export { CopilotM365WebExecutor } from "./copilot-m365-web.ts";
|
|
export { MicrosoftDesignerWebExecutor } from "./microsoft-designer-web.ts";
|
|
export { AdobeFireflyExecutor } from "./adobe-firefly.ts";
|
|
export { VeoAIFreeWebExecutor } from "./veoaifree-web.ts";
|
|
export { DuckDuckGoWebExecutor } from "./duckduckgo-web.ts";
|
|
export { FeloWebExecutor } from "./felo-web.ts";
|
|
export { ClaudeWebExecutor } from "./claude-web.ts";
|
|
export { DeepSeekWebExecutor } from "./deepseek-web.ts";
|
|
export { DeepSeekWebWithAutoRefreshExecutor } from "./deepseek-web-with-auto-refresh.ts";
|
|
export { AdaptaWebExecutor } from "./adapta-web.ts";
|
|
export { YuanbaoWebExecutor } from "./yuanbao-web.ts";
|
|
export { T3ChatWebExecutor } from "./t3-chat-web.ts";
|
|
export { InnerAiExecutor } from "./inner-ai.ts";
|
|
export { QwenWebExecutor } from "./qwen-web.ts";
|
|
export { HailuoWebExecutor } from "./hailuo-web.ts";
|
|
export { TheOldLlmExecutor } from "./theoldllm.ts";
|
|
export { ChipotleExecutor } from "./chipotle.ts";
|
|
export { LMArenaExecutor } from "./lmarena.ts";
|
|
export { MimocodeExecutor } from "./mimocode.ts";
|
|
export { GrokCliExecutor } from "./grok-cli.ts";
|
|
export { CodeBuddyCnExecutor } from "./codebuddy-cn.ts";
|
|
export { ZenmuxFreeExecutor } from "./zenmux-free.ts";
|
|
export { HyperAgentExecutor } from "./hyperagent.ts";
|
|
export { XaiExecutor } from "./xai.ts";
|
|
export { MoonshotExecutor } from "./moonshot.ts";
|
|
export { CheaperInferenceExecutor } from "./cheaperinference.ts";
|
|
export { PromptQlExecutor } from "./promptql.ts";
|