# How to Integrate Custom Model Providers in G0DM0D3

> Learn to integrate custom model providers in G0DM0D3. Extend the Provider type implement a sendMessageVia wrapper and update the queryModel dispatcher for seamless integration.

- Repository: [pliny/G0DM0D3](https://github.com/elder-plinius/G0DM0D3)
- Tags: how-to-guide
- Published: 2026-07-19

---

**Integrating custom model providers in G0DM0D3 requires extending the `Provider` type in [`src/lib/openrouter.ts`](https://github.com/elder-plinius/G0DM0D3/blob/main/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`](https://github.com/elder-plinius/G0DM0D3/blob/main/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`](https://github.com/elder-plinius/G0DM0D3/blob/main/src/lib/openrouter.ts) and update the type definitions:

```typescript
// 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`](https://github.com/elder-plinius/G0DM0D3/blob/main/src/lib/openrouter.ts).

```typescript
// 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`](https://github.com/elder-plinius/G0DM0D3/blob/main/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:

```typescript
// 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`](https://github.com/elder-plinius/G0DM0D3/blob/main/SettingsModal.tsx)).

Update [`src/store/index.ts`](https://github.com/elder-plinius/G0DM0D3/blob/main/src/store/index.ts) to include the new entry:

```typescript
// 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:

```typescript
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`](https://github.com/elder-plinius/G0DM0D3/blob/main/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`](https://github.com/elder-plinius/G0DM0D3/blob/main/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`](https://github.com/elder-plinius/G0DM0D3/blob/main/api/lib/ultraplinian.ts).
- **Expose to UI** by appending the provider to `MODEL_PROVIDERS` in [`src/store/index.ts`](https://github.com/elder-plinius/G0DM0D3/blob/main/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`](https://github.com/elder-plinius/G0DM0D3/blob/main/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`](https://github.com/elder-plinius/G0DM0D3/blob/main/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`](https://github.com/elder-plinius/G0DM0D3/blob/main/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`](https://github.com/elder-plinius/G0DM0D3/blob/main/src/store/index.ts). This array drives the model selector components, including the settings modal where users choose their backend provider.