OpenRouter Provider for Vercel AI SDK

repository·main·Indexed 20 days ago

https://github.com/openrouterteam/ai-sdk-provider

A provider for the Vercel AI SDK that enables access to over 300 large language models via the OpenRouter API. It supports text generation, embeddings, Anthropic prompt caching, fine-grained tool streaming, and response healing for structured outputs. The library provides detailed usage accounting, including costs and token tracking, and supports reasoning/thinking blocks through the OpenRouterChatLanguageModel implementation of the LanguageModelV4 interface.

Tokens
15.6K
Snippets
40
Records
54
Agent score
71%

What's inside @openrouter/ai-sdk-provider

  1. Use Anthropic Prompt Caching with OpenRouter

    main

    To use Anthropic-specific prompt caching, include providerOptions.openrouter.cacheControl within the message content objects. The provider automatically converts these to the correct format for OpenRouter.

    import { createOpenRouter } from '@openrouter/ai-sdk-provider';
    import { streamText } from 'ai';
    
    const openrouter = createOpenRouter({ apiKey: 'your-api-key' });
    const model = openrouter('anthropic/<supported-caching-model>');
    
    await streamText({
      model,
      messages: [
        { role: 'system', content: 'You are a helpful assistant.' },
        {
          role: 'user',
          content: [
            { type: 'text', text: 'Given the text body below:' },
            {
              type: 'text',
              text: `<LARGE BODY OF TEXT>`,
              providerOptions: {
                openrouter: {
                  cacheControl: { type: 'ephemeral' },
                },
              },
            },
            { type: 'text', text: 'List the speakers?' },
          ],
        },
      ],
    });
  2. Install legacy versions of the OpenRouter provider

    main

    If you are using older versions of the Vercel AI SDK, install the corresponding legacy version of the provider:

    • For AI SDK v6: Use version 2.9.1.
    • For AI SDK v5: Use version 1.5.4.
    # For AI SDK v6
    pnpm add @openrouter/ai-sdk-provider@2.9.1
    npm install @openrouter/ai-sdk-provider@2.9.1
    yarn add @openrouter/ai-sdk-provider@2.9.1
    
    # For AI SDK v5
    pnpm add @openrouter/ai-sdk-provider@1.5.4
    npm install @openrouter/ai-sdk-provider@1.5.4
    yarn add @openrouter/ai-sdk-provider@1.5.4
  3. Enable Anthropic Fine-grained Tool Streaming

    main

    Fine-grained tool streaming reduces latency for large schemas by streaming tool parameters without buffering. This is a beta feature and requires passing the anthropic-beta header. You can set this header globally in createOpenRouter or per-request in AI SDK functions.

    import { createOpenRouter } from '@openrouter/ai-sdk-provider';
    import { streamObject } from 'ai';
    
    // Global configuration
    const provider = createOpenRouter({
      apiKey: process.env.OPENROUTER_API_KEY,
      headers: {
        'anthropic-beta': 'fine-grained-tool-streaming-2025-05-14',
      },
    });
    
    const model = provider.chat('anthropic/claude-sonnet-4');
    
    const result = await streamObject({
      model,
      schema: yourLargeSchema,
      prompt: 'Generate a complex object...',
    });
    
    for await (const partialObject of result.partialObjectStream) {
      console.log(partialObject);
    }
  4. Enable and access OpenRouter usage accounting

    main

    You can track token usage and costs directly in your API responses by enabling usage accounting.

    1. Enable it by passing { usage: { include: true } } to the model configuration.
    2. Access standard usage via the AI SDK result.usage object (e.g., inputTokens, cacheReadTokens, reasoningTokens).
    3. Access provider-specific details via result.providerMetadata?.openrouter?.usage. This includes cost and totalTokens.

    This also supports BYOK (Bring Your Own Key) usage accounting, allowing you to track upstreamInferenceCost when using your own provider keys in OpenRouter.

    // Enable usage accounting
    const model = openrouter('openai/gpt-3.5-turbo', {
      usage: {
        include: true,
      },
    });
    
    // Access usage accounting data
    const result = await generateText({
      model,
      prompt: 'Hello, how are you today?',
    });
    
    // AI SDK v7 standard usage details
    console.log('Input tokens:', result.usage.inputTokens);
    console.log('Cached input tokens:', result.usage.inputTokenDetails.cacheReadTokens);
    console.log('Reasoning tokens:', result.usage.outputTokenDetails.reasoningTokens);
    
    // Provider-specific usage details (available in providerMetadata)
    if (result.providerMetadata?.openrouter?.usage) {
      console.log('Cost:', result.providerMetadata.openrouter.usage.cost);
      console.log(
        'Total Tokens:',
        result.providerMetadata.openrouter.usage.totalTokens,
      );
    }
    
    // For BYOK (Bring Your Own Key) scenarios:
    if (result.providerMetadata?.openrouter?.usage) {
      const costDetails = result.providerMetadata.openrouter.usage.costDetails;
      if (costDetails) {
        console.log('BYOK cost:', costDetails.upstreamInferenceCost);
      }
    }
  5. Pass extra body parameters to OpenRouter

    main

    There are three ways to pass additional parameters to the OpenRouter API via the extraBody property:

    1. Via providerOptions.openrouter: Pass options during the AI SDK function call (e.g., streamText).
    2. Via model settings: Pass options when creating the model instance using openrouter(modelId, { extraBody: ... }).
    3. Via the model factory: Pass options globally when initializing the provider with createOpenRouter({ extraBody: ... }).
    import { createOpenRouter } from '@openrouter/ai-sdk-provider';
    import { streamText } from 'ai';
    
    // 1. Via providerOptions
    const openrouter = createOpenRouter({ apiKey: 'your-api-key' });
    const model = openrouter('anthropic/claude-3.7-sonnet:thinking');
    await streamText({
      model,
      messages: [{ role: 'user', content: 'Hello' }],
      providerOptions: {
        openrouter: {
          reasoning: { max_tokens: 10 },
        },
      },
    });
    
    // 2. Via model settings
    const modelWithSettings = openrouter('anthropic/claude-3.7-sonnet:thinking', {
      extraBody: { reasoning: { max_tokens: 10 } },
    });
    
    // 3. Via model factory
    const globalOpenRouter = createOpenRouter({
      apiKey: 'your-api-key',
      extraBody: { reasoning: { max_tokens: 10 } },
    });
  6. Install the OpenRouter provider for Vercel AI SDK

    main

    Install the latest version of @openrouter/ai-sdk-provider for compatibility with AI SDK v7. This version requires Node.js 22 or newer and is ESM-only.

    # For pnpm
    pnpm add @openrouter/ai-sdk-provider
    
    # For npm
    npm install @openrouter/ai-sdk-provider
    
    # For yarn
    yarn add @openrouter/ai-sdk-provider
  7. Understand the tool call lifecycle in OpenRouter provider

    main

    The OpenRouter provider implements a specific lifecycle for tool calls to ensure compatibility with the Vercel AI SDK streaming protocols. A complete tool call lifecycle follows this sequence:

    1. tool-input-start: Emitted when the first arguments for a tool are received.
    2. tool-input-delta: Emitted for each chunk of arguments received.
    3. tool-input-end: Emitted when the JSON arguments are fully parsed and complete.
    4. tool-call: Emitted to signal the actual tool execution request. This event includes the toolCallId, toolName, and the final input.

    Important for Reasoning Models: If the model provides reasoning (thinking) blocks, the reasoning_details are attached to the providerMetadata of the tool-call event. To avoid duplication in parallel tool calls, these details are only attached to the first tool call in the sequence.

  8. Handle OpenRouter streaming parts

    main

    When streaming from OpenRouter, the doStream method emits a sequence of LanguageModelV4StreamPart events. The stream handles several specific types of data:

    • reasoning-start / reasoning-delta / reasoning-end: Emitted when the model is generating reasoning/thinking content.
    • text-start / text-delta: Emitted for the main text content.
    • tool-input-start / tool-input-delta / tool-input-end: Emitted for tool call arguments.
    • source: Emitted for URL citations.
    • response-metadata: Emitted for the response ID and model ID.
    • error: Emitted if a chunk fails to parse or contains an error.

    Note on Reasoning: The implementation ensures that reasoning-delta events are emitted before text-delta events. If reasoning arrives late, it is accumulated in metadata but does not trigger a new UI reasoning block to prevent duplication.

  9. Access OpenRouter reasoning details via providerMetadata

    main

    When using the OpenRouter provider with the Vercel AI SDK, you can access extended model information through the providerMetadata field in the finish event. This includes reasoning_details, which contains the model's internal thinking process (e.g., for Claude or DeepSeek models).

    Note that for parallel tool calls, reasoning_details is typically attached only to the first tool call to avoid duplication. In the finish metadata, reasoning_details is always included (even if empty) to maintain conversation state for certain providers.

    // Example of the structure expected in providerMetadata
    const openrouterMetadata = {
      usage: { ... },
      provider: "...",
      reasoning_details: [ /* ReasoningDetailUnion[] */ ],
      annotations: [ /* FileAnnotation[] */ ]
    };
  10. Access OpenRouter provider metadata

    main

    The OpenRouter provider exposes rich metadata through the providerMetadata field in both doGenerate and doStream responses. This allows access to provider-specific details that are not part of the standard AI SDK schema.

    Metadata Structure

    Inside providerMetadata.openrouter, you can access:

    • provider: The name of the underlying provider.
    • reasoning_details: An array of ReasoningDetailUnion objects (Text, Summary, or Encrypted) used for multi-turn roundtripping.
    • usage: Detailed usage accounting including cost, promptTokensDetails.cachedTokens, and completionTokensDetails.reasoningTokens.
    • annotations: File annotations (e.g., for citations or file references).

    Reasoning Details

    Reasoning is returned as reasoning content parts. The reasoning_details metadata is crucial for preserving the state of 'thinking' blocks (including signatures and encrypted blobs) when performing multi-turn conversations.

  11. Access OpenRouter provider metadata and usage

    main

    The OpenRouterCompletionLanguageModel returns detailed usage and provider information in the providerMetadata.openrouter field. This is available in both doGenerate and doStream responses.

    Available Metadata Fields:

    • provider: The name of the underlying provider used by OpenRouter.
    • usage:
      • promptTokens: Number of input tokens.
      • promptTokensDetails.cachedTokens: Number of cached input tokens.
      • completionTokens: Number of output tokens.
      • completionTokensDetails.reasoningTokens: Number of reasoning tokens.
      • totalTokens: Sum of prompt and completion tokens.
      • cost: Total cost of the request.
      • costDetails.upstreamInferenceCost: Cost from the upstream provider.
  12. Configure OpenRouter model settings

    main

    The OpenRouterChatLanguageModel uses OpenRouterChatSettings to configure model-level behavior. Key settings include:

    • models: The specific models to use.
    • logitBias: Logit bias settings.
    • logprobs: Boolean or number for logprob requests.
    • user: User identifier.
    • parallelToolCalls: Whether to allow parallel tool calls.
    • maxTokens: Maximum output tokens.
    • temperature: Sampling temperature.
    • topP: Nucleus sampling.
    • frequencyPenalty: Penalty for frequent tokens.
    • presencePenalty: Penalty for presence of tokens.
    • topK: Top-K sampling.
    • includeReasoning: Whether to include reasoning/thinking details.
    • reasoning: Specific reasoning settings.
    • usage: Whether to include usage accounting.
    • plugins: Web search or other plugins.
    • webSearchOptions: Configuration for web search.
    • provider: Provider routing settings.
    • debug: Debugging mode.
    • cacheControl: Anthropic-style automatic caching.
    • extraBody: Additional body parameters for the API.