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 formatAPIError helper 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:

  1. Unit test – Mock the fetch global and verify sendMessageViaMyProvider constructs the correct headers and payload.
  2. Integration test – Start the development server, select "MyProvider" in the settings dropdown, and confirm requests hit https://api.myprovider.com/v1/chat.
  3. Error handling – Simulate HTTP 401 or 429 responses to ensure formatAPIError returns user-friendly messages.

Summary

  • Register endpoints in src/lib/openrouter.ts by extending the Provider type and PROVIDER_ENDPOINTS map.
  • Implement wrappers using the sendMessageVia naming convention, ensuring consistent error handling with formatAPIError.
  • Route requests by adding a case to the queryModel switch in api/lib/ultraplinian.ts.
  • Expose to UI by appending the provider to MODEL_PROVIDERS in src/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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →