Packages

@tanstack/ai-openrouter

1.0.0 · 22 Oct 2026MIT69.2k / weekRepositoryHomepagenpmAtom feed

98 stable releases, newest first, by release line. Notes are quoted as the maintainers published them.

  1. 1.x · latest line
  2. 1.0.0

    22 Oct 2026
    • breaking

      TanStack AI 1.0.0. This release removes every API that was deprecated in 0.x. Read the upgrade guide before you upgrade: tanstack.com/ai/latest/docs/migration/v1

    • The TypeSafe, Ollaya, OpenRouter and Vercel Gateway evaluate adapters now set status on the error they throw for an error response. status is the HTTP status code, so you can tell a rate limit (429) from a bad key (401) without parsing the message. The message does not change.

      if (error instanceof Error && 'status' in error && error.status === 429) {
        // wait, then call decide() again
      }
    • Update model metadata from OpenRouter API

  3. 0.23.x
  4. 0.23.1

    21 Oct 2026

    Only updates a dependency:@tanstack/ai 0.71.0

  5. 0.23.0

    19 Oct 2026
    • Structured output sends response_format: { type: "json_object" } for OpenRouter and Groq models that declare a response format without strict structured outputs. These models reject strict json_schema. In JSON mode the adapter adds the schema as a system prompt. await chat({ outputSchema }) checks the reply when the schema is a Standard Schema, such as Zod. Other models keep strict json_schema.

      modelOptions can set json_object for any model. On the OpenAI-base adapters (OpenAI, Grok, Groq and others), a json_object in modelOptions was replaced by strict json_schema. It is now sent as given, with the schema in a system prompt. In JSON mode, supportsCombinedToolsAndSchema() returns false. Tools and the schema then go out in separate requests, so the tool-calling turns do not get the schema prompt.

      OpenRouter catalog ids with a :variant, such as google/gemma-4-26b-a4b-it:free, now match their own catalog entry. Before, only the id without the variant was checked.

    • Keep the provider's raw tool argument string for replay.

  6. 0.22.x
  7. 0.22.0

    13 Oct 2026
    • Text adapters now set one stable code on RUN_ERROR when the input does not fit in the model's context window: code: 'context_overflow'. @tanstack/ai exports it as CONTEXT_OVERFLOW_CODE. The provider's own text stays in message.

      if (chunk.type === 'RUN_ERROR' && chunk.code === CONTEXT_OVERFLOW_CODE) {
        // shorten the messages, then call chat() again
      }

      These adapters set it: OpenAI and the other OpenAI-compatible adapters (from code: 'context_length_exceeded'), Anthropic, Gemini, Bedrock (Converse, Chat Completions, and Responses), OpenRouter, Grok, Cloudflare Workers AI, and BytePlus.

      Changes to code that reads the old values:

    • Add openrouterSignIn() at @tanstack/ai-openrouter/pkce: a local app, such as a CLI, signs the user in to OpenRouter in the browser and gets an API key, with no key to copy.

    • Prompt caching is now on by default. Each chat() call asks the provider to cache the stable start of the request (system prompt, tools, and earlier messages), so repeated requests cost less and answer sooner.

  8. 0.21.x
  9. 0.21.5

    9 Oct 2026

    Only updates a dependency:@tanstack/ai 0.68.0

  10. 0.21.4

    9 Oct 2026
    • Text adapters can now give inputModalities at run time: the input kinds that the model reads, for example ['text', 'image', 'document']. undefined means that the adapter does not know.

    • Add wrapFetch to chat(), to the middleware onConfig config, and to TextOptions. A wrapper gets the next fetch and gives back a new fetch. Use it to change the URL, the headers, the request, or the response of a model call. The new FetchWrapper type names the wrapper.

      The engine chains the chat() wrapper and the middleware wrappers into one function. A middleware wrapper runs inside the chat() wrapper and applies to one model call only.

      These text adapters send their requests through the wrapper: every adapter on @tanstack/openai-base (OpenAI, the OpenAI-compatible adapters, Grok, Groq, BytePlus, LLM Gateway, Lovable, Vercel AI Gateway, Cloudflare, and the Bedrock Chat Completions and Responses APIs), Anthropic, Mistral, Ollama, and OpenRouter. The wrapper wraps the fetch of the adapter config, not the global fetch. An Anthropic or Ollama adapter with an injected client ignores wrapFetch. In Cloudflare binding mode, the wrapper runs, but the binding does not send the URL or the headers. Without wrapFetch, the requests do not change.

  11. 0.21.2

    8 Oct 2026
    • Keep a reported reasoning token count of 0 in the usage. structuredOutputStream() now also puts the received token usage and cost on its RUN_ERROR event.

  12. 0.21.1

    7 Oct 2026
    • Update model metadata from OpenRouter API

  13. 0.21.0

    6 Oct 2026
    • Video adapters can hand a provider's download stream to generation persistence instead of buffering it. Adapters now implement getVideo(). When a provider has no public URL for the finished video (OpenRouter, Lovable, Sora jobs without url), it returns a VideoStreamResult ({ body, contentType }), and withGenerationPersistence streams it into your blob store and sets url from artifactUrl.

      Nothing changes without persistence: getVideoJobStatus() and streaming generateVideo() still return a base64 data: URL for those providers.

      VideoAdapter.getVideoUrl() is deprecated in favor of getVideo(). It still works: on the built-in adapters it is getVideo() with a stream buffered into a data: URL, and custom adapters that only implement getVideoUrl() keep working. A custom adapter that extends BaseVideoAdapter with TypeScript's noImplicitOverride must add override to its getVideoUrl(), or rename it to getVideo().

  14. 0.20.x
  15. 0.20.3

    5 Oct 2026
    • Keep optional tool fields optional. The Chat Completions adapter now sends function tools with strict: false. With strict omitted, OpenAI models through OpenRouter were observed to treat the schema as strict and make every optional field required, so before this fix the model could not leave one out. The Responses adapter now strips the null that strict mode puts in an omitted optional field before the tool input is validated, so the tool runs and sees the field as absent. A .nullable() field keeps its null. Known limit: an optional field inside a union of several object shapes is not stripped and still arrives as null.

    • Update model metadata from OpenRouter API

  16. 0.20.2

    2 Oct 2026
    • Update model metadata from OpenRouter API

  17. 0.20.1

    27 Sep 2026

    Only updates a dependency:@tanstack/ai 0.63.0

  18. 0.19.x
  19. 0.19.20

    24 Sep 2026
    • Structured output now reports a response that was cut off at the output cap (finish_reason: "length") as a truncation error instead of a JSON parse error or a "no content" / "missing structured result" error. This covers chat({ outputSchema }) in native combined mode (error code max_tokens), structuredOutputStream() in openai-base and ai-openrouter (RUN_ERROR with code max_tokens), and their non-stream structuredOutput(). A truncated document used to read as a schema failure; the error now says the token limit was reached.

    • Update model metadata from OpenRouter API

  20. 0.19.18

    24 Sep 2026
    • Add a retryCodes option to the OpenRouter text and summarize adapters. The adapter passes it to every chat request, so retryCodes: ['429', '5XX'] together with retryConfig now retries rate limits. Before, the SDK retried only 5XX errors, because it reads retryCodes only per request.

  21. 0.19.17

    23 Sep 2026
    • Update model metadata from OpenRouter API

  22. 0.19.16

    21 Sep 2026

    Only updates a dependency:@tanstack/ai 0.58.0

  23. 0.19.15

    21 Sep 2026
    • Update model metadata from OpenRouter API

  24. 0.19.14

    21 Sep 2026
    • Add decide() and TypeSafe Jev evaluate adapters.

      Callers await one decide({ adapter, state, questions }) call.
      Questions use choice(), score(), and boolean(). Answers sit on the result (value, probability, confidence). Usage sits on result.meta.

      Jev transports:

  25. 0.19.12

    17 Sep 2026
    • Update model metadata from OpenRouter API

  26. 0.19.11

    17 Sep 2026
    • Update model metadata from OpenRouter API

  27. 0.19.9

    10 Sep 2026
    • Update model metadata from OpenRouter API

  28. 0.19.8

    3 Sep 2026
    • Update model metadata from OpenRouter API

  29. 0.19.7

    2 Sep 2026
    • Update model metadata from OpenRouter API

  30. 0.19.6

    1 Sep 2026
    • Update model metadata from OpenRouter API

  31. 0.19.5

    28 Aug 2026
    • Update model metadata from OpenRouter API

  32. 0.19.3 – 0.19.42 releases that only update dependencies@tanstack/ai 0.51.0Show each
  33. 0.19.1

    24 Aug 2026
    • Update model metadata from OpenRouter API

  34. 0.18.x
  35. 0.18.3

    22 Aug 2026
    • Put AG-UI extras under metadata.tanstack. SSE/HTTP wire events are spec-only.

      sendMessage({ content, metadata }) stamps user metadata on the user message.
      In-process chat() still yields toolName, TOOL_CALL_END.input, and TanStack TokenUsage.
      Thinking signatures round-trip on REASONING_ENCRYPTED_VALUE.
      Wire messages use content / toolCalls / fan-out roles, not parts.

  36. 0.18.2

    21 Aug 2026
    • Preserve reasoning: { enabled: false } by normalizing it to the SDK-supported reasoning: { effort: 'none' }, and omit empty reasoning objects before request serialization.

    • Recover successful OpenAI and OpenRouter Responses API text that is present only on the completed response event.

    • Update model metadata from OpenRouter API

  37. 0.18.1

    20 Aug 2026
    • Restore OPENROUTER_COMBINED_TOOLS_AND_SCHEMA_MODELS, which the model-metadata sync dropped from the generated model-meta.ts. The set is now generated from OpenRouter's catalog (chat models whose supported_parameters include structured_outputs, tools and tool_choice) instead of being hand-maintained, so combined tools + outputSchema mode now covers every model OpenRouter flags as supporting it.

    • Honor modelOptions.responseFormat: { type: 'json_object' } during structured output generation while preserving strict json_schema as the default.

    • Update model metadata from OpenRouter API

  38. 0.18.0

    19 Aug 2026
    • Add a self-describing billed field to TokenUsage so billed quantities carry the unit they are counted in (#816). usage.billed is { quantity, unit } with a BillingUnit union ('seconds', 'units', 'images', 'tokens', ... open-ended). The deprecated unitsBilled / durationSeconds counts are still populated for backward compatibility. The fal adapters report { quantity, unit: 'units' }, Grok video { quantity, unit: 'seconds' }, the OpenAI/Grok/BytePlus duration-billed transcription paths { quantity, unit: 'seconds' }, BytePlus Seedream images { quantity, unit: 'images' }, BytePlus Seedance video { quantity, unit: 'tokens' }, and Cohere/OpenRouter rerank { quantity, unit: 'units' } (search units). Persistence sums billed when both reports use the same unit. otelMiddleware emits the pair as tanstack.ai.usage.billed_quantity / tanstack.ai.usage.billed_unit span attributes.

    • Add native combined tools + outputSchema mode to both OpenRouter text adapters (chat-completions and Responses). When the resolved upstream model supports emitting a schema-constrained final answer alongside tool calls in a single pass, chat({ outputSchema, tools, stream: true }) now wires the JSON Schema into the same streaming request as the tools and harvests the final-turn JSON, skipping the separate finalization round-trip.

      Because OpenRouter is a routing layer, capability is keyed per resolved upstream model via the new OPENROUTER_COMBINED_TOOLS_AND_SCHEMA_MODELS set, exported from @tanstack/ai-openrouter/model-meta, which both adapters consult from supportsCombinedToolsAndSchema(). The set is derived from each upstream provider's combined-mode gate (Anthropic 4.5+, Gemini 3.x, OpenAI's strict json_schema era, Grok 4.x) rather than the broader catalog responseFormat flag, so models that advertise structured output but predate native combined mode stay on the legacy finalization path.

    • Classify Anthropic, Gemini, and OpenAI native tools with stable runtime discriminators so ordinary functions can use the same public names without selecting provider-native behavior. Native tools must come from the adapter factory (webSearchTool(), googleSearchTool(), and the rest). A reserved name alone does not select a native converter. chat() throws DuplicateToolNameError when a factory tool and a custom function share the same public name.

      Previously the converters picked provider-native behavior by tool.name. Tool names are public application identifiers, so a plain function called web_search, google_search, or code_execution was routed into a native converter: it lost its inputSchema and was sent as a provider-only payload (and on Anthropic could also flip on code_execution / skills beta headers). Native tools are now identified by adapter-owned metadata, which converters strip before building the wire payload, so provider API versions stay confined to the wire converters.

      Also preserves Anthropic webSearchTool options (max_uses, allowed_domains, blocked_domains, user_location, cache_control) on the wire payload.

      Also fixes googleSearchTool({ searchTypes: … }) being silently dropped on the experimental geminiTextInteractions() adapter. The Interactions converter read a snake_case search_types array, but the public factory takes the Generate Content shape (GoogleSearch.searchTypes: { webSearch?, imageSearch? }), so the field never matched and every request fell back to the provider default of web-search-only. The camelCase config is now translated to the Interactions wire list.

  39. 0.17.x
  40. 0.17.1

    18 Aug 2026
    • Exclude the prediction parameter from the generated OpenRouter model options. The OpenRouter API newly reports it as a supported parameter, but @openrouter/sdk's ChatRequest does not declare it (its outbound schema would strip it), so the generated Pick<OpenRouterBaseOptions, ... | 'prediction'> types failed to compile.

    • Timestamp native and fallback structured-output events when they are emitted so their lifecycle remains chronologically ordered.

    • Update model metadata from OpenRouter API

  41. 0.17.0

    14 Aug 2026
    • Add openRouterVideo, a video generation adapter for OpenRouter's dedicated async API (POST /api/v1/videos) — Seedance, Veo 3.1, Wan, Kling, and Sora 2 Pro through one API key. Follows the jobs/polling architecture (generateVideo() → getVideoJobStatus()), with per-model size / duration / provider-option types generated from OpenRouter's GET /api/v1/videos/models metadata and validated before submit. duration is typed per model on the shared typed-duration contract — the adapter implements availableDurations() and snapDuration(seconds) (matching the Veo adapter) to enumerate the valid set and coerce raw UI seconds to the closest supported value. Image-conditioned prompts map metadata.role onto the wire: start_frame / end_frame → frame_images (first_frame / last_frame), reference / character → input_references; frame roles are validated against each model's supported_frame_images. Completed videos are downloaded server-side and returned as data: URLs (OpenRouter's download URLs require the API key), and the gateway-reported cost is surfaced as usage.cost.

      Image adapter fixes from the #624 review: requested size is now validated (the WIDTHxHEIGHT union previously used a Unicode ×, so every size except 1024x1024 silently dropped its aspect ratio; unsupported sizes now throw with the supported list), numberOfImages > 1 throws instead of silently returning one image (verified live: the gateway ignores all count keys in image_config), and image_config.strength (0.0–1.0 image-to-image influence) is exposed via modelOptions.strength.

    • Refresh MiniMax M2.7 and M3 context and pricing metadata.

  42. 0.16.x
  43. 0.16.1

    11 Aug 2026
    • populate StructuredOutputResult.usage from non-stream structuredOutput()

      Adapters that already returned tokens/cost on streaming structured paths were dropping response.usage on the non-stream structuredOutput() method. OpenRouter now forwards tokens and cost; openai-base, Mistral, and Bedrock Converse do the same for tokens so fallbackStructuredOutputStream and middleware can observe usage.

  44. 0.16.0

    10 Aug 2026
    • add openRouterRerank / createOpenRouterRerank rerank adapters

      Rerank documents by relevance to a query through OpenRouter's unified /v1/rerank endpoint (e.g. cohere/rerank-v3.5) with the rerank() activity. Reads OPENROUTER_API_KEY from the environment and forwards the optional httpReferer / appTitle attribution headers, consistent with the other OpenRouter adapters.

    • Preserve distinct Responses output item and function call IDs across server tool round trips.

    • publish internal dependency ranges as ^x.y.z instead of exact pins

      Internal dependencies on other TanStack AI packages used workspace:* in dependencies and peerDependencies. pnpm rewrites that to an exact version at publish time, so a released package asked for e.g. @tanstack/ai-utils@0.4.0 rather than ^0.4.0.

      Two consequences for consumers:

      These fields now use workspace:^, which publishes as ^x.y.z. Every package here is still 0.x, so ^0.43.1 resolves to 0.43.x only — patches dedupe cleanly and no breaking minor is ever pulled in.

      devDependencies deliberately keep workspace:*: they are never published, and * correctly means "always build against the local copy".

  45. 0.15.x
  46. 0.15.11

    4 Aug 2026
    • breaking

      RunStatus widened to include 'aborted' (previously 'running' | 'completed' | 'failed' | 'interrupted'). The union appears in a read position (get(): Promise<RunRecord | null>), so an exhaustive switch over record.status with a never default in your code stops compiling until it handles 'aborted'.

    • breaking

      Run types are re-exported from @tanstack/ai rather than declared here, so the runs store is typed against core's RunStore directly. MemoryRunStore implements both optional list methods, and the shared conformance testkit covers them.

    • breaking

      runPersistenceConformance accepts skipMethods. An optional method that is missing and not declared in skipMethods now throws instead of silently passing, so an existing backend running the suite may see a new failure telling it to implement the method or declare the omission.

  47. 0.15.10

    20 Jul 2026

    Reading the note…

  48. 0.15.9

    16 Jul 2026

    Reading the note…

  49. 0.15.8

    6 Jul 2026

    Reading the note…

  50. 0.15.7

    3 Jul 2026

    Reading the note…

  51. 0.15.6

    30 Jun 2026

    Reading the note…

  52. 0.15.5

    29 Jun 2026

    Reading the note…

  53. 0.15.4

    26 Jun 2026

    Reading the note…

  54. 0.15.3

    25 Jun 2026

    Reading the note…

  55. 0.15.2

    25 Jun 2026

    Reading the note…

  56. 0.15.1

    24 Jun 2026

    Reading the note…

  57. 0.15.0

    24 Jun 2026

    Reading the note…

  58. 0.14.x
  59. 0.14.2

    23 Jun 2026

    Reading the note…

  60. 0.14.1

    22 Jun 2026

    Reading the note…