How to Integrate Custom Model Providers in G0DM0D3
Integrating custom model providers in G0DM0D3 requires extending the Provider type in src/lib/openrouter.ts, implementing a sendMessageVia wrapper for your API, and wiring the new case into the queryModel dispatcher in api/lib/ultraplinian.ts.
G0DM0D3 uses a provider-agnostic architecture that routes LLM requests through a unified abstraction layer. To integrate custom model providers, you must map the new endpoint, handle provider-specific request formatting, and expose the option to the frontend store. This guide walks through the exact source files and functions required to add any HTTP-compatible model backend.
Step 1: Define the Provider Endpoint
Register the new provider in the core networking library by extending the Provider union type and adding its API endpoint to the PROVIDER_ENDPOINTS map.
Open src/lib/openrouter.ts and update the type definitions:
// src/lib/openrouter.ts
export type Provider = 'openrouter' | 'venice' | 'myprovider';
const PROVIDER_ENDPOINTS: Record<Provider, string> = {
openrouter: 'https://openrouter.ai/api/v1/chat/completions',
venice: 'https://api.venice.ai/api/v1/chat/completions',
myprovider: 'https://api.myprovider.com/v1/chat', // New provider endpoint
};
The PROVIDER_ENDPOINTS map is consumed by generic streaming functions like streamConsortium and streamUltraplinian. Adding the URL here enables automatic request routing without modifying the underlying fetch logic.
Step 2: Implement the Message Wrapper Function
Create a wrapper function that constructs the request body and parses the response, following the pattern established by sendMessageViaVenice in src/lib/openrouter.ts.
// src/lib/openrouter.ts
interface MyProviderMessageOptions {
messages: Message[];
model: string;
apiKey: string;
signal?: AbortSignal;
temperature?: number;
maxTokens?: number;
top_p?: number;
frequency_penalty?: number;
}
export async function sendMessageViaMyProvider({
messages,
model,
apiKey,
signal,
temperature = 0.7,
maxTokens = 4096,
top_p,
frequency_penalty,
}: MyProviderMessageOptions): Promise<string> {
if (!apiKey) {
throw new Error(
'No MyProvider API key set. Go to Settings → API Key and enter your key from the provider.'
);
}
const body: Record<string, unknown> = {
model,
messages,
temperature,
max_tokens: maxTokens,
};
if (top_p !== undefined) body.top_p = top_p;
if (frequency_penalty !== undefined) body.frequency_penalty = frequency_penalty;
const response = await fetch(PROVIDER_ENDPOINTS['myprovider'], {
method: 'POST',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
signal,
});
if (!response.ok) {
const err = await response.json().catch(() => ({}));
throw new Error(formatAPIError(response.status, err.error?.message));
}
const data = (await response.json()) as OpenRouterResponse;
if (!data.choices?.length) throw new Error('No response from MyProvider model');
return data.choices[0].message.content;
}
Key implementation details:
- Error handling leverages the shared
formatAPIErrorhelper to maintain consistent UI error messages. - AbortSignal support ensures requests can be cancelled by the frontend.
- Return type remains a plain
string, matching the contract used by existing provider wrappers.
Step 3: Route Requests in the API Layer
Wire the new provider into the server-side orchestration by extending the dispatcher in api/lib/ultraplinian.ts. The queryModel function routes requests based on the provider field.
Locate the switch statement within queryModel and add your new case:
// api/lib/ultraplinian.ts
switch (entry.provider) {
case 'openrouter':
response = await fetch(PROVIDER_ENDPOINTS['openrouter'], /* ... */);
break;
case 'venice':
response = await fetch(PROVIDER_ENDPOINTS['venice'], /* ... */);
break;
case 'myprovider': // New routing case
response = await fetch(PROVIDER_ENDPOINTS['myprovider'], /* ... */);
break;
}
This ensures that when the frontend sends a payload with provider: 'myprovider', the system dispatches to your custom endpoint.
Step 4: Expose the Provider to the Frontend
Add the provider to the frontend store so it appears in the model selector UI (typically consumed by SettingsModal.tsx).
Update src/store/index.ts to include the new entry:
// src/store/index.ts
export const MODEL_PROVIDERS = [
{ id: 'openrouter', name: 'OpenRouter' },
{ id: 'venice', name: 'Venice' },
{ id: 'myprovider', name: 'MyProvider' },
];
The UI automatically propagates the selected provider string to the API layer, which then routes according to the switch case defined in Step 3.
Handling Provider-Specific Options
If your custom provider supports unique flags (e.g., a "no-log" mode), inject these into a provider object within the request body:
const providerOptions: Record<string, unknown> = {};
if (noLog) {
providerOptions['no_log'] = true;
}
if (Object.keys(providerOptions).length) {
body.provider = providerOptions;
}
This pattern, visible in src/lib/openrouter.ts around the providerOptions block, keeps provider-specific extensions isolated from the generic message structure.
Testing the Integration
Validate your custom model provider integration with the following checks:
- Unit test – Mock the
fetchglobal and verifysendMessageViaMyProviderconstructs the correct headers and payload. - Integration test – Start the development server, select "MyProvider" in the settings dropdown, and confirm requests hit
https://api.myprovider.com/v1/chat. - Error handling – Simulate HTTP 401 or 429 responses to ensure
formatAPIErrorreturns user-friendly messages.
Summary
- Register endpoints in
src/lib/openrouter.tsby extending theProvidertype andPROVIDER_ENDPOINTSmap. - Implement wrappers using the
sendMessageVianaming convention, ensuring consistent error handling withformatAPIError. - Route requests by adding a case to the
queryModelswitch inapi/lib/ultraplinian.ts. - Expose to UI by appending the provider to
MODEL_PROVIDERSinsrc/store/index.ts.
Frequently Asked Questions
What file contains the provider endpoint configuration in G0DM0D3?
The PROVIDER_ENDPOINTS map and Provider union type are defined in src/lib/openrouter.ts. This file serves as the central registry for all supported model provider URLs.
How does G0DM0D3 dispatch requests to different providers?
The queryModel function in api/lib/ultraplinian.ts uses a switch statement on the provider field to determine which endpoint URL to call. Each case corresponds to an entry in the PROVIDER_ENDPOINTS record.
Can I integrate a provider that uses non-OpenAI request formats?
Yes. While the sendMessageVia wrappers in src/lib/openrouter.ts follow OpenAI-compatible patterns, you can customize the request body construction within your wrapper function. Transform the standard messages array into your provider's required format before the fetch call.
Where do I add a new provider so it appears in the settings dropdown?
Add the provider object to the MODEL_PROVIDERS array exported from src/store/index.ts. This array drives the model selector components, including the settings modal where users choose their backend provider.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →