diff --git a/routes/model_routes.py b/routes/model_routes.py index 07d674e81..29188a72d 100644 --- a/routes/model_routes.py +++ b/routes/model_routes.py @@ -285,6 +285,8 @@ _HOST_TO_CURATED = ( ("x.ai", "xai"), ("openrouter.ai", "openrouter"), ("ollama.com", "ollama"), + ("opencode.ai/zen/go", "opencode-go"), + ("opencode.ai/zen", "opencode-zen"), ) diff --git a/routes/webhook_routes.py b/routes/webhook_routes.py index d1372bea8..5cf739fda 100644 --- a/routes/webhook_routes.py +++ b/routes/webhook_routes.py @@ -194,6 +194,8 @@ def setup_webhook_routes( "together": "https://api.together.xyz/v1", "openrouter": "https://openrouter.ai/api/v1", "ollama": "https://ollama.com/api", + "opencode-zen": "https://opencode.ai/zen/v1", + "opencode-go": "https://opencode.ai/zen/go/v1", "fireworks": "https://api.fireworks.ai/inference/v1", "venice": "https://api.venice.ai/api/v1", } diff --git a/src/llm_core.py b/src/llm_core.py index 9123a1b4a..691ed30c9 100644 --- a/src/llm_core.py +++ b/src/llm_core.py @@ -414,6 +414,10 @@ def _detect_provider(url: str) -> str: return "ollama" if _host_match(url, "anthropic.com"): return "anthropic" + if _host_match(url, "opencode.ai/zen/go"): + return "opencode-go" + if _host_match(url, "opencode.ai/zen"): + return "opencode-zen" if _host_match(url, "openrouter.ai"): return "openrouter" if _host_match(url, "groq.com"): @@ -451,6 +455,8 @@ def _provider_label(url: str) -> str: if _host_match(url, "x.ai"): return "xAI" if _host_match(url, "openai.com"): return "OpenAI" if _host_match(url, "openrouter.ai"): return "OpenRouter" + if _host_match(url, "opencode.ai/zen/go"): return "OpenCode Go" + if _host_match(url, "opencode.ai/zen"): return "OpenCode Zen" if _host_match(url, "groq.com"): return "Groq" from src.copilot import is_copilot_base if is_copilot_base(url): return "GitHub Copilot" diff --git a/static/index.html b/static/index.html index 98a5784e1..9aa365eb4 100644 --- a/static/index.html +++ b/static/index.html @@ -2117,6 +2117,8 @@ + +
diff --git a/static/js/admin.js b/static/js/admin.js index b4a1c7399..06d322432 100644 --- a/static/js/admin.js +++ b/static/js/admin.js @@ -773,7 +773,7 @@ function initEndpointForm() { } } catch(e) {} // Ensure /v1 suffix for bare host:port URLs (not cloud providers) - if (!u.includes('api.') && !u.includes('openrouter') && !u.includes('ollama.com') && !u.endsWith('/v1')) { + if (!u.includes('api.') && !u.includes('openrouter') && !u.includes('opencode.ai') && !u.includes('ollama.com') && !u.endsWith('/v1')) { try { const parsed = new URL(u); if (!parsed.pathname || parsed.pathname === '/') { diff --git a/static/js/providers.js b/static/js/providers.js index ee619cab5..327e0bbff 100644 --- a/static/js/providers.js +++ b/static/js/providers.js @@ -11,6 +11,10 @@ const _PROVIDERS = [ [/openai|gpt-|^o[13]-|chatgpt|dall-e/i, ''], + // OpenCode (Zen / Go) — official brand mark + [/opencode/i, + ''], + // OpenRouter [/openrouter|open router/i, ''], diff --git a/static/js/slashCommands.js b/static/js/slashCommands.js index 1a11454bf..d1ed3e4ff 100644 --- a/static/js/slashCommands.js +++ b/static/js/slashCommands.js @@ -54,8 +54,10 @@ const SETUP_PROVIDER_URLS = { groq: { name: 'Groq', url: 'https://api.groq.com/openai/v1' }, gemini: { name: 'Gemini', url: 'https://generativelanguage.googleapis.com/v1beta/openai' }, google: { name: 'Gemini', url: 'https://generativelanguage.googleapis.com/v1beta/openai' }, + 'opencode-zen': { name: 'OpenCode Zen', url: 'https://opencode.ai/zen/v1' }, + 'opencode-go': { name: 'OpenCode Go', url: 'https://opencode.ai/zen/go/v1' }, }; -const SETUP_PROVIDER_NAMES = ['deepseek', 'openai', 'openrouter', 'ollama', 'xai', 'anthropic', 'groq', 'gemini']; +const SETUP_PROVIDER_NAMES = ['deepseek', 'openai', 'openrouter', 'ollama', 'xai', 'anthropic', 'groq', 'gemini', 'opencode-zen', 'opencode-go']; const SETUP_PROVIDER_HINT = SETUP_PROVIDER_NAMES.slice(0, -1).join(', ') + ', or ' + SETUP_PROVIDER_NAMES[SETUP_PROVIDER_NAMES.length - 1]; const SETUP_LOCAL_ICON = ''; const SETUP_API_ICON = '';