# defineModel

Define LLM model configurations with typed provider options

## Overview

`defineModel` creates a model configuration that can be referenced by prompts and agents. Models use provider factory functions imported from provider packages for typed configuration.

```typescript
import { defineModel } from '@standardagents/spec';
import { openrouter } from '@standardagents/openrouter';

export default defineModel({
  name: 'heavy-thinking',
  provider: openrouter,
  model: 'moonshotai/kimi-k3',
  inputPrice: 3,
  outputPrice: 15,
});
```

The priced open-weight examples use representative rates from the maintained model guide.
OpenRouter supplies live pricing when explicit prices are omitted.
Check the [OpenRouter catalog](https://openrouter.ai/api/v1/models) before setting an override.

## Type Definition

```typescript
import type { ProviderFactoryWithOptions, ModelCapabilities } from '@standardagents/spec';
import type { ZodTypeAny, z } from 'zod';

function defineModel<
  N extends string,
  P extends ProviderFactoryWithOptions<ZodTypeAny>
>(options: ModelDefinition<N, P>): ModelDefinition<N, P>;

interface ModelDefinition<
  N extends string = string,
  P extends ProviderFactoryWithOptions<ZodTypeAny> = ProviderFactoryWithOptions<ZodTypeAny>
> {
  name: N;
  provider: P;
  model: string;
  inputPrice?: number;
  outputPrice?: number;
  cachedPrice?: number;
  fallbacks?: string[];
  includedProviders?: string[];
  capabilities?: ModelCapabilities;
  providerOptions?: InferProviderOptions<P>;
  providerTools?: string[];
}

interface ModelCapabilities {
  reasoningLevels?: Record<number, string | null>;
  supportsImages?: boolean;
  supportsToolCalls?: boolean;
  supportsStreaming?: boolean;
  supportsJsonMode?: boolean;
  maxContextTokens?: number;
  maxOutputTokens?: number;
}

// Automatically infers the correct type from the provider's schema
type InferProviderOptions<P> = P extends ProviderFactoryWithOptions<infer S>
  ? S extends ZodTypeAny ? z.input<S> : Record<string, unknown>
  : Record<string, unknown>;
```

## Parameters

- name (string), required

  Unique identifier for this model configuration. Used to reference the model in prompts and agents.

  **Best Practice:** Name models by use case, not by model ID:

  - `heavy-thinking` - Complex reasoning tasks
  - `fast-response` - Quick, simple responses
  - `code-generation` - Code-focused tasks

* provider (ProviderFactory), required

  Provider factory function imported from a provider package.

  ```typescript
  import { anthropic } from '@standardagents/anthropic';
  import { cerebras } from '@standardagents/cerebras';
  import { cloudflare } from '@standardagents/cloudflare';
  import { deepinfra } from '@standardagents/deepinfra';
  import { google } from '@standardagents/google';
  import { groq } from '@standardagents/groq';
  import { novita } from '@standardagents/novita';
  import { openai } from '@standardagents/openai';
  import { openrouter } from '@standardagents/openrouter';
  import { xai } from '@standardagents/xai';

  provider: anthropic    // Anthropic Claude via @anthropic-ai/sdk
  provider: cerebras     // Cerebras Chat Completions API
  provider: cloudflare   // Cloudflare Workers AI OpenAI-compatible API
  provider: deepinfra    // DeepInfra OpenAI-compatible Chat Completions API
  provider: google       // Google Gemini / Imagen via @google/genai
  provider: groq         // Groq chat completions via groq-sdk
  provider: novita       // Novita OpenAI-compatible Chat Completions API
  provider: openai       // Direct OpenAI API
  provider: openrouter   // Multi-provider gateway
  provider: xai          // xAI Grok chat / image models
  ```

  > **Note:**
  >
  > The provider determines which `providerOptions` are available. TypeScript provides autocompletion based on the provider's schema.

  User-defined providers are also provider factories. Put them in `agents/providers/` with `defineProvider`, then import them as a default import:

  ```typescript
  import darkbloom from '../providers/darkbloom';

  provider: darkbloom
  ```

  See [defineProvider](/docs/api-reference/define/provider) for custom endpoints, API keys, icons, and model discovery overrides.

- model (string), required

  The specific model identifier sent to the provider API.

  **OpenAI examples:**

  - `gpt-6.1-sol`
  - `gpt-6-luna`
  - `gpt-6-astra`

  **Cerebras examples:**

  - `qwen-3.8-27b`
  - `gpt-oss-120b`

  **Cloudflare Workers AI examples:**

  - `@cf/google/gemma-4-26b-a4b-it`
  - `@cf/openai/gpt-oss-120b`
  - `@cf/qwen/qwen3-30b-a3b-fp8`

  **OpenRouter format:** `provider/model-name`

  - `google/gemma-4-31b-it`
  - `nvidia/nemotron-3-ultra-550b-a55b`
  - `meta-llama/llama-3.3-70b-instruct`

  **Google examples:**

  - `gemini-3.1-pro-preview`
  - `gemini-3.8-flash`
  - `imagen-4.0-generate-001`

  **Groq examples:**

  - `llama-3.1-8b-instant`
  - `openai/gpt-oss-120b`
  - `qwen/qwen3-32b`

  **Novita AI examples:**

  - `zai-org/glm-5.2`
  - `deepseek/deepseek-v3.2`
  - `moonshotai/kimi-k2.7-code`

  **xAI examples:**

  - `grok-4-0709`
  - `grok-code-fast-1`
  - `grok-imagine-image`

* inputPrice (number)

  Price per 1 million input tokens in USD.
  Explicit input and output prices take precedence over the runtime's provider pricing tables.
  OpenAI and Cerebras can use those tables when explicit prices are omitted.
  OpenRouter responses can supply cost from the provider API.

- outputPrice (number)

  Price per 1 million output tokens in USD. Set this with `inputPrice` to override runtime pricing.

* cachedPrice (number)

  Price per 1 million cached tokens in USD (if provider supports caching).

- fallbacks (string\[])

  Array of model names to try if the primary model fails. Must reference other models defined with `defineModel`.

  Fallbacks are tried for:

  - Network errors
  - Rate limits (429)
  - Server errors (5xx)
  - Authentication errors (401)

* includedProviders (string\[])

  **OpenRouter only.** Providers to try first for this model, in list order. The list is sent as OpenRouter's `provider.order`, so other providers remain fallbacks unless `providerOptions.provider.allow_fallbacks` is `false`. An explicit `providerOptions.provider.order` takes precedence, and other `provider` routing options are kept. To use only these providers, set `providerOptions.provider.only`.

  ```typescript
  includedProviders: ['deepinfra']  // Prefer DeepInfra
  ```

- capabilities (ModelCapabilities)

  Model capability flags for framework behavior. See [Capabilities](#capabilities) section.

* providerOptions (InferProviderOptions\<P>)

  Provider-specific options. Type is inferred from the provider's schema.
  Native effort values are valid here. A prompt's `reasoning.level` replaces a native effort value. Other options remain. Without a level, options apply as provided.

  See [Provider Options](#provider-options) section for available options per provider.

- providerTools (string\[])

  Enable built-in provider tools by provider-defined name. Available tools depend on the provider and model.

  ```typescript
  providerTools: ['web_search', 'code_interpreter']
  ```

  Provider packages translate these names into their native request format and
  execute them through the provider API. Standard Agents Builder discovers and selects the
  tools, but does not execute provider tools locally.

## Provider Options

### OpenAI

```typescript
import { openai } from '@standardagents/openai';

defineModel({
  name: 'gpt-6.1-sol',
  provider: openai,
  model: 'gpt-6.1-sol',
  providerOptions: {
    service_tier: 'auto', // Also accepts 'default' or 'flex'.
    user: 'user-123',
    seed: 42,
    frequency_penalty: 0.5,  // -2.0 to 2.0
    presence_penalty: 0.5,   // -2.0 to 2.0
    logprobs: true,
    top_logprobs: 5,         // 0-20
    store: true,
    metadata: { key: 'value' },
  },
});
```

### OpenRouter

```typescript
import { openrouter } from '@standardagents/openrouter';

defineModel({
  name: 'conversational',
  provider: openrouter,
  model: 'google/gemma-4-31b-it',
  providerTools: ['web_search', 'web_fetch', 'datetime', 'image_generation'],
  providerOptions: {
    provider: {
      order: ['deepinfra', 'novita'],
      allow_fallbacks: true,
      require_parameters: true,
      data_collection: 'deny', // Also accepts 'allow'.
      zdr: true,
      only: ['deepinfra'],
      ignore: ['chutes'],
      sort: 'price', // Also accepts 'throughput' or 'latency'.
      max_price: {
        prompt: 1,
        completion: 5,
        request: 0.01,
        image: 0.05,
      },
      quantizations: ['fp8', 'fp4'],
      preferred_min_throughput: 100,
      preferred_max_latency: 1,
    },
    serverTools: {
      web_search: { max_results: 5 },
      web_fetch: { max_content_tokens: 50000 },
      datetime: { timezone: 'America/New_York' },
      image_generation: { quality: 'high' },
    },
  },
});
```

### Cerebras

```typescript
import { cerebras } from '@standardagents/cerebras';

defineModel({
  name: 'cerebras-fast',
  provider: cerebras,
  model: 'qwen-3.8-27b',
  // Prices change. Check https://www.cerebras.ai/pricing
  inputPrice: 0.99,
  outputPrice: 1.49,
  providerOptions: {
    service_tier: 'default',
    reasoning_effort: 'high',
    clear_thinking: false,
    user: 'user-123',
    seed: 42,
  },
});
```

### Cloudflare Workers AI

```typescript
import { cloudflare } from '@standardagents/cloudflare';

defineModel({
  name: 'workers-fast',
  provider: cloudflare,
  model: '@cf/google/gemma-4-26b-a4b-it',
  // Prices change. Check https://developers.cloudflare.com/workers-ai/platform/pricing/
  inputPrice: 0.1,
  outputPrice: 0.3,
  providerOptions: {
    seed: 42,
    user: 'user-123',
  },
});
```

## Capabilities

```typescript
capabilities: {
  // Reasoning support (0-100 scale → model values)
  reasoningLevels: {
    0: null,      // No reasoning
    33: 'low',    // Low effort
    66: 'medium', // Medium effort
    100: 'high',  // High effort
  },

  // Feature support
  supportsImages: true,      // Can process image inputs
  supportsToolCalls: true,   // Supports function calling
  supportsStreaming: true,   // Supports streaming responses
  supportsJsonMode: true,    // Supports structured JSON output

  // Token limits
  maxContextTokens: 1050000,  // Max context window
  maxOutputTokens: 128000,    // Max output tokens
}
```

## Return Value

Returns the same `ModelDefinition` object passed in, enabling the build system to register it.

## Examples

### Open-weight reasoning model

```typescript
import { defineModel } from '@standardagents/spec';
import { openrouter } from '@standardagents/openrouter';

export default defineModel({
  name: 'heavy-thinking',
  provider: openrouter,
  model: 'moonshotai/kimi-k3',
  inputPrice: 3,
  outputPrice: 15,
  capabilities: {
    supportsImages: true,
    supportsToolCalls: true,
    supportsJsonMode: true,
  },
});
```

### OpenRouter Model

```typescript
import { defineModel } from '@standardagents/spec';
import { openrouter } from '@standardagents/openrouter';

export default defineModel({
  name: 'conversational',
  provider: openrouter,
  model: 'google/gemma-4-31b-it',
  capabilities: {
    supportsImages: true,
    supportsToolCalls: true,
  },
  providerOptions: {
    provider: {
      zdr: true,
      only: ['deepinfra'],
    },
  },
});
```

> **Note:**
>
> OpenRouter models automatically fetch pricing from the OpenRouter API. You do not need to specify `inputPrice` or `outputPrice`.

### With Fallbacks

```typescript
import { defineModel } from '@standardagents/spec';
import { openrouter } from '@standardagents/openrouter';

// agents/models/fallback_cheap.ts
export default defineModel({
  name: 'fallback-cheap',
  provider: openrouter,
  model: 'nvidia/nemotron-3-super-120b-a12b',
  inputPrice: 0.1,
  outputPrice: 0.5,
});

```

```typescript agents/models/primary.ts
import { defineModel } from '@standardagents/spec';
import { openrouter } from '@standardagents/openrouter';

export default defineModel({
  name: 'primary',
  provider: openrouter,
  model: 'nvidia/nemotron-3-ultra-550b-a55b',
  fallbacks: ['fallback-cheap'],
  inputPrice: 0.5,
  outputPrice: 2.5,
});
```

### With Provider Tools

```typescript
import { defineModel } from '@standardagents/spec';
import { openai } from '@standardagents/openai';

export default defineModel({
  name: 'gpt-6.1-sol-with-tools',
  provider: openai,
  model: 'gpt-6.1-sol',
  // Prices change. Check https://developers.openai.com/api/docs/pricing
  // Standard rates apply to prompts up to 272K tokens.
  inputPrice: 2,
  outputPrice: 10,
  providerTools: ['web_search', 'code_interpreter', 'file_search'],
});
```

### Reasoning Model

```typescript
import { defineModel } from '@standardagents/spec';
import { openrouter } from '@standardagents/openrouter';

export default defineModel({
  name: 'deep-reasoning',
  provider: openrouter,
  model: 'nvidia/nemotron-3-ultra-550b-a55b',
  capabilities: {
    supportsToolCalls: true,
    reasoningLevels: {
      0: 'none',
      66: 'medium',
      100: 'high',
    },
  },
});
```

## File Location

Models are auto-discovered from `agents/models/`:

```
agents/
└── models/
    ├── heavy_thinking.ts
    ├── fast_response.ts
    └── budget.ts
```

**Requirements:**

- Use snake_case for file names
- One model per file
- Default export required

## Generated Types

The dev server populates `StandardAgentSpec.ModelRegistry`. `StandardAgentSpec.Models` resolves to its registered names:

```typescript
// Auto-generated
declare global {
  namespace StandardAgentSpec {
    interface ModelRegistry {
      'heavy-thinking': true;
      'fast-response': true;
      budget: true;
    }
  }
}
export {};
```

This enables type-safe model references in prompts.

## Runtime Validation

`defineModel` performs runtime validation:

- `name` is required and must be a non-empty string
- `provider` must be a valid ProviderFactory function
- `model` is required and must be a non-empty string
- Pricing values must be non-negative if provided
- `providerOptions` are validated against the provider's schema

```typescript
// This will throw at runtime:
defineModel({
  name: 'my-model',
  provider: 'openrouter',  // Error: Must be a ProviderFactory, not a string
  model: 'google/gemma-4-31b-it',
});
```
