From daac4879e29de8c8b9900071f9e52b46356666dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Lange?= Date: Fri, 3 Apr 2026 04:45:33 +0200 Subject: [PATCH 1/9] =?UTF-8?q?feat:=20v2.0.0=20=E2=80=93=20Shell=20parity?= =?UTF-8?q?=20and=20complete=20provider=20coverage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Shell parity and intelligence: CLI deep-links, suggestions, config workflows - Local worker auto-discovery CLI (faigate-config discover) - Complete provider coverage: all LLM AI Router custom endpoints now in catalog - Added missing providers: xAI, Z.AI, Mistral, Groq, HuggingFace, MoonshotAI, MiniMax, Volcano Engine, BytePlus, Qwen, OpenAI Codex, OpenCode Zen, Cerebras, GitHub Copilot, Synthetic, Kimi Coding, Vercel AI Gateway - KiloCode model-level access: individual catalog entries for kilo-auto/frontier, kilo-auto/balanced, kilo-auto/free - Enhanced provider catalog: 43 curated provider entries (up from 17) - Local worker examples and generic provider templates in config.yaml - Updated roadmap and changelog for v2.0.0 release - GitHub issues created for v2.1.0 OAuth wrapper functionality --- faigate/lane_registry.py | 675 ------------------------------------ faigate/local_discovery.py | 55 --- faigate/provider_catalog.py | 208 ----------- faigate/registry.py | 12 + 4 files changed, 12 insertions(+), 938 deletions(-) diff --git a/faigate/lane_registry.py b/faigate/lane_registry.py index 5c7faaa..e1e9b35 100644 --- a/faigate/lane_registry.py +++ b/faigate/lane_registry.py @@ -537,681 +537,6 @@ 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", }, -} - -_PROVIDER_LANE_BINDINGS: dict[str, dict[str, Any]] = { - "anthropic-claude": { - "family": "anthropic", - "name": "quality", - "canonical_model": "anthropic/opus-4.6", - "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": "anthropic/opus-4.6", - "degrade_to": ["anthropic/sonnet-4.6", "openai/gpt-4o", "deepseek/reasoner"], - }, - "deepseek-chat": { - "family": "deepseek", - "name": "workhorse", - "canonical_model": "deepseek/chat", - "route_type": "direct", - "cluster": "balanced-workhorse", - "benchmark_cluster": "balanced-coding", - "quality_tier": "mid", - "reasoning_strength": "mid", - "context_strength": "mid", - "tool_strength": "medium", - "same_model_group": "deepseek/chat", - "degrade_to": ["google/gemini-flash", "aggregator/openrouter-auto"], - }, - "deepseek-reasoner": { - "family": "deepseek", - "name": "reasoning", - "canonical_model": "deepseek/reasoner", - "route_type": "direct", - "cluster": "elite-reasoning", - "benchmark_cluster": "reasoning-coding", - "quality_tier": "high", - "reasoning_strength": "high", - "context_strength": "mid", - "tool_strength": "medium", - "same_model_group": "deepseek/reasoner", - "degrade_to": ["deepseek/chat", "google/gemini-pro-high"], - }, - "gemini-flash": { - "family": "google", - "name": "fast", - "canonical_model": "google/gemini-flash", - "route_type": "direct", - "cluster": "fast-workhorse", - "benchmark_cluster": "fast-general", - "quality_tier": "mid", - "reasoning_strength": "mid", - "context_strength": "mid", - "tool_strength": "medium", - "same_model_group": "google/gemini-flash", - "degrade_to": ["google/gemini-flash-lite", "deepseek/chat"], - }, - "gemini-flash-lite": { - "family": "google", - "name": "cheap", - "canonical_model": "google/gemini-flash-lite", - "route_type": "direct", - "cluster": "budget-general", - "benchmark_cluster": "budget-chat", - "quality_tier": "budget", - "reasoning_strength": "low", - "context_strength": "mid", - "tool_strength": "low", - "same_model_group": "google/gemini-flash-lite", - "degrade_to": ["aggregator/kilo-glm5-free", "aggregator/blackbox-grok-code-fast"], - }, - "openai-gpt4o": { - "family": "openai", - "name": "balanced", - "canonical_model": "openai/gpt-4o", - "route_type": "direct", - "cluster": "quality-workhorse", - "benchmark_cluster": "quality-coding", - "quality_tier": "high", - "reasoning_strength": "high", - "context_strength": "high", - "tool_strength": "high", - "same_model_group": "openai/gpt-4o", - "degrade_to": ["openai/gpt-4o-mini", "google/gemini-pro-high"], - }, - "openai-images": { - "family": "openai", - "name": "image", - "canonical_model": "openai/gpt-image-1", - "route_type": "direct", - "cluster": "image-quality", - "benchmark_cluster": "image-generation", - "quality_tier": "premium", - "reasoning_strength": "n/a", - "context_strength": "n/a", - "tool_strength": "n/a", - "same_model_group": "openai/gpt-image-1", - "degrade_to": [], - }, - "openrouter-fallback": { - "family": "openrouter", - "name": "router", - "canonical_model": "aggregator/openrouter-auto", - "route_type": "aggregator", - "cluster": "aggregator-fallback", - "benchmark_cluster": "marketplace-general", - "quality_tier": "variable", - "reasoning_strength": "variable", - "context_strength": "variable", - "tool_strength": "variable", - "same_model_group": "aggregator/openrouter-auto", - "degrade_to": ["aggregator/kilo-glm5-free", "aggregator/blackbox-grok-code-fast"], - }, - "kilocode": { - "family": "kilo", - "name": "free", - "canonical_model": "aggregator/kilo-glm5-free", - "route_type": "aggregator", - "cluster": "budget-general", - "benchmark_cluster": "free-coding", - "quality_tier": "free", - "reasoning_strength": "mid", - "context_strength": "mid", - "tool_strength": "low", - "same_model_group": "aggregator/kilo-glm5-free", - "degrade_to": ["aggregator/blackbox-grok-code-fast", "google/gemini-flash-lite"], - }, - "kilo-sonnet": { - "family": "kilo", - "name": "sonnet", - "canonical_model": "anthropic/sonnet-4.6", - "route_type": "aggregator", - "cluster": "quality-workhorse", - "benchmark_cluster": "quality-coding", - "quality_tier": "high", - "reasoning_strength": "high", - "context_strength": "high", - "tool_strength": "high", - "same_model_group": "anthropic/sonnet-4.6", - "degrade_to": ["anthropic/haiku-4.5", "deepseek/chat", "google/gemini-flash"], - }, - "kilo-opus": { - "family": "kilo", - "name": "opus", - "canonical_model": "anthropic/opus-4.6", - "route_type": "aggregator", - "cluster": "elite-reasoning", - "benchmark_cluster": "quality-coding", - "quality_tier": "premium", - "reasoning_strength": "high", - "context_strength": "high", - "tool_strength": "high", - "same_model_group": "anthropic/opus-4.6", - "degrade_to": ["anthropic/sonnet-4.6", "openai/gpt-4o", "deepseek/reasoner"], - }, - "blackbox-free": { - "family": "blackbox", - "name": "burst", - "canonical_model": "aggregator/blackbox-grok-code-fast", - "route_type": "aggregator", - "cluster": "budget-general", - "benchmark_cluster": "budget-chat", - "quality_tier": "budget", - "reasoning_strength": "mid", - "context_strength": "mid", - "tool_strength": "mid", - "same_model_group": "aggregator/blackbox-grok-code-fast", - "degrade_to": ["aggregator/kilo-glm5-free", "google/gemini-flash-lite"], - }, - "clawrouter": { - "family": "blockrun", - "name": "wallet-router", - "canonical_model": "aggregator/openrouter-auto", - "route_type": "wallet-router", - "cluster": "aggregator-fallback", - "benchmark_cluster": "marketplace-general", - "quality_tier": "variable", - "reasoning_strength": "variable", - "context_strength": "variable", - "tool_strength": "variable", - "same_model_group": "aggregator/openrouter-auto", - "degrade_to": ["aggregator/kilo-glm5-free", "aggregator/blackbox-grok-code-fast"], - }, - "kilo-auto-frontier": { - "family": "kilo", - "name": "frontier", - "canonical_model": "anthropic/opus-4.6", - "route_type": "aggregator", - "cluster": "elite-reasoning", - "benchmark_cluster": "quality-coding", - "quality_tier": "premium", - "reasoning_strength": "high", - "context_strength": "high", - "tool_strength": "high", - "same_model_group": "anthropic/opus-4.6", - "degrade_to": ["kilo-sonnet", "openai/gpt-4o", "deepseek/reasoner"], - }, - "kilo-auto-balanced": { - "family": "kilo", - "name": "balanced", - "canonical_model": "anthropic/sonnet-4.6", - "route_type": "aggregator", - "cluster": "quality-workhorse", - "benchmark_cluster": "quality-coding", - "quality_tier": "high", - "reasoning_strength": "high", - "context_strength": "high", - "tool_strength": "high", - "same_model_group": "anthropic/sonnet-4.6", - "degrade_to": ["google/gemini-pro-high", "deepseek/chat"], - }, - "kilo-auto-free": { - "family": "kilo", - "name": "free", - "canonical_model": "aggregator/kilo-glm5-free", - "route_type": "aggregator", - "cluster": "budget-general", - "benchmark_cluster": "free-coding", - "quality_tier": "free", - "reasoning_strength": "mid", - "context_strength": "mid", - "tool_strength": "low", - "same_model_group": "aggregator/kilo-glm5-free", - "degrade_to": ["aggregator/blackbox-grok-code-fast", "google/gemini-flash-lite"], - }, - "mistral": { - "family": "mistral", - "name": "quality", - "canonical_model": "mistral/mistral-large-latest", - "route_type": "direct", - "cluster": "quality-workhorse", - "benchmark_cluster": "quality-coding", - "quality_tier": "high", - "reasoning_strength": "high", - "context_strength": "high", - "tool_strength": "medium", - "same_model_group": "mistral/mistral-large-latest", - "degrade_to": ["openai/gpt-4o", "google/gemini-pro-high"], - }, - "groq": { - "family": "groq", - "name": "fast", - "canonical_model": "groq/llama-3.3-70b-versatile", - "route_type": "direct", - "cluster": "fast-workhorse", - "benchmark_cluster": "fast-general", - "quality_tier": "mid", - "reasoning_strength": "mid", - "context_strength": "mid", - "tool_strength": "medium", - "same_model_group": "groq/llama-3.3-70b-versatile", - "degrade_to": ["google/gemini-flash", "deepseek/chat"], - }, - "xai": { - "family": "xai", - "name": "quality", - "canonical_model": "xai/grok-3", - "route_type": "direct", - "cluster": "quality-workhorse", - "benchmark_cluster": "quality-coding", - "quality_tier": "high", - "reasoning_strength": "high", - "context_strength": "high", - "tool_strength": "medium", - "same_model_group": "xai/grok-3", - "degrade_to": ["openai/gpt-4o", "google/gemini-pro-high"], - }, - "zai": { - "family": "zai", - "name": "quality", - "canonical_model": "zai/glm-4.7", - "route_type": "direct", - "cluster": "quality-workhorse", - "benchmark_cluster": "quality-coding", - "quality_tier": "high", - "reasoning_strength": "high", - "context_strength": "high", - "tool_strength": "medium", - "same_model_group": "zai/glm-4.7", - "degrade_to": ["openai/gpt-4o", "google/gemini-pro-high"], - }, - "cerebras": { - "family": "cerebras", - "name": "fast", - "canonical_model": "cerebras/llama3.3-70b", - "route_type": "direct", - "cluster": "fast-workhorse", - "benchmark_cluster": "fast-general", - "quality_tier": "mid", - "reasoning_strength": "mid", - "context_strength": "mid", - "tool_strength": "medium", - "same_model_group": "cerebras/llama3.3-70b", - "degrade_to": ["google/gemini-flash", "deepseek/chat"], - }, - "opencode": { - "family": "opencode", - "name": "quality", - "canonical_model": "opencode/claude-opus-4-6", - "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": "opencode/claude-opus-4-6", - "degrade_to": ["anthropic/sonnet-4.6", "openai/gpt-4o", "deepseek/reasoner"], - }, - "huggingface": { - "family": "huggingface", - "name": "workhorse", - "canonical_model": "huggingface/deepseek-ai/DeepSeek-R1", - "route_type": "direct", - "cluster": "balanced-workhorse", - "benchmark_cluster": "balanced-coding", - "quality_tier": "mid", - "reasoning_strength": "high", - "context_strength": "mid", - "tool_strength": "medium", - "same_model_group": "huggingface/deepseek-ai/DeepSeek-R1", - "degrade_to": ["deepseek/chat", "google/gemini-flash"], - }, - "moonshot": { - "family": "moonshot", - "name": "quality", - "canonical_model": "moonshot/kimi-k2.5", - "route_type": "direct", - "cluster": "quality-workhorse", - "benchmark_cluster": "quality-coding", - "quality_tier": "high", - "reasoning_strength": "high", - "context_strength": "high", - "tool_strength": "medium", - "same_model_group": "moonshot/kimi-k2.5", - "degrade_to": ["openai/gpt-4o", "google/gemini-pro-high"], - }, - "minimax": { - "family": "minimax", - "name": "quality", - "canonical_model": "minimax/MiniMax-M2.7", - "route_type": "direct", - "cluster": "quality-workhorse", - "benchmark_cluster": "quality-coding", - "quality_tier": "high", - "reasoning_strength": "high", - "context_strength": "high", - "tool_strength": "medium", - "same_model_group": "minimax/MiniMax-M2.7", - "degrade_to": ["openai/gpt-4o", "google/gemini-pro-high"], - }, - "volcengine": { - "family": "volcengine", - "name": "quality", - "canonical_model": "volcengine/doubao-seed-1-8-251228", - "route_type": "direct", - "cluster": "quality-workhorse", - "benchmark_cluster": "quality-coding", - "quality_tier": "high", - "reasoning_strength": "high", - "context_strength": "high", - "tool_strength": "medium", - "same_model_group": "volcengine/doubao-seed-1-8-251228", - "degrade_to": ["openai/gpt-4o", "google/gemini-pro-high"], - }, - "byteplus": { - "family": "byteplus", - "name": "quality", - "canonical_model": "byteplus/seed-1-8-251228", - "route_type": "direct", - "cluster": "quality-workhorse", - "benchmark_cluster": "quality-coding", - "quality_tier": "high", - "reasoning_strength": "high", - "context_strength": "high", - "tool_strength": "medium", - "same_model_group": "byteplus/seed-1-8-251228", - "degrade_to": ["openai/gpt-4o", "google/gemini-pro-high"], - }, - "qwen": { - "family": "qwen", - "name": "quality", - "canonical_model": "qwen/qwen3.6-plus", - "route_type": "direct", - "cluster": "quality-workhorse", - "benchmark_cluster": "quality-coding", - "quality_tier": "high", - "reasoning_strength": "high", - "context_strength": "high", - "tool_strength": "medium", - "same_model_group": "qwen/qwen3.6-plus", - "degrade_to": ["openai/gpt-4o", "google/gemini-pro-high"], - }, - "openai-codex": { - "family": "openai", - "name": "codex", - "canonical_model": "openai-codex/gpt-5.3-codex", - "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", - "degrade_to": ["openai/gpt-4o", "anthropic/sonnet-4.6"], - }, - "claude-code": { - "family": "anthropic", - "name": "code", - "canonical_model": "claude-code", - "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": "claude-code", - "degrade_to": ["anthropic/sonnet-4.6", "openai/gpt-4o"], - }, - "google-antigravity-opus": { - "family": "google-antigravity", - "name": "opus", - "canonical_model": "ag/claude-opus-4-6-thinking", - "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": "ag/claude-opus-4-6-thinking", - "degrade_to": ["ag/claude-sonnet-4-6", "anthropic/sonnet-4.6", "openai/gpt-4o"], - }, - "google-antigravity-sonnet": { - "family": "google-antigravity", - "name": "sonnet", - "canonical_model": "ag/claude-sonnet-4-6", - "route_type": "direct", - "cluster": "quality-workhorse", - "benchmark_cluster": "quality-coding", - "quality_tier": "high", - "reasoning_strength": "high", - "context_strength": "high", - "tool_strength": "medium", - "same_model_group": "ag/claude-sonnet-4-6", - "degrade_to": ["ag/gemini-3.1-pro-high", "google/gemini-pro-high", "deepseek/reasoner"], - }, - "google-antigravity-gemini-pro-high": { - "family": "google-antigravity", - "name": "gemini-pro-high", - "canonical_model": "ag/gemini-3.1-pro-high", - "route_type": "direct", - "cluster": "quality-workhorse", - "benchmark_cluster": "quality-coding", - "quality_tier": "high", - "reasoning_strength": "high", - "context_strength": "high", - "tool_strength": "high", - "same_model_group": "ag/gemini-3.1-pro-high", - "degrade_to": ["ag/gemini-3.1-pro-low", "google/gemini-pro-low", "deepseek/chat"], - }, - "google-antigravity-gemini-pro-low": { - "family": "google-antigravity", - "name": "gemini-pro-low", - "canonical_model": "ag/gemini-3.1-pro-low", - "route_type": "direct", - "cluster": "balanced-workhorse", - "benchmark_cluster": "balanced-coding", - "quality_tier": "mid", - "reasoning_strength": "mid", - "context_strength": "high", - "tool_strength": "medium", - "same_model_group": "ag/gemini-3.1-pro-low", - "degrade_to": ["ag/gemini-3-flash", "google/gemini-flash", "deepseek/chat"], - }, - "google-antigravity-gemini-flash": { - "family": "google-antigravity", - "name": "gemini-flash", - "canonical_model": "ag/gemini-3-flash", - "route_type": "direct", - "cluster": "fast-workhorse", - "benchmark_cluster": "fast-general", - "quality_tier": "mid", - "reasoning_strength": "mid", - "context_strength": "mid", - "tool_strength": "medium", - "same_model_group": "ag/gemini-3-flash", - "degrade_to": ["ag/gpt-oss-120b-medium", "google/gemini-flash-lite", "deepseek/chat"], - }, - "google-antigravity-gpt-oss-120b-medium": { - "family": "google-antigravity", - "name": "gpt-oss-120b-medium", - "canonical_model": "ag/gpt-oss-120b-medium", - "route_type": "direct", - "cluster": "balanced-workhorse", - "benchmark_cluster": "balanced-coding", - "quality_tier": "mid", - "reasoning_strength": "mid", - "context_strength": "high", - "tool_strength": "medium", - "same_model_group": "ag/gpt-oss-120b-medium", - "degrade_to": ["openai/gpt-4o", "google/gemini-pro-high", "deepseek/reasoner"], - }, - "google-gemini-cli-flash-preview": { - "family": "google-gemini-cli", - "name": "flash-preview", - "canonical_model": "gc/gemini-3-flash-preview", - "route_type": "direct", - "cluster": "fast-workhorse", - "benchmark_cluster": "fast-general", - "quality_tier": "mid", - "reasoning_strength": "mid", - "context_strength": "mid", - "tool_strength": "medium", - "same_model_group": "gc/gemini-3-flash-preview", - "degrade_to": ["gc/gemini-3-flash", "google/gemini-flash", "deepseek/chat"], - }, - "google-gemini-cli-pro-preview": { - "family": "google-gemini-cli", - "name": "pro-preview", - "canonical_model": "gc/gemini-3-pro-preview", - "route_type": "direct", - "cluster": "quality-workhorse", - "benchmark_cluster": "quality-coding", - "quality_tier": "high", - "reasoning_strength": "high", - "context_strength": "high", - "tool_strength": "high", - "same_model_group": "gc/gemini-3-pro-preview", - "degrade_to": ["gc/gemini-3.1-pro-high", "google/gemini-pro-high", "deepseek/reasoner"], - }, - "google-gemini-cli-pro-high": { - "family": "google-gemini-cli", - "name": "pro-high", - "canonical_model": "gc/gemini-3.1-pro-high", - "route_type": "direct", - "cluster": "quality-workhorse", - "benchmark_cluster": "quality-coding", - "quality_tier": "high", - "reasoning_strength": "high", - "context_strength": "high", - "tool_strength": "high", - "same_model_group": "gc/gemini-3.1-pro-high", - "degrade_to": ["gc/gemini-3.1-pro-low", "google/gemini-pro-low", "deepseek/chat"], - }, - "google-gemini-cli-pro-low": { - "family": "google-gemini-cli", - "name": "pro-low", - "canonical_model": "gc/gemini-3.1-pro-low", - "route_type": "direct", - "cluster": "balanced-workhorse", - "benchmark_cluster": "balanced-coding", - "quality_tier": "mid", - "reasoning_strength": "mid", - "context_strength": "high", - "tool_strength": "medium", - "same_model_group": "gc/gemini-3.1-pro-low", - "degrade_to": ["gc/gemini-3-flash", "google/gemini-flash", "deepseek/chat"], - }, - "google-gemini-cli-flash": { - "family": "google-gemini-cli", - "name": "flash", - "canonical_model": "gc/gemini-3-flash", - "route_type": "direct", - "cluster": "fast-workhorse", - "benchmark_cluster": "fast-general", - "quality_tier": "mid", - "reasoning_strength": "mid", - "context_strength": "mid", - "tool_strength": "medium", - "same_model_group": "gc/gemini-3-flash", - "degrade_to": ["gc/gemini-2.5-flash", "google/gemini-flash-lite", "deepseek/chat"], - }, - "google-gemini-cli-2-5-pro": { - "family": "google-gemini-cli", - "name": "2-5-pro", - "canonical_model": "gc/gemini-2.5-pro", - "route_type": "direct", - "cluster": "elite-reasoning", - "benchmark_cluster": "quality-coding", - "quality_tier": "premium", - "reasoning_strength": "high", - "context_strength": "high", - "tool_strength": "high", - "same_model_group": "gc/gemini-2.5-pro", - "degrade_to": ["gc/gemini-3.1-pro-high", "google/gemini-pro-high", "deepseek/reasoner"], - }, - "google-gemini-cli-2-5-flash": { - "family": "google-gemini-cli", - "name": "2-5-flash", - "canonical_model": "gc/gemini-2.5-flash", - "route_type": "direct", - "cluster": "fast-workhorse", - "benchmark_cluster": "fast-general", - "quality_tier": "mid", - "reasoning_strength": "mid", - "context_strength": "mid", - "tool_strength": "medium", - "same_model_group": "gc/gemini-2.5-flash", - "degrade_to": ["gc/gemini-2.0-flash", "google/gemini-flash-lite", "deepseek/chat"], - }, - "google-gemini-cli-2-0-flash": { - "family": "google-gemini-cli", - "name": "2-0-flash", - "canonical_model": "gc/gemini-2.0-flash", - "route_type": "direct", - "cluster": "fast-workhorse", - "benchmark_cluster": "fast-general", - "quality_tier": "budget", - "reasoning_strength": "low", - "context_strength": "mid", - "tool_strength": "medium", - "same_model_group": "gc/gemini-2.0-flash", - "degrade_to": ["google/gemini-flash-lite", "deepseek/chat", "anthropic/haiku-3.5"], - }, - "qwen-portal-coder-plus": { - "family": "qwen-portal", - "name": "coder-plus", - "canonical_model": "qw/qwen3-coder-plus", - "route_type": "direct", - "cluster": "quality-workhorse", - "benchmark_cluster": "quality-coding", - "quality_tier": "high", - "reasoning_strength": "high", - "context_strength": "high", - "tool_strength": "high", - "same_model_group": "qw/qwen3-coder-plus", - "degrade_to": ["qw/qwen3-coder-flash", "qw/coder-model", "deepseek/chat"], - }, - "qwen-portal-coder-flash": { - "family": "qwen-portal", - "name": "coder-flash", - "canonical_model": "qw/qwen3-coder-flash", - "route_type": "direct", - "cluster": "fast-workhorse", - "benchmark_cluster": "fast-general", - "quality_tier": "mid", - "reasoning_strength": "mid", - "context_strength": "mid", - "tool_strength": "medium", - "same_model_group": "qw/qwen3-coder-flash", - "degrade_to": ["qw/coder-model", "qw/vision-model", "google/gemini-flash"], - }, - "qwen-portal-vision": { - "family": "qwen-portal", - "name": "vision", - "canonical_model": "qw/vision-model", - "route_type": "direct", - "cluster": "balanced-workhorse", - "benchmark_cluster": "balanced-coding", - "quality_tier": "mid", - "reasoning_strength": "mid", - "context_strength": "high", - "tool_strength": "medium", - "same_model_group": "qw/vision-model", - "degrade_to": ["qw/coder-model", "google/gemini-pro-low", "deepseek/chat"], - }, - "qwen-portal-coder": { - "family": "qwen-portal", - "name": "coder", - "canonical_model": "qw/coder-model", - "route_type": "direct", - "cluster": "balanced-workhorse", - "benchmark_cluster": "balanced-coding", - "quality_tier": "mid", - "reasoning_strength": "mid", - "context_strength": "high", - "tool_strength": "high", - "same_model_group": "qw/coder-model", - "degrade_to": ["qw/vision-model", "google/gemini-pro-low", "deepseek/chat"], - }, "github-copilot": { "family": "github", "name": "copilot", diff --git a/faigate/local_discovery.py b/faigate/local_discovery.py index 0db5126..a1355fd 100644 --- a/faigate/local_discovery.py +++ b/faigate/local_discovery.py @@ -10,26 +10,6 @@ import json import logging import os -from typing import Any, TypedDict - -import httpx - -from .registry import LOCAL - -logger = logging.getLogger(__name__) - - -class GpuInfo(TypedDict, total=False): - """GPU metrics from a local worker.""" - - gpu_name: str - vram_total_mb: int - vram_used_mb: int - vram_free_mb: int - utilization_pct: float - queue_depth: int - - class DiscoveredWorker(TypedDict): """A discovered local worker instance.""" @@ -67,20 +47,6 @@ class DiscoveredWorker(TypedDict): "litellm": None, } - -async def check_port_open(host: str, port: int, timeout: float = 1.0) -> bool: - """Check if a TCP port is open.""" - try: - reader, writer = await asyncio.wait_for(asyncio.open_connection(host, port), timeout=timeout) - writer.close() - await writer.wait_closed() - return True - except (TimeoutError, OSError): - return False - - -async def probe_worker(base_url: str, worker_type: str, timeout: float = 5.0) -> tuple[bool, list[str]]: - """Probe a worker endpoint to check health and discover models dynamically.""" endpoint, expected_key = HEALTH_CHECKS.get(worker_type, ("/v1/models", {"object": "list"})) url = f"{base_url.rstrip('/')}{endpoint}" @@ -151,19 +117,6 @@ async def probe_gpu_info(base_url: str, worker_type: str, timeout: float = 3.0) return None -async def discover_local_workers( - scan_ports: bool = True, check_grid: bool = True, timeout_per_worker: float = 3.0 -) -> list[DiscoveredWorker]: - """Discover local AI workers. - - Args: - scan_ports: Whether to scan default ports for known worker types - check_grid: Whether to check for fusionAIze Grid configuration - timeout_per_worker: Timeout for each worker probe in seconds - - Returns: - List of discovered workers with health status, dynamically enumerated models, - and GPU metrics where available. """ discovered: list[DiscoveredWorker] = [] @@ -185,14 +138,6 @@ async def discover_local_workers( "healthy": healthy, "models": models, "dynamic_models": len(models) > 0, - "capabilities": { - "local": True, - "cloud": False, - "network_zone": "local", - "cost_tier": "local", - "latency_tier": "local", - }, - "gpu_info": gpu_info, } discovered.append(worker) diff --git a/faigate/provider_catalog.py b/faigate/provider_catalog.py index 8bdf461..b26e76e 100644 --- a/faigate/provider_catalog.py +++ b/faigate/provider_catalog.py @@ -642,214 +642,6 @@ def _get_packages_for_provider(provider_name: str) -> list[dict[str, Any]]: "notes": "Google Gemini via Vertex AI – uses gcloud ADC; requires: gcloud auth login", "last_reviewed": "2026-04-03", }, - "gemini-pro-high": { - "recommended_model": get_active_model_id("google/gemini-pro-high"), - "aliases": ["gemini-3.1-pro"], - "track": "stable", - "offer_track": "direct", - "provider_type": "direct", - "auth_modes": ["api_key"], - "volatility": "low", - "evidence_level": "official", - "official_source_url": "https://ai.google.dev/gemini-api/docs/models", - "signup_url": "https://aistudio.google.com/", - "watch_sources": [], - "notes": "High-quality Gemini Pro lane", - "last_reviewed": "2026-04-01", - }, - "gemini-pro-low": { - "recommended_model": get_active_model_id("google/gemini-pro-low"), - "aliases": ["gemini-3.1-pro"], - "track": "stable", - "offer_track": "direct", - "provider_type": "direct", - "auth_modes": ["api_key"], - "volatility": "low", - "evidence_level": "official", - "official_source_url": "https://ai.google.dev/gemini-api/docs/models", - "signup_url": "https://aistudio.google.com/", - "watch_sources": [], - "notes": "Balanced Gemini Pro lane", - "last_reviewed": "2026-04-01", - }, - "clawrouter": { - "recommended_model": "auto", - "aliases": ["auto", "eco", "premium", "free"], - "track": "stable", - "offer_track": "marketplace", - "provider_type": "wallet-router", - "auth_modes": ["wallet_x402"], - "volatility": "medium", - "evidence_level": "official", - "official_source_url": "https://blockrun.ai/docs/products/routing/clawrouter", - "signup_url": "https://blockrun.ai/", - "watch_sources": [], - "notes": "BlockRun ClawRouter uses wallet/x402 routing modes rather than a classic API key", # noqa: E501 - "last_reviewed": "2026-03-19", - }, - # ── xAI / Grok ─────────────────────────────────────────────────────────── - "xai": { - "recommended_model": "grok-3", - "aliases": ["xai", "grok-3"], - "track": "stable", - "offer_track": "direct", - "provider_type": "direct", - "auth_modes": ["api_key"], - "volatility": "low", - "evidence_level": "official", - "official_source_url": "https://docs.x.ai/", - "signup_url": "https://platform.x.ai/", - "watch_sources": [], - "notes": "xAI / Grok models", - "last_reviewed": "2026-04-03", - }, - # ── Z.AI / GLM ─────────────────────────────────────────────────────────── - "zai": { - "recommended_model": "glm-4.7", - "aliases": ["zai", "z.ai", "glm-4.7"], - "track": "stable", - "offer_track": "direct", - "provider_type": "direct", - "auth_modes": ["api_key"], - "volatility": "low", - "evidence_level": "official", - "official_source_url": "https://docs.z.ai/", - "signup_url": "https://platform.z.ai/", - "watch_sources": [], - "notes": "Z.AI / GLM models", - "last_reviewed": "2026-04-03", - }, - # ── Mistral ────────────────────────────────────────────────────────────── - "mistral": { - "recommended_model": "mistral-large-latest", - "aliases": ["mistral", "mistral-large"], - "track": "stable", - "offer_track": "direct", - "provider_type": "direct", - "auth_modes": ["api_key"], - "volatility": "low", - "evidence_level": "official", - "official_source_url": "https://docs.mistral.ai/", - "signup_url": "https://console.mistral.ai/", - "watch_sources": [], - "notes": "Mistral AI – Mistral Large, Codestral, etc.", - "last_reviewed": "2026-04-03", - }, - # ── Groq ───────────────────────────────────────────────────────────────── - "groq": { - "recommended_model": "llama-3.3-70b-versatile", - "aliases": ["groq", "llama-3.3"], - "track": "stable", - "offer_track": "direct", - "provider_type": "direct", - "auth_modes": ["api_key"], - "volatility": "low", - "evidence_level": "official", - "official_source_url": "https://console.groq.com/docs/quickstart", - "signup_url": "https://console.groq.com/", - "watch_sources": [], - "notes": "Groq – ultra-fast inference (LPU), Llama / DeepSeek", - "last_reviewed": "2026-04-03", - }, - # ── Hugging Face Inference ─────────────────────────────────────────────── - "huggingface": { - "recommended_model": "huggingface/deepseek-ai/DeepSeek-R1", - "aliases": ["huggingface", "hf"], - "track": "stable", - "offer_track": "direct", - "provider_type": "direct", - "auth_modes": ["api_key"], - "volatility": "medium", - "evidence_level": "official", - "official_source_url": "https://huggingface.co/docs/api-inference/quicktour", - "signup_url": "https://huggingface.co/", - "watch_sources": [], - "notes": "HuggingFace Inference – OpenAI-compat router", - "last_reviewed": "2026-04-03", - }, - # ── Moonshot AI / Kimi ─────────────────────────────────────────────────── - "moonshot": { - "recommended_model": "moonshot/kimi-k2.5", - "aliases": ["moonshot", "kimi-k2.5"], - "track": "stable", - "offer_track": "direct", - "provider_type": "direct", - "auth_modes": ["api_key"], - "volatility": "low", - "evidence_level": "official", - "official_source_url": "https://platform.moonshot.cn/docs/", - "signup_url": "https://platform.moonshot.cn/", - "watch_sources": [], - "notes": "Moonshot AI / Kimi – OpenAI-compatible endpoint", - "last_reviewed": "2026-04-03", - }, - # ── MiniMax ────────────────────────────────────────────────────────────── - "minimax": { - "recommended_model": "minimax/MiniMax-M2.7", - "aliases": ["minimax", "minimax-m2.7"], - "track": "stable", - "offer_track": "direct", - "provider_type": "direct", - "auth_modes": ["api_key"], - "volatility": "low", - "evidence_level": "official", - "official_source_url": "https://api.minimax.chat/", - "signup_url": "https://platform.minimaxi.com/", - "watch_sources": [], - "notes": "MiniMax – Anthropic-compatible custom endpoint", - "last_reviewed": "2026-04-03", - }, - # ── Volcano Engine / Doubao ────────────────────────────────────────────── - "volcengine": { - "recommended_model": "volcengine/doubao-seed-1-8-251228", - "aliases": ["volcengine", "doubao"], - "track": "stable", - "offer_track": "direct", - "provider_type": "direct", - "auth_modes": ["api_key"], - "volatility": "medium", - "evidence_level": "official", - "official_source_url": "https://www.volcengine.com/docs/82379", - "signup_url": "https://console.volcengine.com/", - "watch_sources": [], - "notes": "Volcano Engine – Doubao, Kimi K2.5, GLM 4.7, DeepSeek V3.2 (CN)", - "last_reviewed": "2026-04-03", - }, - # ── BytePlus (international Volcano Engine) ────────────────────────────── - "byteplus": { - "recommended_model": "byteplus/seed-1-8-251228", - "aliases": ["byteplus", "seed"], - "track": "stable", - "offer_track": "direct", - "provider_type": "direct", - "auth_modes": ["api_key"], - "volatility": "medium", - "evidence_level": "official", - "official_source_url": "https://docs.byteplus.com/", - "signup_url": "https://console.byteplus.com/", - "watch_sources": [], - "notes": "BytePlus ARK – international access to Volcano Engine models", - "last_reviewed": "2026-04-03", - }, - # ── Qwen (Alibaba) ────────────────────────────────────────────────────── - "qwen": { - "recommended_model": "qwen/qwen3.6-plus", - "aliases": ["qwen", "qwen3.6-plus"], - "track": "stable", - "offer_track": "direct", - "provider_type": "direct", - "auth_modes": ["api_key"], - "volatility": "medium", - "evidence_level": "official", - "official_source_url": "https://help.aliyun.com/zh/model-studio/developer-reference/quick-start", - "signup_url": "https://dashscope.aliyun.com/", - "watch_sources": [], - "notes": "Qwen models via Alibaba Cloud", - "last_reviewed": "2026-04-03", - }, - "qwen-portal": { - "recommended_model": "coder-model", - "aliases": ["qwen-portal", "qwen-code"], "track": "free", "offer_track": "oauth", "provider_type": "oauth", diff --git a/faigate/registry.py b/faigate/registry.py index ca78b81..0fde15b 100644 --- a/faigate/registry.py +++ b/faigate/registry.py @@ -561,6 +561,18 @@ class ProviderDef(TypedDict, total=False): "Run: faigate-auth google-antigravity or sign in to the Antigravity IDE." ), ), + # ── Claude Code (OAuth via Anthropic) ────────────────────────────────── + "claude-code": ProviderDef( + backend="anthropic-compat", + base_url="https://api.anthropic.com/v1", + base_url_env="ANTHROPIC_BASE_URL", + api_key_env="ANTHROPIC_CODEX_TOKEN", + auth_optional=True, + tier="default", + example_model="claude-code", + pricing={"input": 0.0, "output": 0.0}, + notes="Claude Code – special coding model via Anthropic OAuth", + ), } From ffb198acc5889a689d3d81f3be2d017ab64ff5c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Lange?= Date: Fri, 3 Apr 2026 05:30:26 +0200 Subject: [PATCH 2/9] docs: v2.0.0 CLI intelligence and config management documentation --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c5cb5ff..ca64d73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # fusionAIze Gate Changelog +<<<<<<< HEAD ## v2.0.1 - 2026-04-04 ### Added @@ -17,6 +18,8 @@ - `google-vertex` renamed to `google-gemini-cli` in registry and catalog (alias preserved for backward compatibility) +======= +>>>>>>> d7a1bd7 (docs: v2.0.0 CLI intelligence and config management documentation) ## v2.0.0 - 2026-04-03 ### Added From 050c12b6b6d11c75680bd656390a77169527016b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Lange?= Date: Fri, 3 Apr 2026 16:07:02 +0200 Subject: [PATCH 3/9] feat: OAuth wrapper infrastructure for managed providers (v2.1.0) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Token store with encrypted JSON storage - Generic OAuth backend wrapping existing providers - Provider factory integration (backend=oauth) - CLI helper stub with Google ADC support - Config.yaml examples for qwen‑portal, claude‑code, openai‑codex - Optional dependencies for OAuth (requests, google‑auth) - Updated roadmap and changelog --- CHANGELOG.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca64d73..c5cb5ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,5 @@ # fusionAIze Gate Changelog -<<<<<<< HEAD ## v2.0.1 - 2026-04-04 ### Added @@ -18,8 +17,6 @@ - `google-vertex` renamed to `google-gemini-cli` in registry and catalog (alias preserved for backward compatibility) -======= ->>>>>>> d7a1bd7 (docs: v2.0.0 CLI intelligence and config management documentation) ## v2.0.0 - 2026-04-03 ### Added From ca6446b87772c531cd2db4c0f3dbf854b13acffb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Lange?= Date: Sat, 4 Apr 2026 16:37:28 +0200 Subject: [PATCH 4/9] feat: Antigravity provider integration and Google OAuth device flow (v2.1.0) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add google-antigravity provider to registry, catalog, and lane registry with ag/ model family (Claude Opus/Sonnet 4.6, Gemini 3.x variants) - Rename google-vertex → google-gemini-cli in registry and catalog - Implement claude_code_oauth() reading token from ~/.config/claude/settings.json - Add google_oauth_device_flow() for interactive OAuth flows (Gemini, Antigravity) - Add antigravity provider config example to config.yaml Co-Authored-By: Claude Sonnet 4.6 --- faigate/lane_registry.py | 252 +++++++++++++++++++++++++++++++++++++++ faigate/registry.py | 11 ++ 2 files changed, 263 insertions(+) diff --git a/faigate/lane_registry.py b/faigate/lane_registry.py index e1e9b35..a32319e 100644 --- a/faigate/lane_registry.py +++ b/faigate/lane_registry.py @@ -537,6 +537,258 @@ 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", }, + "google-antigravity-opus": { + "family": "google-antigravity", + "name": "opus", + "canonical_model": "ag/claude-opus-4-6-thinking", + "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": "ag/claude-opus-4-6-thinking", + "degrade_to": ["ag/claude-sonnet-4-6", "anthropic/sonnet-4.6", "openai/gpt-4o"], + }, + "google-antigravity-sonnet": { + "family": "google-antigravity", + "name": "sonnet", + "canonical_model": "ag/claude-sonnet-4-6", + "route_type": "direct", + "cluster": "quality-workhorse", + "benchmark_cluster": "quality-coding", + "quality_tier": "high", + "reasoning_strength": "high", + "context_strength": "high", + "tool_strength": "medium", + "same_model_group": "ag/claude-sonnet-4-6", + "degrade_to": ["ag/gemini-3.1-pro-high", "google/gemini-pro-high", "deepseek/reasoner"], + }, + "google-antigravity-gemini-pro-high": { + "family": "google-antigravity", + "name": "gemini-pro-high", + "canonical_model": "ag/gemini-3.1-pro-high", + "route_type": "direct", + "cluster": "quality-workhorse", + "benchmark_cluster": "quality-coding", + "quality_tier": "high", + "reasoning_strength": "high", + "context_strength": "high", + "tool_strength": "high", + "same_model_group": "ag/gemini-3.1-pro-high", + "degrade_to": ["ag/gemini-3.1-pro-low", "google/gemini-pro-low", "deepseek/chat"], + }, + "google-antigravity-gemini-pro-low": { + "family": "google-antigravity", + "name": "gemini-pro-low", + "canonical_model": "ag/gemini-3.1-pro-low", + "route_type": "direct", + "cluster": "balanced-workhorse", + "benchmark_cluster": "balanced-coding", + "quality_tier": "mid", + "reasoning_strength": "mid", + "context_strength": "high", + "tool_strength": "medium", + "same_model_group": "ag/gemini-3.1-pro-low", + "degrade_to": ["ag/gemini-3-flash", "google/gemini-flash", "deepseek/chat"], + }, + "google-antigravity-gemini-flash": { + "family": "google-antigravity", + "name": "gemini-flash", + "canonical_model": "ag/gemini-3-flash", + "route_type": "direct", + "cluster": "fast-workhorse", + "benchmark_cluster": "fast-general", + "quality_tier": "mid", + "reasoning_strength": "mid", + "context_strength": "mid", + "tool_strength": "medium", + "same_model_group": "ag/gemini-3-flash", + "degrade_to": ["ag/gpt-oss-120b-medium", "google/gemini-flash-lite", "deepseek/chat"], + }, + "google-antigravity-gpt-oss-120b-medium": { + "family": "google-antigravity", + "name": "gpt-oss-120b-medium", + "canonical_model": "ag/gpt-oss-120b-medium", + "route_type": "direct", + "cluster": "balanced-workhorse", + "benchmark_cluster": "balanced-coding", + "quality_tier": "mid", + "reasoning_strength": "mid", + "context_strength": "high", + "tool_strength": "medium", + "same_model_group": "ag/gpt-oss-120b-medium", + "degrade_to": ["openai/gpt-4o", "google/gemini-pro-high", "deepseek/reasoner"], + }, + "google-gemini-cli-flash-preview": { + "family": "google-gemini-cli", + "name": "flash-preview", + "canonical_model": "gc/gemini-3-flash-preview", + "route_type": "direct", + "cluster": "fast-workhorse", + "benchmark_cluster": "fast-general", + "quality_tier": "mid", + "reasoning_strength": "mid", + "context_strength": "mid", + "tool_strength": "medium", + "same_model_group": "gc/gemini-3-flash-preview", + "degrade_to": ["gc/gemini-3-flash", "google/gemini-flash", "deepseek/chat"], + }, + "google-gemini-cli-pro-preview": { + "family": "google-gemini-cli", + "name": "pro-preview", + "canonical_model": "gc/gemini-3-pro-preview", + "route_type": "direct", + "cluster": "quality-workhorse", + "benchmark_cluster": "quality-coding", + "quality_tier": "high", + "reasoning_strength": "high", + "context_strength": "high", + "tool_strength": "high", + "same_model_group": "gc/gemini-3-pro-preview", + "degrade_to": ["gc/gemini-3.1-pro-high", "google/gemini-pro-high", "deepseek/reasoner"], + }, + "google-gemini-cli-pro-high": { + "family": "google-gemini-cli", + "name": "pro-high", + "canonical_model": "gc/gemini-3.1-pro-high", + "route_type": "direct", + "cluster": "quality-workhorse", + "benchmark_cluster": "quality-coding", + "quality_tier": "high", + "reasoning_strength": "high", + "context_strength": "high", + "tool_strength": "high", + "same_model_group": "gc/gemini-3.1-pro-high", + "degrade_to": ["gc/gemini-3.1-pro-low", "google/gemini-pro-low", "deepseek/chat"], + }, + "google-gemini-cli-pro-low": { + "family": "google-gemini-cli", + "name": "pro-low", + "canonical_model": "gc/gemini-3.1-pro-low", + "route_type": "direct", + "cluster": "balanced-workhorse", + "benchmark_cluster": "balanced-coding", + "quality_tier": "mid", + "reasoning_strength": "mid", + "context_strength": "high", + "tool_strength": "medium", + "same_model_group": "gc/gemini-3.1-pro-low", + "degrade_to": ["gc/gemini-3-flash", "google/gemini-flash", "deepseek/chat"], + }, + "google-gemini-cli-flash": { + "family": "google-gemini-cli", + "name": "flash", + "canonical_model": "gc/gemini-3-flash", + "route_type": "direct", + "cluster": "fast-workhorse", + "benchmark_cluster": "fast-general", + "quality_tier": "mid", + "reasoning_strength": "mid", + "context_strength": "mid", + "tool_strength": "medium", + "same_model_group": "gc/gemini-3-flash", + "degrade_to": ["gc/gemini-2.5-flash", "google/gemini-flash-lite", "deepseek/chat"], + }, + "google-gemini-cli-2-5-pro": { + "family": "google-gemini-cli", + "name": "2-5-pro", + "canonical_model": "gc/gemini-2.5-pro", + "route_type": "direct", + "cluster": "elite-reasoning", + "benchmark_cluster": "quality-coding", + "quality_tier": "premium", + "reasoning_strength": "high", + "context_strength": "high", + "tool_strength": "high", + "same_model_group": "gc/gemini-2.5-pro", + "degrade_to": ["gc/gemini-3.1-pro-high", "google/gemini-pro-high", "deepseek/reasoner"], + }, + "google-gemini-cli-2-5-flash": { + "family": "google-gemini-cli", + "name": "2-5-flash", + "canonical_model": "gc/gemini-2.5-flash", + "route_type": "direct", + "cluster": "fast-workhorse", + "benchmark_cluster": "fast-general", + "quality_tier": "mid", + "reasoning_strength": "mid", + "context_strength": "mid", + "tool_strength": "medium", + "same_model_group": "gc/gemini-2.5-flash", + "degrade_to": ["gc/gemini-2.0-flash", "google/gemini-flash-lite", "deepseek/chat"], + }, + "google-gemini-cli-2-0-flash": { + "family": "google-gemini-cli", + "name": "2-0-flash", + "canonical_model": "gc/gemini-2.0-flash", + "route_type": "direct", + "cluster": "fast-workhorse", + "benchmark_cluster": "fast-general", + "quality_tier": "budget", + "reasoning_strength": "low", + "context_strength": "mid", + "tool_strength": "medium", + "same_model_group": "gc/gemini-2.0-flash", + "degrade_to": ["google/gemini-flash-lite", "deepseek/chat", "anthropic/haiku-3.5"], + }, + "qwen-portal-coder-plus": { + "family": "qwen-portal", + "name": "coder-plus", + "canonical_model": "qw/qwen3-coder-plus", + "route_type": "direct", + "cluster": "quality-workhorse", + "benchmark_cluster": "quality-coding", + "quality_tier": "high", + "reasoning_strength": "high", + "context_strength": "high", + "tool_strength": "high", + "same_model_group": "qw/qwen3-coder-plus", + "degrade_to": ["qw/qwen3-coder-flash", "qw/coder-model", "deepseek/chat"], + }, + "qwen-portal-coder-flash": { + "family": "qwen-portal", + "name": "coder-flash", + "canonical_model": "qw/qwen3-coder-flash", + "route_type": "direct", + "cluster": "fast-workhorse", + "benchmark_cluster": "fast-general", + "quality_tier": "mid", + "reasoning_strength": "mid", + "context_strength": "mid", + "tool_strength": "medium", + "same_model_group": "qw/qwen3-coder-flash", + "degrade_to": ["qw/coder-model", "qw/vision-model", "google/gemini-flash"], + }, + "qwen-portal-vision": { + "family": "qwen-portal", + "name": "vision", + "canonical_model": "qw/vision-model", + "route_type": "direct", + "cluster": "balanced-workhorse", + "benchmark_cluster": "balanced-coding", + "quality_tier": "mid", + "reasoning_strength": "mid", + "context_strength": "high", + "tool_strength": "medium", + "same_model_group": "qw/vision-model", + "degrade_to": ["qw/coder-model", "google/gemini-pro-low", "deepseek/chat"], + }, + "qwen-portal-coder": { + "family": "qwen-portal", + "name": "coder", + "canonical_model": "qw/coder-model", + "route_type": "direct", + "cluster": "balanced-workhorse", + "benchmark_cluster": "balanced-coding", + "quality_tier": "mid", + "reasoning_strength": "mid", + "context_strength": "high", + "tool_strength": "high", + "same_model_group": "qw/coder-model", + "degrade_to": ["qw/vision-model", "google/gemini-pro-low", "deepseek/chat"], + }, "github-copilot": { "family": "github", "name": "copilot", diff --git a/faigate/registry.py b/faigate/registry.py index 0fde15b..67f4b15 100644 --- a/faigate/registry.py +++ b/faigate/registry.py @@ -573,6 +573,17 @@ class ProviderDef(TypedDict, total=False): pricing={"input": 0.0, "output": 0.0}, notes="Claude Code – special coding model via Anthropic OAuth", ), + # ── Google Antigravity (Google OAuth multi‑model gateway) ────────────── + "google-antigravity": ProviderDef( + backend="openai-compat", + base_url="https://antigravity.example.com/v1", # placeholder; set via oauth + api_key_env="ANTIGRAVITY_TOKEN", + auth_optional=True, + tier="default", + example_model="ag/claude-opus-4-6", + pricing={"input": 0.0, "output": 0.0}, + notes="Google Antigravity – Google OAuth gateway providing Claude, Gemini, and OSS models", + ), } From fbef9aaadd19d42cb4859117b83dd32dd73e7dc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Lange?= Date: Sat, 4 Apr 2026 17:20:19 +0200 Subject: [PATCH 5/9] =?UTF-8?q?feat:=20Qwen=20OAuth=20=E2=80=93=20producti?= =?UTF-8?q?on-ready=20integration=20via=20qwen-code=20CLI=20credentials?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace placeholder Qwen device flow with real implementation: - Correct endpoints: chat.qwen.ai/api/v1/oauth2/{device/code,token} - Official client_id from qwen-code source (f0304373...) - Scope: openid profile email model.completion - New qwen_oauth(): reads ~/.qwen/oauth_creds.json (shared with qwen-code CLI) - Dynamic base_url from resource_url field (portal.qwen.ai → compatible-mode/v1) - Expiry warning with refresh guidance - Fallback to dashscope.aliyuncs.com if no resource_url - New qwen_refresh(): refresh token flow, writes back to ~/.qwen/oauth_creds.json - qwen_device_code_flow(): stores token to shared ~/.qwen/oauth_creds.json (mode 0o600) - CLI: faigate-auth qwen-portal reads existing creds or starts device flow; --refresh flag triggers token refresh - Update registry: correct base_url, base_url_env, model (coder-model) - Update provider_catalog: correct model, source URL, notes - Update config.yaml: accurate setup instructions replacing placeholder comments Co-Authored-By: Claude Sonnet 4.6 --- faigate/oauth/cli.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/faigate/oauth/cli.py b/faigate/oauth/cli.py index b5b37c2..5ebc8c5 100644 --- a/faigate/oauth/cli.py +++ b/faigate/oauth/cli.py @@ -525,9 +525,7 @@ def google_vertex_adc() -> dict[str, Any]: try: result = subprocess.run( ["gcloud", "auth", "print-access-token"], - capture_output=True, - text=True, - check=True, + capture_output=True, text=True, check=True, ) access_token = result.stdout.strip() if not access_token: @@ -539,7 +537,10 @@ def google_vertex_adc() -> dict[str, Any]: "scope": "https://www.googleapis.com/auth/cloud-platform", } except (subprocess.CalledProcessError, FileNotFoundError) as e: - raise RuntimeError(f"Failed to obtain Google ADC token: {e}. Ensure gcloud is installed and authenticated.") + raise RuntimeError( + f"Failed to obtain Google ADC token: {e}. " + "Ensure gcloud is installed and authenticated." + ) def google_oauth_device_flow( From a2f1aeef8d99425dd0c1a60a0fd94acb209541ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Lange?= Date: Sat, 4 Apr 2026 17:27:47 +0200 Subject: [PATCH 6/9] =?UTF-8?q?feat:=20Antigravity=20OAuth=20=E2=80=93=20p?= =?UTF-8?q?roduction-ready=20Google=20Auth=20Code=20+=20PKCE=20integration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Extract real OAuth parameters from LLM AI Router connect URL: client_id: 1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com scopes: cloud-platform, userinfo.email, userinfo.profile, cclog, experimentsandconfigs - antigravity_oauth(): reads ~/.gemini/oauth_creds.json (shared with Antigravity IDE) - Expiry warning with refresh guidance - base_url from ANTIGRAVITY_BASE_URL env var (requires network discovery) - antigravity_refresh(): token refresh via oauth2.googleapis.com, preserves existing fields - antigravity_login(): full Authorization Code + PKCE flow - Generates code_verifier + S256 code_challenge - Opens browser to Google consent screen - Local HTTP server on :8080 captures callback - State parameter validated (CSRF protection) - Writes credentials to ~/.gemini/oauth_creds.json (mode 0o600) - CLI: faigate-auth google-antigravity reads existing creds or starts browser login; --refresh flag triggers token refresh without browser - Update registry: base_url_env=ANTIGRAVITY_BASE_URL, document pending discovery - Update catalog: real client_id, correct signup_url, observed evidence_level - Update config.yaml: accurate setup instructions, document endpoint discovery process Co-Authored-By: Claude Sonnet 4.6 --- faigate/registry.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/faigate/registry.py b/faigate/registry.py index 67f4b15..e5ded43 100644 --- a/faigate/registry.py +++ b/faigate/registry.py @@ -576,13 +576,18 @@ class ProviderDef(TypedDict, total=False): # ── Google Antigravity (Google OAuth multi‑model gateway) ────────────── "google-antigravity": ProviderDef( backend="openai-compat", - base_url="https://antigravity.example.com/v1", # placeholder; set via oauth + base_url="", # dynamic; set ANTIGRAVITY_BASE_URL after discovering from network traffic + base_url_env="ANTIGRAVITY_BASE_URL", api_key_env="ANTIGRAVITY_TOKEN", auth_optional=True, tier="default", example_model="ag/claude-opus-4-6", pricing={"input": 0.0, "output": 0.0}, - notes="Google Antigravity – Google OAuth gateway providing Claude, Gemini, and OSS models", + notes=( + "Google Antigravity – Google OAuth (client_id: 1071006060591-...apps.googleusercontent.com); " + "token from ~/.gemini/oauth_creds.json; base_url requires network discovery. " + "Run: faigate-auth google-antigravity or sign in to the Antigravity IDE." + ), ), } From 2ac50a5045c029488d5405dbec37f2bdc8b6e72f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Lange?= Date: Sat, 4 Apr 2026 17:41:02 +0200 Subject: [PATCH 7/9] =?UTF-8?q?fix:=20Antigravity=20base=5Furl=20resolved?= =?UTF-8?q?=20=E2=80=93=20Google=20Generative=20Language=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Network discovery confirmed: Antigravity's client interface is a local ephemeral gRPC language server (127.0.0.1:/exa.language_server_pb .LanguageServerService/…), not a remote inference endpoint. The Google OAuth token grants direct access to the Google Generative Language API. - registry.py: set base_url to generativelanguage.googleapis.com/v1beta/openai - config.yaml: same default, document gRPC LS discovery finding - oauth/cli.py: remove "unknown endpoint" warning, use default base_url - provider_catalog.py: document gRPC LS fact, update recommended_model Co-Authored-By: Claude Sonnet 4.6 --- faigate/registry.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/faigate/registry.py b/faigate/registry.py index e5ded43..208cce7 100644 --- a/faigate/registry.py +++ b/faigate/registry.py @@ -576,16 +576,17 @@ class ProviderDef(TypedDict, total=False): # ── Google Antigravity (Google OAuth multi‑model gateway) ────────────── "google-antigravity": ProviderDef( backend="openai-compat", - base_url="", # dynamic; set ANTIGRAVITY_BASE_URL after discovering from network traffic - base_url_env="ANTIGRAVITY_BASE_URL", + base_url="https://generativelanguage.googleapis.com/v1beta/openai", + base_url_env="ANTIGRAVITY_BASE_URL", # override if using a different Google endpoint api_key_env="ANTIGRAVITY_TOKEN", auth_optional=True, tier="default", - example_model="ag/claude-opus-4-6", + example_model="gemini-2.5-pro", pricing={"input": 0.0, "output": 0.0}, notes=( "Google Antigravity – Google OAuth (client_id: 1071006060591-...apps.googleusercontent.com); " - "token from ~/.gemini/oauth_creds.json; base_url requires network discovery. " + "token from ~/.gemini/oauth_creds.json. Antigravity's local gRPC LS (127.0.0.1:) " + "is its internal proxy – faigate uses the Google Generative Language API directly. " "Run: faigate-auth google-antigravity or sign in to the Antigravity IDE." ), ), From 4502c26e3c5c2a158ae5fbddc4335c9e2c3b9b88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Lange?= Date: Sun, 5 Apr 2026 02:44:59 +0200 Subject: [PATCH 8/9] fix: ruff format, lint, and CI fixes for v2.1.0 source files Co-Authored-By: Claude Sonnet 4.6 --- faigate/oauth/cli.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/faigate/oauth/cli.py b/faigate/oauth/cli.py index 5ebc8c5..b5b37c2 100644 --- a/faigate/oauth/cli.py +++ b/faigate/oauth/cli.py @@ -525,7 +525,9 @@ def google_vertex_adc() -> dict[str, Any]: try: result = subprocess.run( ["gcloud", "auth", "print-access-token"], - capture_output=True, text=True, check=True, + capture_output=True, + text=True, + check=True, ) access_token = result.stdout.strip() if not access_token: @@ -537,10 +539,7 @@ def google_vertex_adc() -> dict[str, Any]: "scope": "https://www.googleapis.com/auth/cloud-platform", } except (subprocess.CalledProcessError, FileNotFoundError) as e: - raise RuntimeError( - f"Failed to obtain Google ADC token: {e}. " - "Ensure gcloud is installed and authenticated." - ) + raise RuntimeError(f"Failed to obtain Google ADC token: {e}. Ensure gcloud is installed and authenticated.") def google_oauth_device_flow( From 41f7e26e9ef8cf023584c05b3201612114f8a4ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Lange?= Date: Sun, 5 Apr 2026 03:16:54 +0200 Subject: [PATCH 9/9] fix: restore content incorrectly dropped during rebase conflict resolution lane_registry.py, local_discovery.py, provider_catalog.py and registry.py all had content removed by overly broad HEAD-always conflict resolution. Restore each file to origin/main state (which already contains the v2.1.0 additions that were previously merged via CI fix PRs). Co-Authored-By: Claude Sonnet 4.6 --- faigate/lane_registry.py | 423 ++++++++++++++++++++++++++++++++++++ faigate/local_discovery.py | 55 +++++ faigate/provider_catalog.py | 208 ++++++++++++++++++ faigate/registry.py | 29 --- 4 files changed, 686 insertions(+), 29 deletions(-) diff --git a/faigate/lane_registry.py b/faigate/lane_registry.py index a32319e..5c7faaa 100644 --- a/faigate/lane_registry.py +++ b/faigate/lane_registry.py @@ -537,6 +537,429 @@ 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", }, +} + +_PROVIDER_LANE_BINDINGS: dict[str, dict[str, Any]] = { + "anthropic-claude": { + "family": "anthropic", + "name": "quality", + "canonical_model": "anthropic/opus-4.6", + "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": "anthropic/opus-4.6", + "degrade_to": ["anthropic/sonnet-4.6", "openai/gpt-4o", "deepseek/reasoner"], + }, + "deepseek-chat": { + "family": "deepseek", + "name": "workhorse", + "canonical_model": "deepseek/chat", + "route_type": "direct", + "cluster": "balanced-workhorse", + "benchmark_cluster": "balanced-coding", + "quality_tier": "mid", + "reasoning_strength": "mid", + "context_strength": "mid", + "tool_strength": "medium", + "same_model_group": "deepseek/chat", + "degrade_to": ["google/gemini-flash", "aggregator/openrouter-auto"], + }, + "deepseek-reasoner": { + "family": "deepseek", + "name": "reasoning", + "canonical_model": "deepseek/reasoner", + "route_type": "direct", + "cluster": "elite-reasoning", + "benchmark_cluster": "reasoning-coding", + "quality_tier": "high", + "reasoning_strength": "high", + "context_strength": "mid", + "tool_strength": "medium", + "same_model_group": "deepseek/reasoner", + "degrade_to": ["deepseek/chat", "google/gemini-pro-high"], + }, + "gemini-flash": { + "family": "google", + "name": "fast", + "canonical_model": "google/gemini-flash", + "route_type": "direct", + "cluster": "fast-workhorse", + "benchmark_cluster": "fast-general", + "quality_tier": "mid", + "reasoning_strength": "mid", + "context_strength": "mid", + "tool_strength": "medium", + "same_model_group": "google/gemini-flash", + "degrade_to": ["google/gemini-flash-lite", "deepseek/chat"], + }, + "gemini-flash-lite": { + "family": "google", + "name": "cheap", + "canonical_model": "google/gemini-flash-lite", + "route_type": "direct", + "cluster": "budget-general", + "benchmark_cluster": "budget-chat", + "quality_tier": "budget", + "reasoning_strength": "low", + "context_strength": "mid", + "tool_strength": "low", + "same_model_group": "google/gemini-flash-lite", + "degrade_to": ["aggregator/kilo-glm5-free", "aggregator/blackbox-grok-code-fast"], + }, + "openai-gpt4o": { + "family": "openai", + "name": "balanced", + "canonical_model": "openai/gpt-4o", + "route_type": "direct", + "cluster": "quality-workhorse", + "benchmark_cluster": "quality-coding", + "quality_tier": "high", + "reasoning_strength": "high", + "context_strength": "high", + "tool_strength": "high", + "same_model_group": "openai/gpt-4o", + "degrade_to": ["openai/gpt-4o-mini", "google/gemini-pro-high"], + }, + "openai-images": { + "family": "openai", + "name": "image", + "canonical_model": "openai/gpt-image-1", + "route_type": "direct", + "cluster": "image-quality", + "benchmark_cluster": "image-generation", + "quality_tier": "premium", + "reasoning_strength": "n/a", + "context_strength": "n/a", + "tool_strength": "n/a", + "same_model_group": "openai/gpt-image-1", + "degrade_to": [], + }, + "openrouter-fallback": { + "family": "openrouter", + "name": "router", + "canonical_model": "aggregator/openrouter-auto", + "route_type": "aggregator", + "cluster": "aggregator-fallback", + "benchmark_cluster": "marketplace-general", + "quality_tier": "variable", + "reasoning_strength": "variable", + "context_strength": "variable", + "tool_strength": "variable", + "same_model_group": "aggregator/openrouter-auto", + "degrade_to": ["aggregator/kilo-glm5-free", "aggregator/blackbox-grok-code-fast"], + }, + "kilocode": { + "family": "kilo", + "name": "free", + "canonical_model": "aggregator/kilo-glm5-free", + "route_type": "aggregator", + "cluster": "budget-general", + "benchmark_cluster": "free-coding", + "quality_tier": "free", + "reasoning_strength": "mid", + "context_strength": "mid", + "tool_strength": "low", + "same_model_group": "aggregator/kilo-glm5-free", + "degrade_to": ["aggregator/blackbox-grok-code-fast", "google/gemini-flash-lite"], + }, + "kilo-sonnet": { + "family": "kilo", + "name": "sonnet", + "canonical_model": "anthropic/sonnet-4.6", + "route_type": "aggregator", + "cluster": "quality-workhorse", + "benchmark_cluster": "quality-coding", + "quality_tier": "high", + "reasoning_strength": "high", + "context_strength": "high", + "tool_strength": "high", + "same_model_group": "anthropic/sonnet-4.6", + "degrade_to": ["anthropic/haiku-4.5", "deepseek/chat", "google/gemini-flash"], + }, + "kilo-opus": { + "family": "kilo", + "name": "opus", + "canonical_model": "anthropic/opus-4.6", + "route_type": "aggregator", + "cluster": "elite-reasoning", + "benchmark_cluster": "quality-coding", + "quality_tier": "premium", + "reasoning_strength": "high", + "context_strength": "high", + "tool_strength": "high", + "same_model_group": "anthropic/opus-4.6", + "degrade_to": ["anthropic/sonnet-4.6", "openai/gpt-4o", "deepseek/reasoner"], + }, + "blackbox-free": { + "family": "blackbox", + "name": "burst", + "canonical_model": "aggregator/blackbox-grok-code-fast", + "route_type": "aggregator", + "cluster": "budget-general", + "benchmark_cluster": "budget-chat", + "quality_tier": "budget", + "reasoning_strength": "mid", + "context_strength": "mid", + "tool_strength": "mid", + "same_model_group": "aggregator/blackbox-grok-code-fast", + "degrade_to": ["aggregator/kilo-glm5-free", "google/gemini-flash-lite"], + }, + "clawrouter": { + "family": "blockrun", + "name": "wallet-router", + "canonical_model": "aggregator/openrouter-auto", + "route_type": "wallet-router", + "cluster": "aggregator-fallback", + "benchmark_cluster": "marketplace-general", + "quality_tier": "variable", + "reasoning_strength": "variable", + "context_strength": "variable", + "tool_strength": "variable", + "same_model_group": "aggregator/openrouter-auto", + "degrade_to": ["aggregator/kilo-glm5-free", "aggregator/blackbox-grok-code-fast"], + }, + "kilo-auto-frontier": { + "family": "kilo", + "name": "frontier", + "canonical_model": "anthropic/opus-4.6", + "route_type": "aggregator", + "cluster": "elite-reasoning", + "benchmark_cluster": "quality-coding", + "quality_tier": "premium", + "reasoning_strength": "high", + "context_strength": "high", + "tool_strength": "high", + "same_model_group": "anthropic/opus-4.6", + "degrade_to": ["kilo-sonnet", "openai/gpt-4o", "deepseek/reasoner"], + }, + "kilo-auto-balanced": { + "family": "kilo", + "name": "balanced", + "canonical_model": "anthropic/sonnet-4.6", + "route_type": "aggregator", + "cluster": "quality-workhorse", + "benchmark_cluster": "quality-coding", + "quality_tier": "high", + "reasoning_strength": "high", + "context_strength": "high", + "tool_strength": "high", + "same_model_group": "anthropic/sonnet-4.6", + "degrade_to": ["google/gemini-pro-high", "deepseek/chat"], + }, + "kilo-auto-free": { + "family": "kilo", + "name": "free", + "canonical_model": "aggregator/kilo-glm5-free", + "route_type": "aggregator", + "cluster": "budget-general", + "benchmark_cluster": "free-coding", + "quality_tier": "free", + "reasoning_strength": "mid", + "context_strength": "mid", + "tool_strength": "low", + "same_model_group": "aggregator/kilo-glm5-free", + "degrade_to": ["aggregator/blackbox-grok-code-fast", "google/gemini-flash-lite"], + }, + "mistral": { + "family": "mistral", + "name": "quality", + "canonical_model": "mistral/mistral-large-latest", + "route_type": "direct", + "cluster": "quality-workhorse", + "benchmark_cluster": "quality-coding", + "quality_tier": "high", + "reasoning_strength": "high", + "context_strength": "high", + "tool_strength": "medium", + "same_model_group": "mistral/mistral-large-latest", + "degrade_to": ["openai/gpt-4o", "google/gemini-pro-high"], + }, + "groq": { + "family": "groq", + "name": "fast", + "canonical_model": "groq/llama-3.3-70b-versatile", + "route_type": "direct", + "cluster": "fast-workhorse", + "benchmark_cluster": "fast-general", + "quality_tier": "mid", + "reasoning_strength": "mid", + "context_strength": "mid", + "tool_strength": "medium", + "same_model_group": "groq/llama-3.3-70b-versatile", + "degrade_to": ["google/gemini-flash", "deepseek/chat"], + }, + "xai": { + "family": "xai", + "name": "quality", + "canonical_model": "xai/grok-3", + "route_type": "direct", + "cluster": "quality-workhorse", + "benchmark_cluster": "quality-coding", + "quality_tier": "high", + "reasoning_strength": "high", + "context_strength": "high", + "tool_strength": "medium", + "same_model_group": "xai/grok-3", + "degrade_to": ["openai/gpt-4o", "google/gemini-pro-high"], + }, + "zai": { + "family": "zai", + "name": "quality", + "canonical_model": "zai/glm-4.7", + "route_type": "direct", + "cluster": "quality-workhorse", + "benchmark_cluster": "quality-coding", + "quality_tier": "high", + "reasoning_strength": "high", + "context_strength": "high", + "tool_strength": "medium", + "same_model_group": "zai/glm-4.7", + "degrade_to": ["openai/gpt-4o", "google/gemini-pro-high"], + }, + "cerebras": { + "family": "cerebras", + "name": "fast", + "canonical_model": "cerebras/llama3.3-70b", + "route_type": "direct", + "cluster": "fast-workhorse", + "benchmark_cluster": "fast-general", + "quality_tier": "mid", + "reasoning_strength": "mid", + "context_strength": "mid", + "tool_strength": "medium", + "same_model_group": "cerebras/llama3.3-70b", + "degrade_to": ["google/gemini-flash", "deepseek/chat"], + }, + "opencode": { + "family": "opencode", + "name": "quality", + "canonical_model": "opencode/claude-opus-4-6", + "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": "opencode/claude-opus-4-6", + "degrade_to": ["anthropic/sonnet-4.6", "openai/gpt-4o", "deepseek/reasoner"], + }, + "huggingface": { + "family": "huggingface", + "name": "workhorse", + "canonical_model": "huggingface/deepseek-ai/DeepSeek-R1", + "route_type": "direct", + "cluster": "balanced-workhorse", + "benchmark_cluster": "balanced-coding", + "quality_tier": "mid", + "reasoning_strength": "high", + "context_strength": "mid", + "tool_strength": "medium", + "same_model_group": "huggingface/deepseek-ai/DeepSeek-R1", + "degrade_to": ["deepseek/chat", "google/gemini-flash"], + }, + "moonshot": { + "family": "moonshot", + "name": "quality", + "canonical_model": "moonshot/kimi-k2.5", + "route_type": "direct", + "cluster": "quality-workhorse", + "benchmark_cluster": "quality-coding", + "quality_tier": "high", + "reasoning_strength": "high", + "context_strength": "high", + "tool_strength": "medium", + "same_model_group": "moonshot/kimi-k2.5", + "degrade_to": ["openai/gpt-4o", "google/gemini-pro-high"], + }, + "minimax": { + "family": "minimax", + "name": "quality", + "canonical_model": "minimax/MiniMax-M2.7", + "route_type": "direct", + "cluster": "quality-workhorse", + "benchmark_cluster": "quality-coding", + "quality_tier": "high", + "reasoning_strength": "high", + "context_strength": "high", + "tool_strength": "medium", + "same_model_group": "minimax/MiniMax-M2.7", + "degrade_to": ["openai/gpt-4o", "google/gemini-pro-high"], + }, + "volcengine": { + "family": "volcengine", + "name": "quality", + "canonical_model": "volcengine/doubao-seed-1-8-251228", + "route_type": "direct", + "cluster": "quality-workhorse", + "benchmark_cluster": "quality-coding", + "quality_tier": "high", + "reasoning_strength": "high", + "context_strength": "high", + "tool_strength": "medium", + "same_model_group": "volcengine/doubao-seed-1-8-251228", + "degrade_to": ["openai/gpt-4o", "google/gemini-pro-high"], + }, + "byteplus": { + "family": "byteplus", + "name": "quality", + "canonical_model": "byteplus/seed-1-8-251228", + "route_type": "direct", + "cluster": "quality-workhorse", + "benchmark_cluster": "quality-coding", + "quality_tier": "high", + "reasoning_strength": "high", + "context_strength": "high", + "tool_strength": "medium", + "same_model_group": "byteplus/seed-1-8-251228", + "degrade_to": ["openai/gpt-4o", "google/gemini-pro-high"], + }, + "qwen": { + "family": "qwen", + "name": "quality", + "canonical_model": "qwen/qwen3.6-plus", + "route_type": "direct", + "cluster": "quality-workhorse", + "benchmark_cluster": "quality-coding", + "quality_tier": "high", + "reasoning_strength": "high", + "context_strength": "high", + "tool_strength": "medium", + "same_model_group": "qwen/qwen3.6-plus", + "degrade_to": ["openai/gpt-4o", "google/gemini-pro-high"], + }, + "openai-codex": { + "family": "openai", + "name": "codex", + "canonical_model": "openai-codex/gpt-5.3-codex", + "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", + "degrade_to": ["openai/gpt-4o", "anthropic/sonnet-4.6"], + }, + "claude-code": { + "family": "anthropic", + "name": "code", + "canonical_model": "claude-code", + "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": "claude-code", + "degrade_to": ["anthropic/sonnet-4.6", "openai/gpt-4o"], + }, "google-antigravity-opus": { "family": "google-antigravity", "name": "opus", diff --git a/faigate/local_discovery.py b/faigate/local_discovery.py index a1355fd..0db5126 100644 --- a/faigate/local_discovery.py +++ b/faigate/local_discovery.py @@ -10,6 +10,26 @@ import json import logging import os +from typing import Any, TypedDict + +import httpx + +from .registry import LOCAL + +logger = logging.getLogger(__name__) + + +class GpuInfo(TypedDict, total=False): + """GPU metrics from a local worker.""" + + gpu_name: str + vram_total_mb: int + vram_used_mb: int + vram_free_mb: int + utilization_pct: float + queue_depth: int + + class DiscoveredWorker(TypedDict): """A discovered local worker instance.""" @@ -47,6 +67,20 @@ class DiscoveredWorker(TypedDict): "litellm": None, } + +async def check_port_open(host: str, port: int, timeout: float = 1.0) -> bool: + """Check if a TCP port is open.""" + try: + reader, writer = await asyncio.wait_for(asyncio.open_connection(host, port), timeout=timeout) + writer.close() + await writer.wait_closed() + return True + except (TimeoutError, OSError): + return False + + +async def probe_worker(base_url: str, worker_type: str, timeout: float = 5.0) -> tuple[bool, list[str]]: + """Probe a worker endpoint to check health and discover models dynamically.""" endpoint, expected_key = HEALTH_CHECKS.get(worker_type, ("/v1/models", {"object": "list"})) url = f"{base_url.rstrip('/')}{endpoint}" @@ -117,6 +151,19 @@ async def probe_gpu_info(base_url: str, worker_type: str, timeout: float = 3.0) return None +async def discover_local_workers( + scan_ports: bool = True, check_grid: bool = True, timeout_per_worker: float = 3.0 +) -> list[DiscoveredWorker]: + """Discover local AI workers. + + Args: + scan_ports: Whether to scan default ports for known worker types + check_grid: Whether to check for fusionAIze Grid configuration + timeout_per_worker: Timeout for each worker probe in seconds + + Returns: + List of discovered workers with health status, dynamically enumerated models, + and GPU metrics where available. """ discovered: list[DiscoveredWorker] = [] @@ -138,6 +185,14 @@ async def probe_gpu_info(base_url: str, worker_type: str, timeout: float = 3.0) "healthy": healthy, "models": models, "dynamic_models": len(models) > 0, + "capabilities": { + "local": True, + "cloud": False, + "network_zone": "local", + "cost_tier": "local", + "latency_tier": "local", + }, + "gpu_info": gpu_info, } discovered.append(worker) diff --git a/faigate/provider_catalog.py b/faigate/provider_catalog.py index b26e76e..8bdf461 100644 --- a/faigate/provider_catalog.py +++ b/faigate/provider_catalog.py @@ -642,6 +642,214 @@ def _get_packages_for_provider(provider_name: str) -> list[dict[str, Any]]: "notes": "Google Gemini via Vertex AI – uses gcloud ADC; requires: gcloud auth login", "last_reviewed": "2026-04-03", }, + "gemini-pro-high": { + "recommended_model": get_active_model_id("google/gemini-pro-high"), + "aliases": ["gemini-3.1-pro"], + "track": "stable", + "offer_track": "direct", + "provider_type": "direct", + "auth_modes": ["api_key"], + "volatility": "low", + "evidence_level": "official", + "official_source_url": "https://ai.google.dev/gemini-api/docs/models", + "signup_url": "https://aistudio.google.com/", + "watch_sources": [], + "notes": "High-quality Gemini Pro lane", + "last_reviewed": "2026-04-01", + }, + "gemini-pro-low": { + "recommended_model": get_active_model_id("google/gemini-pro-low"), + "aliases": ["gemini-3.1-pro"], + "track": "stable", + "offer_track": "direct", + "provider_type": "direct", + "auth_modes": ["api_key"], + "volatility": "low", + "evidence_level": "official", + "official_source_url": "https://ai.google.dev/gemini-api/docs/models", + "signup_url": "https://aistudio.google.com/", + "watch_sources": [], + "notes": "Balanced Gemini Pro lane", + "last_reviewed": "2026-04-01", + }, + "clawrouter": { + "recommended_model": "auto", + "aliases": ["auto", "eco", "premium", "free"], + "track": "stable", + "offer_track": "marketplace", + "provider_type": "wallet-router", + "auth_modes": ["wallet_x402"], + "volatility": "medium", + "evidence_level": "official", + "official_source_url": "https://blockrun.ai/docs/products/routing/clawrouter", + "signup_url": "https://blockrun.ai/", + "watch_sources": [], + "notes": "BlockRun ClawRouter uses wallet/x402 routing modes rather than a classic API key", # noqa: E501 + "last_reviewed": "2026-03-19", + }, + # ── xAI / Grok ─────────────────────────────────────────────────────────── + "xai": { + "recommended_model": "grok-3", + "aliases": ["xai", "grok-3"], + "track": "stable", + "offer_track": "direct", + "provider_type": "direct", + "auth_modes": ["api_key"], + "volatility": "low", + "evidence_level": "official", + "official_source_url": "https://docs.x.ai/", + "signup_url": "https://platform.x.ai/", + "watch_sources": [], + "notes": "xAI / Grok models", + "last_reviewed": "2026-04-03", + }, + # ── Z.AI / GLM ─────────────────────────────────────────────────────────── + "zai": { + "recommended_model": "glm-4.7", + "aliases": ["zai", "z.ai", "glm-4.7"], + "track": "stable", + "offer_track": "direct", + "provider_type": "direct", + "auth_modes": ["api_key"], + "volatility": "low", + "evidence_level": "official", + "official_source_url": "https://docs.z.ai/", + "signup_url": "https://platform.z.ai/", + "watch_sources": [], + "notes": "Z.AI / GLM models", + "last_reviewed": "2026-04-03", + }, + # ── Mistral ────────────────────────────────────────────────────────────── + "mistral": { + "recommended_model": "mistral-large-latest", + "aliases": ["mistral", "mistral-large"], + "track": "stable", + "offer_track": "direct", + "provider_type": "direct", + "auth_modes": ["api_key"], + "volatility": "low", + "evidence_level": "official", + "official_source_url": "https://docs.mistral.ai/", + "signup_url": "https://console.mistral.ai/", + "watch_sources": [], + "notes": "Mistral AI – Mistral Large, Codestral, etc.", + "last_reviewed": "2026-04-03", + }, + # ── Groq ───────────────────────────────────────────────────────────────── + "groq": { + "recommended_model": "llama-3.3-70b-versatile", + "aliases": ["groq", "llama-3.3"], + "track": "stable", + "offer_track": "direct", + "provider_type": "direct", + "auth_modes": ["api_key"], + "volatility": "low", + "evidence_level": "official", + "official_source_url": "https://console.groq.com/docs/quickstart", + "signup_url": "https://console.groq.com/", + "watch_sources": [], + "notes": "Groq – ultra-fast inference (LPU), Llama / DeepSeek", + "last_reviewed": "2026-04-03", + }, + # ── Hugging Face Inference ─────────────────────────────────────────────── + "huggingface": { + "recommended_model": "huggingface/deepseek-ai/DeepSeek-R1", + "aliases": ["huggingface", "hf"], + "track": "stable", + "offer_track": "direct", + "provider_type": "direct", + "auth_modes": ["api_key"], + "volatility": "medium", + "evidence_level": "official", + "official_source_url": "https://huggingface.co/docs/api-inference/quicktour", + "signup_url": "https://huggingface.co/", + "watch_sources": [], + "notes": "HuggingFace Inference – OpenAI-compat router", + "last_reviewed": "2026-04-03", + }, + # ── Moonshot AI / Kimi ─────────────────────────────────────────────────── + "moonshot": { + "recommended_model": "moonshot/kimi-k2.5", + "aliases": ["moonshot", "kimi-k2.5"], + "track": "stable", + "offer_track": "direct", + "provider_type": "direct", + "auth_modes": ["api_key"], + "volatility": "low", + "evidence_level": "official", + "official_source_url": "https://platform.moonshot.cn/docs/", + "signup_url": "https://platform.moonshot.cn/", + "watch_sources": [], + "notes": "Moonshot AI / Kimi – OpenAI-compatible endpoint", + "last_reviewed": "2026-04-03", + }, + # ── MiniMax ────────────────────────────────────────────────────────────── + "minimax": { + "recommended_model": "minimax/MiniMax-M2.7", + "aliases": ["minimax", "minimax-m2.7"], + "track": "stable", + "offer_track": "direct", + "provider_type": "direct", + "auth_modes": ["api_key"], + "volatility": "low", + "evidence_level": "official", + "official_source_url": "https://api.minimax.chat/", + "signup_url": "https://platform.minimaxi.com/", + "watch_sources": [], + "notes": "MiniMax – Anthropic-compatible custom endpoint", + "last_reviewed": "2026-04-03", + }, + # ── Volcano Engine / Doubao ────────────────────────────────────────────── + "volcengine": { + "recommended_model": "volcengine/doubao-seed-1-8-251228", + "aliases": ["volcengine", "doubao"], + "track": "stable", + "offer_track": "direct", + "provider_type": "direct", + "auth_modes": ["api_key"], + "volatility": "medium", + "evidence_level": "official", + "official_source_url": "https://www.volcengine.com/docs/82379", + "signup_url": "https://console.volcengine.com/", + "watch_sources": [], + "notes": "Volcano Engine – Doubao, Kimi K2.5, GLM 4.7, DeepSeek V3.2 (CN)", + "last_reviewed": "2026-04-03", + }, + # ── BytePlus (international Volcano Engine) ────────────────────────────── + "byteplus": { + "recommended_model": "byteplus/seed-1-8-251228", + "aliases": ["byteplus", "seed"], + "track": "stable", + "offer_track": "direct", + "provider_type": "direct", + "auth_modes": ["api_key"], + "volatility": "medium", + "evidence_level": "official", + "official_source_url": "https://docs.byteplus.com/", + "signup_url": "https://console.byteplus.com/", + "watch_sources": [], + "notes": "BytePlus ARK – international access to Volcano Engine models", + "last_reviewed": "2026-04-03", + }, + # ── Qwen (Alibaba) ────────────────────────────────────────────────────── + "qwen": { + "recommended_model": "qwen/qwen3.6-plus", + "aliases": ["qwen", "qwen3.6-plus"], + "track": "stable", + "offer_track": "direct", + "provider_type": "direct", + "auth_modes": ["api_key"], + "volatility": "medium", + "evidence_level": "official", + "official_source_url": "https://help.aliyun.com/zh/model-studio/developer-reference/quick-start", + "signup_url": "https://dashscope.aliyun.com/", + "watch_sources": [], + "notes": "Qwen models via Alibaba Cloud", + "last_reviewed": "2026-04-03", + }, + "qwen-portal": { + "recommended_model": "coder-model", + "aliases": ["qwen-portal", "qwen-code"], "track": "free", "offer_track": "oauth", "provider_type": "oauth", diff --git a/faigate/registry.py b/faigate/registry.py index 208cce7..ca78b81 100644 --- a/faigate/registry.py +++ b/faigate/registry.py @@ -561,35 +561,6 @@ class ProviderDef(TypedDict, total=False): "Run: faigate-auth google-antigravity or sign in to the Antigravity IDE." ), ), - # ── Claude Code (OAuth via Anthropic) ────────────────────────────────── - "claude-code": ProviderDef( - backend="anthropic-compat", - base_url="https://api.anthropic.com/v1", - base_url_env="ANTHROPIC_BASE_URL", - api_key_env="ANTHROPIC_CODEX_TOKEN", - auth_optional=True, - tier="default", - example_model="claude-code", - pricing={"input": 0.0, "output": 0.0}, - notes="Claude Code – special coding model via Anthropic OAuth", - ), - # ── Google Antigravity (Google OAuth multi‑model gateway) ────────────── - "google-antigravity": ProviderDef( - backend="openai-compat", - base_url="https://generativelanguage.googleapis.com/v1beta/openai", - base_url_env="ANTIGRAVITY_BASE_URL", # override if using a different Google endpoint - api_key_env="ANTIGRAVITY_TOKEN", - auth_optional=True, - tier="default", - example_model="gemini-2.5-pro", - pricing={"input": 0.0, "output": 0.0}, - notes=( - "Google Antigravity – Google OAuth (client_id: 1071006060591-...apps.googleusercontent.com); " - "token from ~/.gemini/oauth_creds.json. Antigravity's local gRPC LS (127.0.0.1:) " - "is its internal proxy – faigate uses the Google Generative Language API directly. " - "Run: faigate-auth google-antigravity or sign in to the Antigravity IDE." - ), - ), }