Skip to content

ai-openrouter: unconditional stream_options.include_usage injection breaks provider.require_parameters: true #1037

Description

@archiekd

Which project does this relate to?

AI

Describe the bug

@tanstack/ai-openrouter unconditionally injects streamOptions: { includeUsage: true } into every streaming request (serialized to stream_options on the wire by @openrouter/sdk). Because it is hardcoded after the spread of the caller's streamOptions, there is no way to remove or override it via modelOptions.

This breaks OpenRouter's provider routing option provider: { require_parameters: true }: OpenRouter filters to endpoints that declare support for every parameter in the request, and stream_options is an OpenAI Chat-Completions-shaped parameter that e.g. Anthropic-family endpoints do not declare. Result: every streaming call to such providers fails with 404 No endpoints found that can handle the requested parameters (verified live A/B 2026-07-31 with anthropic/claude-sonnet-4.5require_parameters: false works, true 404s every call).

Injection sites (current main):

  • packages/ai-openrouter/src/adapters/text.tschatStream:

    streamOptions: {
      ...(chatRequest.streamOptions ?? {}),
      includeUsage: true,   // hardcoded after the spread — caller cannot disable
    },
  • same file, structuredOutputStream — strips the caller's streamOptions then re-adds a hardcoded streamOptions: { includeUsage: true }.

  • same pattern in packages/openai-base/src/adapters/chat-completions-text.ts (stream_options: { include_usage: true }), affecting any OpenAI-compatible gateway that routes to heterogeneous providers.

Expected behavior

One of:

  1. Respect an explicit caller value: modelOptions.streamOptions.includeUsage: false (or streamOptions: null) suppresses the injection, or
  2. an adapter-level option to disable usage-tracking injection, or
  3. the OpenRouter adapter omits stream_options when the request carries provider.require_parameters: true.

Usage accounting is valuable as a default, but it currently costs the ability to use require_parameters: true at all — which is OpenRouter's recommended guard against silent provider-side parameter dropping (e.g. tool schemas).

Steps to reproduce

import { chat } from "@tanstack/ai"
import { openRouterText } from "@tanstack/ai-openrouter"

const stream = chat({
  adapter: openRouterText("anthropic/claude-sonnet-4.5"),
  messages: [{ role: "user", content: "hi" }],
  modelOptions: {
    provider: { only: ["anthropic"], require_parameters: true }
  }
})
for await (const chunk of stream) console.log(chunk.type)
// → RUN_ERROR: 404 "No endpoints found that can handle the requested parameters"
// Flip require_parameters to false → works.

Versions: @tanstack/ai@0.42.0, @tanstack/ai-openrouter@0.15.10 (latest at time of filing); injection sites confirmed still present on main.

Workaround we ship today: require_parameters: false and re-test on every adapter upgrade.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions