feat: add custom/other OpenAI-compatible LLM providers

Allow Settings → Providers to define custom providers (id, name, base URL,
API key, models, headers) without code changes. Persist config via OpenCode
layers, store keys through auth.set, and keep web/VS Code parity.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
This commit is contained in:
Cursor Agent
2026-08-02 09:12:28 +00:00
co-authored by Serhii Dziupin
parent 5d24d6cb2a
commit be87e25c7d
25 changed files with 1980 additions and 33 deletions
+24
View File
@@ -1118,6 +1118,30 @@ const handleLocalApiRequest = async (input: RequestInfo | URL, url: URL, init: R
}
}
// Handle custom provider upsert: PUT /api/provider
if (pathname === '/api/provider' && method === 'PUT') {
try {
const body = await extractJsonBody(input, init, method);
const queryDirectory = url.searchParams.get('directory') || undefined;
const data = await sendBridgeMessage('api:provider:upsert', {
...(body && typeof body === 'object' ? body : {}),
directory: queryDirectory
?? (body && typeof body === 'object' && typeof body.directory === 'string' ? body.directory : undefined),
});
if (data && typeof data === 'object' && 'success' in data && (data as { success?: boolean }).success === false) {
const message = (data as { error?: string }).error || 'Failed to save provider config';
return new Response(JSON.stringify({ error: message }), { status: 400, headers: { 'Content-Type': 'application/json' } });
}
return new Response(JSON.stringify((data as { data?: unknown })?.data ?? data), {
status: 200,
headers: { 'Content-Type': 'application/json' },
});
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
return new Response(JSON.stringify({ error: message }), { status: 500, headers: { 'Content-Type': 'application/json' } });
}
}
return null;
};