From 95d46d2a321aacf24b585a10dafd27cb224dc691 Mon Sep 17 00:00:00 2001 From: Nestor Ale Date: Mon, 6 Jul 2026 13:53:13 -0300 Subject: [PATCH 1/3] fix: sync validNames array with ProviderName type, handle provider-prefixed model IDs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix 1 (providers.ts): validNames array was missing 5 provider types (openaiCompat, mimo, mimoTokenPlan, chatgptWeb, githubCopilot) that exist in the ProviderName union type. This caused 'Unknown provider' errors when toggling/disabling any of these providers from the web UI. Fix 2 (provider-models.ts): isOpenAIChatModel() rejected model IDs with provider prefixes (e.g. OpenRouter's 'openai/gpt-4o-mini') because it checked the full ID for the 'gpt-' prefix. Split on '/' and check the last segment instead — backward-compatible with direct API model names. --- src/utils/provider-models.ts | 25 ++++++++++++++----------- src/web/api/providers.ts | 2 +- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/utils/provider-models.ts b/src/utils/provider-models.ts index 3a50d38f..5f57ba77 100644 --- a/src/utils/provider-models.ts +++ b/src/utils/provider-models.ts @@ -165,22 +165,25 @@ function limitModels(models: string[]): string[] { function isOpenAIChatModel(id: string): boolean { const lower = id.toLowerCase(); + // Handle provider-prefixed model IDs (e.g. OpenRouter's "openai/gpt-4o-mini") + const parts = lower.split('/'); + const modelName = parts[parts.length - 1]; if ( - lower.includes('image') - || lower.includes('audio') - || lower.includes('tts') - || lower.includes('transcribe') - || lower.includes('embedding') - || lower.includes('moderation') - || lower.includes('realtime') - || lower.includes('whisper') - || lower.includes('search') - || lower.includes('computer') + modelName.includes('image') + || modelName.includes('audio') + || modelName.includes('tts') + || modelName.includes('transcribe') + || modelName.includes('embedding') + || modelName.includes('moderation') + || modelName.includes('realtime') + || modelName.includes('whisper') + || modelName.includes('search') + || modelName.includes('computer') ) { return false; } - return lower.startsWith('gpt-') || /^o\d/.test(lower); + return modelName.startsWith('gpt-') || /^o\d/.test(modelName); } function chooseRecommendedModel( diff --git a/src/web/api/providers.ts b/src/web/api/providers.ts index 8a9d3006..d2dafa72 100644 --- a/src/web/api/providers.ts +++ b/src/web/api/providers.ts @@ -26,7 +26,7 @@ providers.post('/api/providers/:name', async (c) => { const body = await c.req.json(); const config = loadConfig(); - const validNames: ProviderName[] = ['openai', 'anthropic', 'deepseek', 'grok', 'ollamaCloud', 'ollamaLocal']; + const validNames: ProviderName[] = ['openai', 'anthropic', 'deepseek', 'grok', 'ollamaCloud', 'ollamaLocal', 'openaiCompat', 'mimo', 'mimoTokenPlan', 'chatgptWeb', 'githubCopilot']; if (!validNames.includes(providerName)) { return c.json({ error: 'Unknown provider' }, 400); } From c5698895d63d0d34922e06b77dfecbcf2083cdb8 Mon Sep 17 00:00:00 2001 From: Nestor Ale Date: Mon, 6 Jul 2026 15:12:54 -0300 Subject: [PATCH 2/3] fix: force Chat Completions API for all OpenAI-compatible providers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The openai provider (and others falling through to the else branch in ProviderRegistry) defaulted to OpenAI Responses API via createOpenAI(model) instead of Chat Completions API via createOpenAI.chat(model). OpenRouter and most proxy services only support Chat Completions endpoint, causing HTTP 400 'Invalid Responses API request' on every call — agent retries endlessly burning tokens. Changed the else branch to pass { useChatApi: true }, matching the existing openaiCompat and deepseek providers. --- src/providers/registry.ts | 2 +- src/utils/provider-models.ts | 25 ++++++++++++------------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/providers/registry.ts b/src/providers/registry.ts index 2de70f09..dfe4049e 100644 --- a/src/providers/registry.ts +++ b/src/providers/registry.ts @@ -32,7 +32,7 @@ async function createProvider(pc: ProviderConfig): Promise { return new GitHubCopilotProvider(pc); } else { const { OpenAICompatProvider } = await import('./openai-compat.js'); - return new OpenAICompatProvider(pc); + return new OpenAICompatProvider(pc, { useChatApi: true }); } } diff --git a/src/utils/provider-models.ts b/src/utils/provider-models.ts index 5f57ba77..a076fbbd 100644 --- a/src/utils/provider-models.ts +++ b/src/utils/provider-models.ts @@ -165,25 +165,24 @@ function limitModels(models: string[]): string[] { function isOpenAIChatModel(id: string): boolean { const lower = id.toLowerCase(); - // Handle provider-prefixed model IDs (e.g. OpenRouter's "openai/gpt-4o-mini") - const parts = lower.split('/'); + const parts = lower.split("/"); const modelName = parts[parts.length - 1]; if ( - modelName.includes('image') - || modelName.includes('audio') - || modelName.includes('tts') - || modelName.includes('transcribe') - || modelName.includes('embedding') - || modelName.includes('moderation') - || modelName.includes('realtime') - || modelName.includes('whisper') - || modelName.includes('search') - || modelName.includes('computer') + modelName.includes("image") + || modelName.includes("audio") + || modelName.includes("tts") + || modelName.includes("transcribe") + || modelName.includes("embedding") + || modelName.includes("moderation") + || modelName.includes("realtime") + || modelName.includes("whisper") + || modelName.includes("search") + || modelName.includes("computer") ) { return false; } - return modelName.startsWith('gpt-') || /^o\d/.test(modelName); + return modelName.startsWith("gpt-") || /^o\d/.test(modelName); } function chooseRecommendedModel( From 8a9f95c25eb8e1c3d44ac337e7249a954b7af47e Mon Sep 17 00:00:00 2001 From: Nestor Ale Date: Mon, 6 Jul 2026 15:14:39 -0300 Subject: [PATCH 3/3] fix: default web channel to Allow All permissions The web UI lacks a permissions mode toggle in Settings, so users cannot switch from 'Ask Me' to 'Allow All' mode. Permission prompts render as raw JSON in the chat stream instead of interactive dialogs, blocking all tool execution. Change bypassPermissions default from false to true so the web channel starts in Allow All mode. Users who want Ask Me can still toggle it programmatically via PUT /api/chat/settings. --- src/channels/web.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/channels/web.ts b/src/channels/web.ts index 8997d7db..285f5dc4 100644 --- a/src/channels/web.ts +++ b/src/channels/web.ts @@ -42,7 +42,7 @@ export class WebChannel extends BaseChannel { private pendingPermModes: Map = new Map(); private agentName: string; private stepCounter: Map = new Map(); - private bypassPermissions = false; + private bypassPermissions = true; private restrictUser = false; constructor(agentName: string) {