> ## Documentation Index
> Fetch the complete documentation index at: https://docs.standardagentbuilder.com/llms.txt
> Use this file to discover all available pages before exploring further.

# defineProvider

> Define a provider that extends another provider with custom config and method overrides

## Overview

`defineProvider` creates a named provider factory from a base provider. Use it when an API is compatible with an existing provider package but needs its own endpoint, key, icon, model list, pricing, or request behavior.

Provider files live in `agents/providers/` and must default-export `defineProvider(...)`.

```typescript agents/providers/darkbloom.ts theme={null}
import { defineProvider, providerEnv } from '@standardagents/spec';
import { openai } from '@standardagents/openai';

export default defineProvider({
  name: 'darkbloom',
  label: 'Darkbloom',
  baseProvider: openai,
  config: {
    apiKey: providerEnv('DARKBLOOM_API_KEY', { valueType: 'secret' }),
    baseUrl: providerEnv('DARKBLOOM_BASE_URL', {
      valueType: 'url',
      default: 'https://api.darkbloom.dev/v1',
    }),
  },
});
```

Models import the local provider as a default import:

```typescript agents/models/darkbloom_chat.ts theme={null}
import { defineModel } from '@standardagents/spec';
import darkbloom from '../providers/darkbloom';

export default defineModel({
  name: 'darkbloom_chat',
  provider: darkbloom,
  model: 'darkbloom-chat',
});
```

## Type Definition

```typescript theme={null}
function defineProvider<N extends string, Base extends ProviderFactoryWithOptions>(
  definition: ProviderDefinition<N, Base>
): ProviderFactoryWithOptions;

interface ProviderDefinition<N extends string = string> {
  name: N;
  label?: string;
  baseProvider: ProviderFactoryWithOptions;
  config?: Record<string, ProviderConfigValueSource>;
  overrides?: ProviderMethodOverrides;
}
```

## Configuration

Provider config describes values passed to the base provider factory. It is for connection-level values such as keys, endpoints, regions, account IDs, and timeouts. Per-model request options still belong in `providerOptions` on `defineModel`.

```typescript theme={null}
config: {
  apiKey: providerEnv('DARKBLOOM_API_KEY', {
    valueType: 'secret',
    description: 'Darkbloom API key',
  }),
  baseUrl: providerEnv('DARKBLOOM_BASE_URL', {
    valueType: 'url',
    default: 'https://api.darkbloom.dev/v1',
  }),
}
```

### Value Sources

| Helper                       | Description                                                                                                              |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `providerEnv(name, options)` | Reads a value from an environment variable, with optional `default`, `required`, `valueType`, and `description` metadata |
| `providerValue(value)`       | Uses a literal constant value                                                                                            |
| `providerConst(value)`       | Alias for `providerValue(value)`                                                                                         |

If a sub-provider does not override a required base provider slot, the base provider's `defaultEnv` is used. For example, an OpenAI-based provider that only overrides `baseUrl` still requires `OPENAI_API_KEY`.

## Overrides

The `overrides` object can replace or compose with provider behavior. Each method receives a context object and `next()`, where `next()` calls the base provider's implementation.

```typescript theme={null}
export default defineProvider({
  name: 'darkbloom',
  label: 'Darkbloom',
  baseProvider: openai,
  config: {
    apiKey: providerEnv('DARKBLOOM_API_KEY', { valueType: 'secret' }),
    baseUrl: providerValue('https://api.darkbloom.dev/v1'),
  },
  overrides: {
    getIcon() {
      return '/icons/darkbloom.svg';
    },
    async getModels(_context, next) {
      const models = await next();
      return [
        { id: 'darkbloom-chat', name: 'Darkbloom Chat' },
        ...models,
      ];
    },
  },
});
```

Call `next()` when the override should extend the base provider. Omit `next()` when it should fully replace the base behavior.

Overrideable methods include `generate`, `stream`, `supportsModel`, `getModels`, `getModelsPage`, `getModelCapabilities`, `getTools`, `getIcon`, `inspectRequest`, and `getResponseMetadata`.

<Note>
  `supportsModel` and `getIcon` are synchronous because the provider interface expects synchronous results for those methods. Use `getModels` or `getModelsPage` for asynchronous discovery.
</Note>

## Model Discovery Metadata

`getModels` and `getModelsPage` return `ProviderModelInfo` entries. Providers
may include optional pricing metadata when their catalog exposes it:

```typescript theme={null}
{
  id: 'vendor/model-id',
  name: 'Model Display Name',
  inputPrice: 1.4,
  outputPrice: 4.4,
}
```

`inputPrice`, `outputPrice`, and `cachedPrice` use the same units as
`defineModel`: USD per 1M tokens. When present, AgentBuilder can copy those
values into generated model definitions so request logs can calculate cost from
token usage when the upstream response does not report a dollar cost.
