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

    has-prAn open PR references this issuewaiting-on: maintainerThe ball is in the maintainers’ court

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions