-
-
Notifications
You must be signed in to change notification settings - Fork 251
fix(ai-openrouter): stop forwarding root observability metadata to the wire request #737
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
AlemTuzlak
merged 2 commits into
main
from
735-tanstackai-openrouter-013-root-observability-metadata-is-forwarded-to-chatrequestmetadata-failing-sdk-recordstringstring-validation-on-every-call
Jun 22, 2026
Merged
Changes from 1 commit
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| --- | ||
| '@tanstack/ai-openrouter': patch | ||
| '@tanstack/ai': patch | ||
| --- | ||
|
|
||
| fix(ai-openrouter): stop forwarding root observability `metadata` to the provider wire request (#735) | ||
|
|
||
| The OpenRouter chat-completions adapter (since 0.13.0) and responses adapter (since 0.9.0) copied `chat()`'s root-level observability `metadata` onto the wire as `chatRequest.metadata` / `responsesRequest.metadata`. The `@openrouter/sdk` validates those fields as `Record<string, string>`, so structured observability metadata (objects, arrays β the documented usage for middleware/devtools consumers) failed client-side Zod validation with `Input validation failed` on every call. The spread also clobbered an intentional, correctly-typed `modelOptions.metadata`. | ||
|
|
||
| Root `metadata` is observability-only again (middleware, devtools, event client) and `modelOptions.metadata` is the sole source for OpenRouter wire metadata, matching every other adapter. The `TextOptions.metadata` doc comment in `@tanstack/ai` now states this contract explicitly. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| import { test, expect } from './fixtures' | ||
|
|
||
| /** | ||
| * End-to-end regression coverage for #735: root-level observability | ||
| * `metadata` on `chat()` must never be forwarded onto the provider wire | ||
| * request. | ||
| * | ||
| * In `@tanstack/ai-openrouter` 0.13.x the chat-completions mapper copied | ||
| * root `metadata` into OpenRouter's `chatRequest.metadata`. The | ||
| * `@openrouter/sdk` validates that field as `Record<string, string>` | ||
| * client-side, so structured observability metadata (objects, arrays β | ||
| * the documented usage for middleware/devtools consumers) failed Zod | ||
| * validation before the request ever left the process, killing every | ||
| * call with `RUN_ERROR`. | ||
| * | ||
| * Wire-shape coverage lives in the unit tests | ||
| * `packages/ai-openrouter/tests/openrouter-adapter.test.ts` and | ||
| * `openrouter-responses-adapter.test.ts`, which inspect the request | ||
| * handed to the SDK directly. What this spec covers (which those | ||
| * cannot): the full HTTP path β test β route β `chat()` β adapter β | ||
| * real `@openrouter/sdk` outbound validation β tolerates structured | ||
| * root metadata. Pre-fix, the SDK's own Zod schema rejects the request | ||
| * and the stream emits RUN_ERROR instead of completing. | ||
| */ | ||
| test.describe('root observability metadata β wire path', () => { | ||
| test('chat completes end-to-end on OpenRouter without the root metadata reaching the wire request', async ({ | ||
| request, | ||
| testId, | ||
| aimockPort, | ||
| }) => { | ||
| const body = { | ||
| threadId: 'thread-root-meta-1', | ||
| runId: 'run-root-meta-1', | ||
| state: {}, | ||
| messages: [ | ||
| { id: 'u1', role: 'user', content: '[chat] recommend a guitar' }, | ||
| ], | ||
| tools: [], | ||
| context: [], | ||
| forwardedProps: { | ||
| provider: 'openrouter', | ||
| feature: 'chat', | ||
| testId, | ||
| aimockPort, | ||
| // Opt-in flag handled by `api.chat.ts` β passes structured | ||
| // root-level observability metadata (arrays, nested objects) to | ||
| // `chat()`. The adapter must keep it off the provider request; | ||
| // pre-fix, the SDK's own outbound Zod validation rejects the | ||
| // request before it reaches aimock and the stream ends in | ||
| // RUN_ERROR. | ||
| structuredRootMetadata: true, | ||
| }, | ||
| } | ||
| const response = await request.post('/api/chat', { | ||
| data: body, | ||
| headers: { 'Content-Type': 'application/json' }, | ||
| }) | ||
| expect( | ||
| response.ok(), | ||
| `expected 200, got ${response.status()}: ${await response.text()}`, | ||
| ).toBe(true) | ||
| const text = await response.text() | ||
| expect(text).toContain('RUN_FINISHED') | ||
| // No RUN_ERROR β the @openrouter/sdk's outbound Record<string, string> | ||
| // validation never saw the structured metadata. | ||
| expect(text).not.toContain('RUN_ERROR') | ||
| }) | ||
| }) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.