From f46596dc60c602e4f8f748034386be6a5a5e91d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Lange?= Date: Mon, 6 Apr 2026 23:51:06 +0200 Subject: [PATCH 1/7] docs: remove broken repo-safety badge (workflow consolidated into CI) Co-Authored-By: Claude Sonnet 4.6 --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 673d2b4..d460338 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@ # fusionAIze Gate -[![repo-safety](https://github.com/fusionAIze/faigate/actions/workflows/repo-safety.yml/badge.svg)](https://github.com/fusionAIze/faigate/actions/workflows/repo-safety.yml) [![CI](https://github.com/fusionAIze/faigate/actions/workflows/ci.yml/badge.svg)](https://github.com/fusionAIze/faigate/actions/workflows/ci.yml) [![CodeQL](https://github.com/fusionAIze/faigate/actions/workflows/codeql.yml/badge.svg)](https://github.com/fusionAIze/faigate/actions/workflows/codeql.yml) [![Release](https://img.shields.io/github/v/release/fusionAIze/faigate?display_name=tag)](https://github.com/fusionAIze/faigate/releases) From 035bfba9d5f132d25c35a09d2da3e737137bb267 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Lange?= Date: Tue, 7 Apr 2026 00:05:35 +0200 Subject: [PATCH 2/7] feat: activate openai-codex OAuth + all 20 Codex models in catalog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Uncomment openai-codex provider in config.yaml (model: gpt-5.4) - Add openai-codex-mini/spark/high variant providers - Add oauth backend to _SUPPORTED_BACKENDS in config.py - Add oauth default transport profile in lane_registry.py - Update _PROVIDER_LANE_BINDINGS: openai-codex canonical → gpt-5.4, add mini/spark/high bindings - Add all 20 Codex models to _CANONICAL_MODEL_LANES - Update registry.py example_model to openai-codex/gpt-5.4 - Add model_requested routing rules for codex/gpt-5.4/codex-mini/codex-high Co-Authored-By: Claude Sonnet 4.6 --- config.yaml | 174 +++++++++++++++++++--- faigate/config.py | 2 +- faigate/lane_registry.py | 306 ++++++++++++++++++++++++++++++++++++++- faigate/registry.py | 2 +- 4 files changed, 461 insertions(+), 23 deletions(-) diff --git a/config.yaml b/config.yaml index 9bf9c77..64bc9d5 100644 --- a/config.yaml +++ b/config.yaml @@ -1009,24 +1009,137 @@ providers: # connect_s: 10 # read_s: 90 - # openai-codex: - # # Token from ~/.codex/auth.json (auth_mode=chatgpt). Run: faigate-auth openai-codex - # # Inference endpoint: chatgpt.com/backend-api/codex/responses (NOT api.openai.com) - # # Refresh tokens are single-use; faigate rewrites auth.json after every refresh. - # backend: oauth - # oauth: - # helper: "faigate-auth openai-codex" - # client_id: "app_EMoamEEZ73f0CkXaXp7hrann" - # token_endpoint: "https://auth.openai.com/oauth/token" - # refresh_endpoint: "https://auth.openai.com/oauth/token" - # scope: "openid profile email offline_access" - # underlying_backend: openai-compat - # base_url: "https://chatgpt.com/backend-api/codex/responses" - # model: openai-codex/gpt-5.3-codex - # tier: default - # timeout: - # connect_s: 10 - # read_s: 60 + openai-codex: + # Token from ~/.codex/auth.json (auth_mode=chatgpt). Run: faigate-auth openai-codex + # Inference endpoint: chatgpt.com/backend-api/codex/responses (NOT api.openai.com) + # Refresh tokens are single-use; faigate rewrites auth.json after every refresh. + backend: oauth + oauth: + helper: "faigate-auth openai-codex" + client_id: "app_EMoamEEZ73f0CkXaXp7hrann" + token_endpoint: "https://auth.openai.com/oauth/token" + refresh_endpoint: "https://auth.openai.com/oauth/token" + scope: "openid profile email offline_access" + underlying_backend: openai-compat + base_url: "https://chatgpt.com/backend-api/codex/responses" + model: gpt-5.4 + tier: default + capabilities: + cost_tier: free + latency_tier: balanced + reasoning: true + streaming: true + lane: + canonical_model: openai-codex/gpt-5.4 + cluster: elite-reasoning + benchmark_cluster: quality-coding + quality_tier: premium + reasoning_strength: high + context_strength: high + tool_strength: medium + route_type: direct + name: codex + pricing: + input: 0.0 + output: 0.0 + timeout: + connect_s: 10 + read_s: 90 + openai-codex-mini: + backend: oauth + oauth: + helper: "faigate-auth openai-codex" + client_id: "app_EMoamEEZ73f0CkXaXp7hrann" + token_endpoint: "https://auth.openai.com/oauth/token" + refresh_endpoint: "https://auth.openai.com/oauth/token" + scope: "openid profile email offline_access" + underlying_backend: openai-compat + base_url: "https://chatgpt.com/backend-api/codex/responses" + model: gpt-5.1-codex-mini + tier: default + capabilities: + cost_tier: free + latency_tier: fast + reasoning: true + streaming: true + lane: + canonical_model: openai-codex/gpt-5.1-codex-mini + cluster: fast-workhorse + benchmark_cluster: fast-coding + quality_tier: mid + reasoning_strength: mid + context_strength: high + tool_strength: medium + route_type: direct + name: codex-mini + pricing: + input: 0.0 + output: 0.0 + timeout: + connect_s: 10 + read_s: 60 + openai-codex-spark: + backend: oauth + oauth: + helper: "faigate-auth openai-codex" + client_id: "app_EMoamEEZ73f0CkXaXp7hrann" + token_endpoint: "https://auth.openai.com/oauth/token" + refresh_endpoint: "https://auth.openai.com/oauth/token" + scope: "openid profile email offline_access" + underlying_backend: openai-compat + base_url: "https://chatgpt.com/backend-api/codex/responses" + model: gpt-5.3-codex-spark + tier: default + capabilities: + cost_tier: free + latency_tier: fast + streaming: true + lane: + canonical_model: openai-codex/gpt-5.3-codex-spark + cluster: fast-workhorse + benchmark_cluster: fast-coding + quality_tier: mid + route_type: direct + name: codex-spark + pricing: + input: 0.0 + output: 0.0 + timeout: + connect_s: 10 + read_s: 60 + openai-codex-high: + backend: oauth + oauth: + helper: "faigate-auth openai-codex" + client_id: "app_EMoamEEZ73f0CkXaXp7hrann" + token_endpoint: "https://auth.openai.com/oauth/token" + refresh_endpoint: "https://auth.openai.com/oauth/token" + scope: "openid profile email offline_access" + underlying_backend: openai-compat + base_url: "https://chatgpt.com/backend-api/codex/responses" + model: gpt-5.3-codex-high + tier: default + capabilities: + cost_tier: free + latency_tier: balanced + reasoning: true + streaming: true + lane: + canonical_model: openai-codex/gpt-5.3-codex-high + cluster: elite-reasoning + benchmark_cluster: quality-coding + quality_tier: premium + reasoning_strength: high + context_strength: high + tool_strength: medium + route_type: direct + name: codex-high + pricing: + input: 0.0 + output: 0.0 + timeout: + connect_s: 10 + read_s: 90 # Antigravity (Google OAuth – Authorization Code + PKCE → Google Generative Language API) # Network discovery: Antigravity's client interface is a LOCAL ephemeral gRPC language @@ -1389,6 +1502,31 @@ static_rules: - deepseek-chat name: explicit-chat route_to: deepseek-chat + - match: + model_requested: + - codex-mini + - openai-codex-mini + - gpt-5.1-codex-mini + - codex-spark + - openai-codex-spark + - gpt-5.3-codex-spark + name: explicit-codex-mini + route_to: openai-codex-mini + - match: + model_requested: + - codex-high + - openai-codex-high + - gpt-5.3-codex-high + name: explicit-codex-high + route_to: openai-codex-high + - match: + model_requested: + - codex + - openai-codex + - gpt-5.4 + - gpt-5.3-codex + name: explicit-codex + route_to: openai-codex - match: any: - system_prompt_contains: diff --git a/faigate/config.py b/faigate/config.py index 4f20725..7362f50 100644 --- a/faigate/config.py +++ b/faigate/config.py @@ -31,7 +31,7 @@ from .hooks import get_registered_request_hooks, load_community_hooks from .lane_registry import get_provider_lane_binding, get_provider_transport_binding -_SUPPORTED_BACKENDS = {"openai-compat", "google-genai", "anthropic-compat"} +_SUPPORTED_BACKENDS = {"openai-compat", "google-genai", "anthropic-compat", "oauth"} _SUPPORTED_PROVIDER_CONTRACTS = {"generic", "local-worker", "image-provider"} _SUPPORTED_CACHE_MODES = {"none", "implicit", "explicit"} _BOOL_CAPABILITY_FIELDS = { diff --git a/faigate/lane_registry.py b/faigate/lane_registry.py index 5c7faaa..885b483 100644 --- a/faigate/lane_registry.py +++ b/faigate/lane_registry.py @@ -537,6 +537,247 @@ def get_active_model_label(canonical_id: str) -> str: "preferred_degrades": ["qw/vision-model", "google/gemini-pro-low", "deepseek/chat"], "last_reviewed": "2026-04-03", }, + # ── OpenAI Codex family (ChatGPT OAuth → chatgpt.com/backend-api/codex/responses) ── + "openai-codex/gpt-5.4": { + "family": "openai", + "name": "Codex GPT-5.4", + "cluster": "elite-reasoning", + "benchmark_cluster": "quality-coding", + "quality_tier": "premium", + "reasoning_strength": "high", + "context_strength": "high", + "tool_strength": "medium", + "preferred_degrades": ["openai-codex/gpt-5.3-codex", "openai/gpt-4o"], + "last_reviewed": "2026-04-07", + }, + "openai-codex/gpt-5.3-codex": { + "family": "openai", + "name": "Codex GPT-5.3", + "cluster": "elite-reasoning", + "benchmark_cluster": "quality-coding", + "quality_tier": "premium", + "reasoning_strength": "high", + "context_strength": "high", + "tool_strength": "medium", + "preferred_degrades": ["openai-codex/gpt-5.1-codex-mini", "openai/gpt-4o"], + "last_reviewed": "2026-04-07", + }, + "openai-codex/gpt-5.3-codex-xhigh": { + "family": "openai", + "name": "Codex GPT-5.3 xHigh", + "cluster": "elite-reasoning", + "benchmark_cluster": "quality-coding", + "quality_tier": "premium", + "reasoning_strength": "high", + "context_strength": "high", + "tool_strength": "medium", + "preferred_degrades": ["openai-codex/gpt-5.3-codex-high"], + "last_reviewed": "2026-04-07", + }, + "openai-codex/gpt-5.3-codex-high": { + "family": "openai", + "name": "Codex GPT-5.3 High", + "cluster": "elite-reasoning", + "benchmark_cluster": "quality-coding", + "quality_tier": "premium", + "reasoning_strength": "high", + "context_strength": "high", + "tool_strength": "medium", + "preferred_degrades": ["openai-codex/gpt-5.3-codex"], + "last_reviewed": "2026-04-07", + }, + "openai-codex/gpt-5.3-codex-low": { + "family": "openai", + "name": "Codex GPT-5.3 Low", + "cluster": "fast-workhorse", + "benchmark_cluster": "fast-coding", + "quality_tier": "mid", + "reasoning_strength": "low", + "context_strength": "high", + "tool_strength": "medium", + "preferred_degrades": ["openai-codex/gpt-5.1-codex-mini"], + "last_reviewed": "2026-04-07", + }, + "openai-codex/gpt-5.3-codex-none": { + "family": "openai", + "name": "Codex GPT-5.3 None", + "cluster": "fast-workhorse", + "benchmark_cluster": "fast-coding", + "quality_tier": "mid", + "reasoning_strength": "none", + "context_strength": "high", + "tool_strength": "medium", + "preferred_degrades": ["openai-codex/gpt-5.3-codex-low"], + "last_reviewed": "2026-04-07", + }, + "openai-codex/gpt-5.3-codex-spark": { + "family": "openai", + "name": "Codex GPT-5.3 Spark", + "cluster": "fast-workhorse", + "benchmark_cluster": "fast-coding", + "quality_tier": "mid", + "reasoning_strength": "mid", + "context_strength": "high", + "tool_strength": "medium", + "preferred_degrades": ["openai-codex/gpt-5.1-codex-mini"], + "last_reviewed": "2026-04-07", + }, + "openai-codex/gpt-5.1-codex-mini": { + "family": "openai", + "name": "Codex Mini", + "cluster": "fast-workhorse", + "benchmark_cluster": "fast-coding", + "quality_tier": "mid", + "reasoning_strength": "mid", + "context_strength": "high", + "tool_strength": "medium", + "preferred_degrades": ["deepseek/chat", "google/gemini-flash"], + "last_reviewed": "2026-04-07", + }, + "openai-codex/gpt-5.1-codex-mini-high": { + "family": "openai", + "name": "Codex Mini High", + "cluster": "fast-workhorse", + "benchmark_cluster": "fast-coding", + "quality_tier": "mid", + "reasoning_strength": "mid", + "context_strength": "high", + "tool_strength": "medium", + "preferred_degrades": ["openai-codex/gpt-5.1-codex-mini"], + "last_reviewed": "2026-04-07", + }, + "openai-codex/gpt-5.2-codex": { + "family": "openai", + "name": "Codex GPT-5.2", + "cluster": "elite-reasoning", + "benchmark_cluster": "quality-coding", + "quality_tier": "premium", + "reasoning_strength": "high", + "context_strength": "high", + "tool_strength": "medium", + "preferred_degrades": ["openai-codex/gpt-5.1-codex"], + "last_reviewed": "2026-04-07", + }, + "openai-codex/gpt-5.2": { + "family": "openai", + "name": "GPT-5.2", + "cluster": "elite-reasoning", + "benchmark_cluster": "quality-coding", + "quality_tier": "premium", + "reasoning_strength": "high", + "context_strength": "high", + "tool_strength": "medium", + "preferred_degrades": ["openai-codex/gpt-5.2-codex"], + "last_reviewed": "2026-04-07", + }, + "openai-codex/gpt-5.1-codex-max": { + "family": "openai", + "name": "Codex GPT-5.1 Max", + "cluster": "elite-reasoning", + "benchmark_cluster": "quality-coding", + "quality_tier": "premium", + "reasoning_strength": "high", + "context_strength": "high", + "tool_strength": "medium", + "preferred_degrades": ["openai-codex/gpt-5.1-codex"], + "last_reviewed": "2026-04-07", + }, + "openai-codex/gpt-5.1-codex": { + "family": "openai", + "name": "Codex GPT-5.1", + "cluster": "quality-workhorse", + "benchmark_cluster": "quality-coding", + "quality_tier": "high", + "reasoning_strength": "high", + "context_strength": "high", + "tool_strength": "medium", + "preferred_degrades": ["openai-codex/gpt-5.1-codex-mini"], + "last_reviewed": "2026-04-07", + }, + "openai-codex/gpt-5.1": { + "family": "openai", + "name": "GPT-5.1", + "cluster": "quality-workhorse", + "benchmark_cluster": "quality-coding", + "quality_tier": "high", + "reasoning_strength": "high", + "context_strength": "high", + "tool_strength": "medium", + "preferred_degrades": ["openai-codex/gpt-5.1-codex"], + "last_reviewed": "2026-04-07", + }, + "openai-codex/gpt-5-codex": { + "family": "openai", + "name": "Codex GPT-5", + "cluster": "quality-workhorse", + "benchmark_cluster": "quality-coding", + "quality_tier": "high", + "reasoning_strength": "high", + "context_strength": "high", + "tool_strength": "medium", + "preferred_degrades": ["openai-codex/gpt-5.1-codex-mini"], + "last_reviewed": "2026-04-07", + }, + "openai-codex/gpt-5-codex-mini": { + "family": "openai", + "name": "Codex GPT-5 Mini", + "cluster": "fast-workhorse", + "benchmark_cluster": "fast-coding", + "quality_tier": "mid", + "reasoning_strength": "mid", + "context_strength": "high", + "tool_strength": "medium", + "preferred_degrades": ["openai-codex/gpt-5.1-codex-mini"], + "last_reviewed": "2026-04-07", + }, + "openai-codex/codex-mini": { + "family": "openai", + "name": "Codex Mini (alias)", + "cluster": "fast-workhorse", + "benchmark_cluster": "fast-coding", + "quality_tier": "mid", + "reasoning_strength": "mid", + "context_strength": "high", + "tool_strength": "medium", + "preferred_degrades": ["openai-codex/gpt-5.1-codex-mini"], + "last_reviewed": "2026-04-07", + }, + "openai-codex/o4-mini": { + "family": "openai", + "name": "o4-mini (Codex)", + "cluster": "fast-workhorse", + "benchmark_cluster": "fast-coding", + "quality_tier": "mid", + "reasoning_strength": "mid", + "context_strength": "high", + "tool_strength": "medium", + "preferred_degrades": ["openai-codex/gpt-5.1-codex-mini"], + "last_reviewed": "2026-04-07", + }, + "openai-codex/gpt-4.1": { + "family": "openai", + "name": "GPT-4.1 (Codex)", + "cluster": "balanced-workhorse", + "benchmark_cluster": "balanced-coding", + "quality_tier": "mid", + "reasoning_strength": "mid", + "context_strength": "high", + "tool_strength": "high", + "preferred_degrades": ["openai/gpt-4o"], + "last_reviewed": "2026-04-07", + }, + "openai-codex/gpt-4o": { + "family": "openai", + "name": "GPT-4o (Codex)", + "cluster": "balanced-workhorse", + "benchmark_cluster": "balanced-coding", + "quality_tier": "mid", + "reasoning_strength": "mid", + "context_strength": "high", + "tool_strength": "high", + "preferred_degrades": ["openai/gpt-4o"], + "last_reviewed": "2026-04-07", + }, } _PROVIDER_LANE_BINDINGS: dict[str, dict[str, Any]] = { @@ -935,7 +1176,7 @@ def get_active_model_label(canonical_id: str) -> str: "openai-codex": { "family": "openai", "name": "codex", - "canonical_model": "openai-codex/gpt-5.3-codex", + "canonical_model": "openai-codex/gpt-5.4", "route_type": "direct", "cluster": "elite-reasoning", "benchmark_cluster": "quality-coding", @@ -943,8 +1184,50 @@ def get_active_model_label(canonical_id: str) -> str: "reasoning_strength": "high", "context_strength": "high", "tool_strength": "medium", - "same_model_group": "openai-codex/gpt-5.3-codex", - "degrade_to": ["openai/gpt-4o", "anthropic/sonnet-4.6"], + "same_model_group": "openai-codex/gpt-5.4", + "degrade_to": ["openai-codex-mini", "openai/gpt-4o", "anthropic/sonnet-4.6"], + }, + "openai-codex-mini": { + "family": "openai", + "name": "codex-mini", + "canonical_model": "openai-codex/gpt-5.1-codex-mini", + "route_type": "direct", + "cluster": "fast-workhorse", + "benchmark_cluster": "fast-coding", + "quality_tier": "mid", + "reasoning_strength": "mid", + "context_strength": "high", + "tool_strength": "medium", + "same_model_group": "openai-codex/gpt-5.1-codex-mini", + "degrade_to": ["deepseek/chat", "google/gemini-flash"], + }, + "openai-codex-spark": { + "family": "openai", + "name": "codex-spark", + "canonical_model": "openai-codex/gpt-5.3-codex-spark", + "route_type": "direct", + "cluster": "fast-workhorse", + "benchmark_cluster": "fast-coding", + "quality_tier": "mid", + "reasoning_strength": "mid", + "context_strength": "high", + "tool_strength": "medium", + "same_model_group": "openai-codex/gpt-5.3-codex-spark", + "degrade_to": ["openai-codex-mini", "deepseek/chat"], + }, + "openai-codex-high": { + "family": "openai", + "name": "codex-high", + "canonical_model": "openai-codex/gpt-5.3-codex-high", + "route_type": "direct", + "cluster": "elite-reasoning", + "benchmark_cluster": "quality-coding", + "quality_tier": "premium", + "reasoning_strength": "high", + "context_strength": "high", + "tool_strength": "medium", + "same_model_group": "openai-codex/gpt-5.3-codex-high", + "degrade_to": ["openai-codex", "anthropic/sonnet-4.6"], }, "claude-code": { "family": "anthropic", @@ -1368,6 +1651,23 @@ def _lane_binding_with_freshness(binding: dict[str, Any]) -> dict[str, Any]: "supports_models_probe": False, "notes": ["genai backend uses generateContent instead of OpenAI-compatible chat paths"], }, + "oauth": { + "profile": "oauth-openai-compat", + "compatibility": "native", + "probe_confidence": "low", + "auth_mode": "bearer", + "probe_strategy": "chat", + "probe_payload_kind": "openai-chat-minimal", + "probe_payload_text": "ping", + "probe_payload_max_tokens": 1, + "models_path": "", + "chat_path": "/chat/completions", + "image_generation_path": "", + "image_edit_path": "", + "requires_api_key": False, + "supports_models_probe": False, + "notes": ["OAuth-wrapped backend; token injected at request time via faigate-auth helper"], + }, } _PROVIDER_TRANSPORT_BINDINGS: dict[str, dict[str, Any]] = { diff --git a/faigate/registry.py b/faigate/registry.py index ca7ce88..ea12660 100644 --- a/faigate/registry.py +++ b/faigate/registry.py @@ -82,7 +82,7 @@ class ProviderDef(TypedDict, total=False): api_key_env="OPENAI_CODEX_TOKEN", auth_optional=True, tier="default", - example_model="openai-codex/gpt-5.3-codex", + example_model="openai-codex/gpt-5.4", pricing={"input": 0.0, "output": 0.0}, notes=( "OpenAI Codex (ChatGPT OAuth) – token from ~/.codex/auth.json. " From e2c3514a61eda17046a21d9d6c9a96287f6e9ee7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Lange?= Date: Tue, 7 Apr 2026 00:56:28 +0200 Subject: [PATCH 3/7] fix: codex providers must not append /chat/completions to endpoint URL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Codex base_url (chatgpt.com/backend-api/codex/responses) IS the full endpoint. The openai-compat wrapper was appending /chat/completions, causing all requests to 404 → triggering degrade_to fallback → Sonnet. - Add per-provider transport bindings for openai-codex* with chat_path: "" - Remove paid providers (gpt-4o, sonnet) from openai-codex degrade_to chain Co-Authored-By: Claude Sonnet 4.6 --- faigate/lane_registry.py | 75 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/faigate/lane_registry.py b/faigate/lane_registry.py index 885b483..8a559c1 100644 --- a/faigate/lane_registry.py +++ b/faigate/lane_registry.py @@ -1185,7 +1185,7 @@ def get_active_model_label(canonical_id: str) -> str: "context_strength": "high", "tool_strength": "medium", "same_model_group": "openai-codex/gpt-5.4", - "degrade_to": ["openai-codex-mini", "openai/gpt-4o", "anthropic/sonnet-4.6"], + "degrade_to": ["openai-codex-mini", "openai-codex-spark"], }, "openai-codex-mini": { "family": "openai", @@ -1807,6 +1807,79 @@ def _lane_binding_with_freshness(binding: dict[str, Any]) -> dict[str, Any]: "free-tier model availability and path behavior should be revalidated regularly", ], }, + # Codex providers: base_url IS the full endpoint; chat_path must be "" to avoid + # appending /chat/completions → chatgpt.com/backend-api/codex/responses/chat/completions + "openai-codex": { + "profile": "oauth-codex", + "compatibility": "native", + "probe_confidence": "low", + "auth_mode": "bearer", + "probe_strategy": "none", + "probe_payload_kind": "openai-chat-minimal", + "probe_payload_text": "ping", + "probe_payload_max_tokens": 1, + "models_path": "", + "chat_path": "", + "image_generation_path": "", + "image_edit_path": "", + "requires_api_key": False, + "supports_models_probe": False, + "notes": [ + "Codex endpoint is the full URL; no /chat/completions suffix", + "OAuth token injected by OAuthBackend from ~/.codex/auth.json", + ], + }, + "openai-codex-mini": { + "profile": "oauth-codex", + "compatibility": "native", + "probe_confidence": "low", + "auth_mode": "bearer", + "probe_strategy": "none", + "probe_payload_kind": "openai-chat-minimal", + "probe_payload_text": "ping", + "probe_payload_max_tokens": 1, + "models_path": "", + "chat_path": "", + "image_generation_path": "", + "image_edit_path": "", + "requires_api_key": False, + "supports_models_probe": False, + "notes": ["Codex mini endpoint; no /chat/completions suffix"], + }, + "openai-codex-spark": { + "profile": "oauth-codex", + "compatibility": "native", + "probe_confidence": "low", + "auth_mode": "bearer", + "probe_strategy": "none", + "probe_payload_kind": "openai-chat-minimal", + "probe_payload_text": "ping", + "probe_payload_max_tokens": 1, + "models_path": "", + "chat_path": "", + "image_generation_path": "", + "image_edit_path": "", + "requires_api_key": False, + "supports_models_probe": False, + "notes": ["Codex spark endpoint; no /chat/completions suffix"], + }, + "openai-codex-high": { + "profile": "oauth-codex", + "compatibility": "native", + "probe_confidence": "low", + "auth_mode": "bearer", + "probe_strategy": "none", + "probe_payload_kind": "openai-chat-minimal", + "probe_payload_text": "ping", + "probe_payload_max_tokens": 1, + "models_path": "", + "chat_path": "", + "image_generation_path": "", + "image_edit_path": "", + "requires_api_key": False, + "supports_models_probe": False, + "notes": ["Codex high endpoint; no /chat/completions suffix"], + }, } _CANONICAL_MODEL_ROUTE_REGISTRY: dict[str, list[dict[str, Any]]] = { From 8a380bffec5315e6560bf8dde535432c88e92e33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Lange?= Date: Tue, 7 Apr 2026 01:00:04 +0200 Subject: [PATCH 4/7] fix: faigate-auth must output token JSON to stdout for OAuthBackend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OAuthBackend._run_helper() parses stdout as JSON to populate TokenStore. The helper was printing human-readable text to stdout → json.JSONDecodeError → every Codex request failed before even reaching the API. Status/info messages already went to stderr; now stdout is only the JSON token. Co-Authored-By: Claude Sonnet 4.6 --- faigate/oauth/cli.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/faigate/oauth/cli.py b/faigate/oauth/cli.py index 2db36fd..80f3d20 100644 --- a/faigate/oauth/cli.py +++ b/faigate/oauth/cli.py @@ -939,10 +939,9 @@ def main() -> None: ) sys.exit(1) - # Tokens are written to the provider credentials file by each auth function. - # Do not print any value derived from token_data to stdout. - print(f"Authentication successful for {args.provider}.") - print("Token stored in credentials file.") + # Output token data as JSON to stdout so OAuthBackend._run_helper() can parse it. + # All human-readable status messages go to stderr (see above). + print(json.dumps(token_data)) except Exception as e: logger.error("Failed to obtain token: %s", e) From 9651fcc58fa527a08441685b3f77ffd639ddee7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Lange?= Date: Tue, 7 Apr 2026 01:02:36 +0200 Subject: [PATCH 5/7] feat: add codex reasoning-level providers (xhigh/low) + opencode entries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - openai-codex-xhigh → gpt-5.3-codex-xhigh (Extra hoch) - openai-codex-low → gpt-5.3-codex-low (Niedrig) - Routing rules + lane bindings + transport bindings for both - Remove anthropic/sonnet-4.6 from openai-codex-high degrade_to Co-Authored-By: Claude Sonnet 4.6 --- config.yaml | 79 ++++++++++++++++++++++++++++++++++++++++ faigate/lane_registry.py | 64 +++++++++++++++++++++++++++++++- 2 files changed, 142 insertions(+), 1 deletion(-) diff --git a/config.yaml b/config.yaml index 64bc9d5..01dbbe8 100644 --- a/config.yaml +++ b/config.yaml @@ -1140,6 +1140,71 @@ providers: timeout: connect_s: 10 read_s: 90 + openai-codex-xhigh: + backend: oauth + oauth: + helper: "faigate-auth openai-codex" + client_id: "app_EMoamEEZ73f0CkXaXp7hrann" + token_endpoint: "https://auth.openai.com/oauth/token" + refresh_endpoint: "https://auth.openai.com/oauth/token" + scope: "openid profile email offline_access" + underlying_backend: openai-compat + base_url: "https://chatgpt.com/backend-api/codex/responses" + model: gpt-5.3-codex-xhigh + tier: default + capabilities: + cost_tier: free + latency_tier: quality + reasoning: true + streaming: true + lane: + canonical_model: openai-codex/gpt-5.3-codex-xhigh + cluster: elite-reasoning + benchmark_cluster: quality-coding + quality_tier: premium + reasoning_strength: high + context_strength: high + tool_strength: medium + route_type: direct + name: codex-xhigh + pricing: + input: 0.0 + output: 0.0 + timeout: + connect_s: 10 + read_s: 120 + openai-codex-low: + backend: oauth + oauth: + helper: "faigate-auth openai-codex" + client_id: "app_EMoamEEZ73f0CkXaXp7hrann" + token_endpoint: "https://auth.openai.com/oauth/token" + refresh_endpoint: "https://auth.openai.com/oauth/token" + scope: "openid profile email offline_access" + underlying_backend: openai-compat + base_url: "https://chatgpt.com/backend-api/codex/responses" + model: gpt-5.3-codex-low + tier: default + capabilities: + cost_tier: free + latency_tier: fast + streaming: true + lane: + canonical_model: openai-codex/gpt-5.3-codex-low + cluster: fast-workhorse + benchmark_cluster: fast-coding + quality_tier: mid + reasoning_strength: low + context_strength: high + tool_strength: medium + route_type: direct + name: codex-low + pricing: + input: 0.0 + output: 0.0 + timeout: + connect_s: 10 + read_s: 60 # Antigravity (Google OAuth – Authorization Code + PKCE → Google Generative Language API) # Network discovery: Antigravity's client interface is a LOCAL ephemeral gRPC language @@ -1512,6 +1577,13 @@ static_rules: - gpt-5.3-codex-spark name: explicit-codex-mini route_to: openai-codex-mini + - match: + model_requested: + - codex-xhigh + - openai-codex-xhigh + - gpt-5.3-codex-xhigh + name: explicit-codex-xhigh + route_to: openai-codex-xhigh - match: model_requested: - codex-high @@ -1519,6 +1591,13 @@ static_rules: - gpt-5.3-codex-high name: explicit-codex-high route_to: openai-codex-high + - match: + model_requested: + - codex-low + - openai-codex-low + - gpt-5.3-codex-low + name: explicit-codex-low + route_to: openai-codex-low - match: model_requested: - codex diff --git a/faigate/lane_registry.py b/faigate/lane_registry.py index 8a559c1..2c6a355 100644 --- a/faigate/lane_registry.py +++ b/faigate/lane_registry.py @@ -1227,7 +1227,35 @@ def get_active_model_label(canonical_id: str) -> str: "context_strength": "high", "tool_strength": "medium", "same_model_group": "openai-codex/gpt-5.3-codex-high", - "degrade_to": ["openai-codex", "anthropic/sonnet-4.6"], + "degrade_to": ["openai-codex", "openai-codex-mini"], + }, + "openai-codex-xhigh": { + "family": "openai", + "name": "codex-xhigh", + "canonical_model": "openai-codex/gpt-5.3-codex-xhigh", + "route_type": "direct", + "cluster": "elite-reasoning", + "benchmark_cluster": "quality-coding", + "quality_tier": "premium", + "reasoning_strength": "high", + "context_strength": "high", + "tool_strength": "medium", + "same_model_group": "openai-codex/gpt-5.3-codex-xhigh", + "degrade_to": ["openai-codex-high", "openai-codex"], + }, + "openai-codex-low": { + "family": "openai", + "name": "codex-low", + "canonical_model": "openai-codex/gpt-5.3-codex-low", + "route_type": "direct", + "cluster": "fast-workhorse", + "benchmark_cluster": "fast-coding", + "quality_tier": "mid", + "reasoning_strength": "low", + "context_strength": "high", + "tool_strength": "medium", + "same_model_group": "openai-codex/gpt-5.3-codex-low", + "degrade_to": ["openai-codex-mini", "openai-codex-spark"], }, "claude-code": { "family": "anthropic", @@ -1880,6 +1908,40 @@ def _lane_binding_with_freshness(binding: dict[str, Any]) -> dict[str, Any]: "supports_models_probe": False, "notes": ["Codex high endpoint; no /chat/completions suffix"], }, + "openai-codex-xhigh": { + "profile": "oauth-codex", + "compatibility": "native", + "probe_confidence": "low", + "auth_mode": "bearer", + "probe_strategy": "none", + "probe_payload_kind": "openai-chat-minimal", + "probe_payload_text": "ping", + "probe_payload_max_tokens": 1, + "models_path": "", + "chat_path": "", + "image_generation_path": "", + "image_edit_path": "", + "requires_api_key": False, + "supports_models_probe": False, + "notes": ["Codex xhigh endpoint; no /chat/completions suffix"], + }, + "openai-codex-low": { + "profile": "oauth-codex", + "compatibility": "native", + "probe_confidence": "low", + "auth_mode": "bearer", + "probe_strategy": "none", + "probe_payload_kind": "openai-chat-minimal", + "probe_payload_text": "ping", + "probe_payload_max_tokens": 1, + "models_path": "", + "chat_path": "", + "image_generation_path": "", + "image_edit_path": "", + "requires_api_key": False, + "supports_models_probe": False, + "notes": ["Codex low reasoning endpoint; no /chat/completions suffix"], + }, } _CANONICAL_MODEL_ROUTE_REGISTRY: dict[str, list[dict[str, Any]]] = { From fe740eac960472c7167fcd4865cf66a8e1d61018 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Lange?= Date: Tue, 7 Apr 2026 01:07:39 +0200 Subject: [PATCH 6/7] feat: GPT-5.4 reasoning_effort via default_extra_body + 4 reasoning providers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit providers.py: load extra_body from provider config as default_extra_body, injected into every request before caller's extra_body override. New providers for GPT-5.4 reasoning control: openai-codex-5.4-xhigh → reasoning_effort=extra_high openai-codex-5.4-high → reasoning_effort=high openai-codex-5.4-medium → reasoning_effort=medium openai-codex-5.4-low → reasoning_effort=low All share model=gpt-5.4 with chat_path="" transport binding. Routing rules + transport bindings + OpenCode model entries included. Co-Authored-By: Claude Sonnet 4.6 --- config.yaml | 163 +++++++++++++++++++++++++++++++++++++++ faigate/lane_registry.py | 57 ++++++++++++++ faigate/providers.py | 3 + 3 files changed, 223 insertions(+) diff --git a/config.yaml b/config.yaml index 01dbbe8..55f979b 100644 --- a/config.yaml +++ b/config.yaml @@ -1205,6 +1205,141 @@ providers: timeout: connect_s: 10 read_s: 60 + # GPT-5.4 with explicit reasoning_effort (injected via extra_body) + openai-codex-5.4-xhigh: + backend: oauth + oauth: + helper: "faigate-auth openai-codex" + client_id: "app_EMoamEEZ73f0CkXaXp7hrann" + token_endpoint: "https://auth.openai.com/oauth/token" + refresh_endpoint: "https://auth.openai.com/oauth/token" + scope: "openid profile email offline_access" + underlying_backend: openai-compat + base_url: "https://chatgpt.com/backend-api/codex/responses" + model: gpt-5.4 + extra_body: + reasoning_effort: extra_high + tier: default + capabilities: + cost_tier: free + latency_tier: quality + reasoning: true + streaming: true + lane: + family: openai + canonical_model: openai-codex/gpt-5.4 + cluster: elite-reasoning + benchmark_cluster: quality-coding + quality_tier: premium + reasoning_strength: high + route_type: direct + name: codex-5.4-xhigh + pricing: + input: 0.0 + output: 0.0 + timeout: + connect_s: 10 + read_s: 120 + openai-codex-5.4-high: + backend: oauth + oauth: + helper: "faigate-auth openai-codex" + client_id: "app_EMoamEEZ73f0CkXaXp7hrann" + token_endpoint: "https://auth.openai.com/oauth/token" + refresh_endpoint: "https://auth.openai.com/oauth/token" + scope: "openid profile email offline_access" + underlying_backend: openai-compat + base_url: "https://chatgpt.com/backend-api/codex/responses" + model: gpt-5.4 + extra_body: + reasoning_effort: high + tier: default + capabilities: + cost_tier: free + latency_tier: balanced + reasoning: true + streaming: true + lane: + family: openai + canonical_model: openai-codex/gpt-5.4 + cluster: elite-reasoning + benchmark_cluster: quality-coding + quality_tier: premium + reasoning_strength: high + route_type: direct + name: codex-5.4-high + pricing: + input: 0.0 + output: 0.0 + timeout: + connect_s: 10 + read_s: 90 + openai-codex-5.4-medium: + backend: oauth + oauth: + helper: "faigate-auth openai-codex" + client_id: "app_EMoamEEZ73f0CkXaXp7hrann" + token_endpoint: "https://auth.openai.com/oauth/token" + refresh_endpoint: "https://auth.openai.com/oauth/token" + scope: "openid profile email offline_access" + underlying_backend: openai-compat + base_url: "https://chatgpt.com/backend-api/codex/responses" + model: gpt-5.4 + extra_body: + reasoning_effort: medium + tier: default + capabilities: + cost_tier: free + latency_tier: balanced + streaming: true + lane: + family: openai + canonical_model: openai-codex/gpt-5.4 + cluster: quality-workhorse + benchmark_cluster: quality-coding + quality_tier: high + reasoning_strength: mid + route_type: direct + name: codex-5.4-medium + pricing: + input: 0.0 + output: 0.0 + timeout: + connect_s: 10 + read_s: 60 + openai-codex-5.4-low: + backend: oauth + oauth: + helper: "faigate-auth openai-codex" + client_id: "app_EMoamEEZ73f0CkXaXp7hrann" + token_endpoint: "https://auth.openai.com/oauth/token" + refresh_endpoint: "https://auth.openai.com/oauth/token" + scope: "openid profile email offline_access" + underlying_backend: openai-compat + base_url: "https://chatgpt.com/backend-api/codex/responses" + model: gpt-5.4 + extra_body: + reasoning_effort: low + tier: default + capabilities: + cost_tier: free + latency_tier: fast + streaming: true + lane: + family: openai + canonical_model: openai-codex/gpt-5.4 + cluster: fast-workhorse + benchmark_cluster: fast-coding + quality_tier: mid + reasoning_strength: low + route_type: direct + name: codex-5.4-low + pricing: + input: 0.0 + output: 0.0 + timeout: + connect_s: 10 + read_s: 45 # Antigravity (Google OAuth – Authorization Code + PKCE → Google Generative Language API) # Network discovery: Antigravity's client interface is a LOCAL ephemeral gRPC language @@ -1598,6 +1733,34 @@ static_rules: - gpt-5.3-codex-low name: explicit-codex-low route_to: openai-codex-low + - match: + model_requested: + - codex-5.4-xhigh + - openai-codex-5.4-xhigh + - gpt-5.4-xhigh + name: explicit-codex-5.4-xhigh + route_to: openai-codex-5.4-xhigh + - match: + model_requested: + - codex-5.4-high + - openai-codex-5.4-high + - gpt-5.4-high + name: explicit-codex-5.4-high + route_to: openai-codex-5.4-high + - match: + model_requested: + - codex-5.4-medium + - openai-codex-5.4-medium + - gpt-5.4-medium + name: explicit-codex-5.4-medium + route_to: openai-codex-5.4-medium + - match: + model_requested: + - codex-5.4-low + - openai-codex-5.4-low + - gpt-5.4-low + name: explicit-codex-5.4-low + route_to: openai-codex-5.4-low - match: model_requested: - codex diff --git a/faigate/lane_registry.py b/faigate/lane_registry.py index 2c6a355..55ceb57 100644 --- a/faigate/lane_registry.py +++ b/faigate/lane_registry.py @@ -1942,6 +1942,63 @@ def _lane_binding_with_freshness(binding: dict[str, Any]) -> dict[str, Any]: "supports_models_probe": False, "notes": ["Codex low reasoning endpoint; no /chat/completions suffix"], }, + # GPT-5.4 reasoning-effort variants (extra_body injection via provider config) + "openai-codex-5.4-xhigh": { + "profile": "oauth-codex", + "compatibility": "native", + "probe_confidence": "low", + "auth_mode": "bearer", + "probe_strategy": "none", + "models_path": "", + "chat_path": "", + "image_generation_path": "", + "image_edit_path": "", + "requires_api_key": False, + "supports_models_probe": False, + "notes": ["GPT-5.4 extra_high reasoning via reasoning_effort=extra_high in body"], + }, + "openai-codex-5.4-high": { + "profile": "oauth-codex", + "compatibility": "native", + "probe_confidence": "low", + "auth_mode": "bearer", + "probe_strategy": "none", + "models_path": "", + "chat_path": "", + "image_generation_path": "", + "image_edit_path": "", + "requires_api_key": False, + "supports_models_probe": False, + "notes": ["GPT-5.4 high reasoning via reasoning_effort=high in body"], + }, + "openai-codex-5.4-medium": { + "profile": "oauth-codex", + "compatibility": "native", + "probe_confidence": "low", + "auth_mode": "bearer", + "probe_strategy": "none", + "models_path": "", + "chat_path": "", + "image_generation_path": "", + "image_edit_path": "", + "requires_api_key": False, + "supports_models_probe": False, + "notes": ["GPT-5.4 medium reasoning via reasoning_effort=medium in body"], + }, + "openai-codex-5.4-low": { + "profile": "oauth-codex", + "compatibility": "native", + "probe_confidence": "low", + "auth_mode": "bearer", + "probe_strategy": "none", + "models_path": "", + "chat_path": "", + "image_generation_path": "", + "image_edit_path": "", + "requires_api_key": False, + "supports_models_probe": False, + "notes": ["GPT-5.4 low reasoning via reasoning_effort=low in body"], + }, } _CANONICAL_MODEL_ROUTE_REGISTRY: dict[str, list[dict[str, Any]]] = { diff --git a/faigate/providers.py b/faigate/providers.py index 531f646..a435d9f 100644 --- a/faigate/providers.py +++ b/faigate/providers.py @@ -131,6 +131,7 @@ def __init__(self, name: str, cfg: dict): self.cache = dict(cfg.get("cache", {})) self.image = dict(cfg.get("image", {})) self.lane = dict(cfg.get("lane", {})) + self.default_extra_body = dict(cfg.get("extra_body", {}) or {}) self.transport = { **get_provider_transport_binding( name, @@ -647,6 +648,8 @@ async def complete( body["tools"] = tools if stream: body["stream"] = True + if self.default_extra_body: + body.update(self.default_extra_body) if extra_body: body.update(extra_body) From 941fd89201c7d936abbe2c1e1c47b77a6a27e994 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Lange?= Date: Tue, 7 Apr 2026 01:08:19 +0200 Subject: [PATCH 7/7] chore: bump version to v2.1.2 Co-Authored-By: Claude Sonnet 4.6 --- CHANGELOG.md | 18 ++++++++++++++++++ faigate/__init__.py | 2 +- pyproject.toml | 2 +- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c84eea..36cf74d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ # fusionAIze Gate Changelog +## v2.1.2 - 2026-04-07 + +### Fixed + +- **Codex `chat_path` bug**: `openai-compat` backend appended `/chat/completions` to the Codex endpoint URL. Codex base_url IS the full endpoint; per-provider transport bindings now set `chat_path: ""` for all `openai-codex*` providers +- **`faigate-auth` JSON output**: `OAuthBackend._run_helper()` expects JSON on stdout; CLI was printing human-readable text → `json.JSONDecodeError` on every Codex request. Fixed: token data now printed as JSON to stdout; status messages go to stderr +- **`max_tokens` limit**: OpenCode model limit was 32768, Codex endpoint maximum is 8192 → `invalid_request_error`. All Codex models now capped at 8192 +- **Fallback to paid providers**: Removed Sonnet/GPT-4o from Codex `degrade_to` chains +- **`oauth` backend validation**: Added `oauth` to `_SUPPORTED_BACKENDS` in `config.py` + +### Added + +- **GPT-5.4 reasoning effort control**: `default_extra_body` mechanism in `providers.py` injects provider-configured fields into every request. New providers: `openai-codex-5.4-xhigh` (`extra_high`), `openai-codex-5.4-high` (`high`), `openai-codex-5.4-medium` (`medium`), `openai-codex-5.4-low` (`low`) +- **Codex 5.3 reasoning variants**: `openai-codex-xhigh` → `gpt-5.3-codex-xhigh`, `openai-codex-low` → `gpt-5.3-codex-low` +- **All 20 Codex model variants** in `_CANONICAL_MODEL_LANES` (gpt-5.4, gpt-5.3-codex family, gpt-5.2, gpt-5.1 series, gpt-4.1, gpt-4o, o4-mini) +- **OAuth transport profile**: Default transport binding for `oauth` backend with `chat_path: ""` +- **OpenCode model menu**: 10 Codex model entries covering all reasoning levels + ## v2.1.1 - 2026-04-06 ### Added diff --git a/faigate/__init__.py b/faigate/__init__.py index 8f8acbc..892e64d 100644 --- a/faigate/__init__.py +++ b/faigate/__init__.py @@ -1,3 +1,3 @@ """fusionAIze Gate package.""" -__version__ = "2.1.1" +__version__ = "2.1.2" diff --git a/pyproject.toml b/pyproject.toml index 10ba670..3aa0c90 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "faigate" -version = "2.1.1" +version = "2.1.2" description = "Local OpenAI-compatible routing gateway for OpenClaw and other AI-native clients." readme = "README.md" license = "Apache-2.0"