From cf3122dd8fc3b217d28d8f021c9f13d209525cd6 Mon Sep 17 00:00:00 2001 From: Erik Demaine Date: Thu, 18 Jun 2026 03:58:19 -0400 Subject: [PATCH 1/2] feat: cost for OpenRouter image models --- .changeset/openrouter-image-cost.md | 6 +++ packages/ai-openrouter/src/adapters/image.ts | 9 +++-- .../ai-openrouter/tests/image-adapter.test.ts | 39 +++++++++++++++++++ 3 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 .changeset/openrouter-image-cost.md diff --git a/.changeset/openrouter-image-cost.md b/.changeset/openrouter-image-cost.md new file mode 100644 index 000000000..deb4875f2 --- /dev/null +++ b/.changeset/openrouter-image-cost.md @@ -0,0 +1,6 @@ +--- +'@tanstack/ai-openrouter': patch +--- + +Surface OpenRouter provider-reported cost on image generation usage, matching +the existing text adapter behavior. diff --git a/packages/ai-openrouter/src/adapters/image.ts b/packages/ai-openrouter/src/adapters/image.ts index ced370e54..a61fe2b16 100644 --- a/packages/ai-openrouter/src/adapters/image.ts +++ b/packages/ai-openrouter/src/adapters/image.ts @@ -6,6 +6,7 @@ import { generateId as utilGenerateId, } from '../utils' import { buildOpenRouterUsage } from '../usage' +import { extractUsageCost } from './cost' import type { OpenRouterClientConfig } from '../utils' import type { OpenRouterImageModelInputModalitiesByName, @@ -203,10 +204,10 @@ export class OpenRouterImageAdapter< // OpenRouter routes image generation through the chat surface, so the // response carries the same `usage` shape as text. Surface it (with any - // detail breakdowns) when present. - const usage = response.usage - ? buildOpenRouterUsage(response.usage) - : undefined + // detail breakdowns and provider-reported cost) when present. + const baseUsage = buildOpenRouterUsage(response.usage) + const usage = + baseUsage && { ...baseUsage, ...extractUsageCost(response.usage) } return { id: response.id || this.generateId(), diff --git a/packages/ai-openrouter/tests/image-adapter.test.ts b/packages/ai-openrouter/tests/image-adapter.test.ts index 4f078fd33..f055b5093 100644 --- a/packages/ai-openrouter/tests/image-adapter.test.ts +++ b/packages/ai-openrouter/tests/image-adapter.test.ts @@ -111,6 +111,45 @@ describe('OpenRouter Image Adapter', () => { }) }) + it('surfaces provider-reported cost from OpenRouter image usage', async () => { + const mockResponse = { + ...createMockImageResponse([{ url: 'https://example.com/image1.png' }]), + usage: { + completionTokens: 1291, + cost: 0.0387076, + cost_details: { + upstream_inference_completions_cost: 0.0387025, + upstream_inference_cost: 0.0387076, + upstream_inference_prompt_cost: 0.0000051, + }, + promptTokens: 17, + totalTokens: 1308, + }, + } + + mockSend = vi.fn().mockResolvedValueOnce(mockResponse) + + const adapter = createAdapter() + + const result = await adapter.generateImages({ + model: 'google/gemini-2.5-flash-image', + prompt: 'A futuristic city at sunset', + logger: testLogger, + }) + + expect(result.usage).toMatchObject({ + promptTokens: 17, + completionTokens: 1291, + totalTokens: 1308, + cost: 0.0387076, + costDetails: { + upstreamOutputCost: 0.0387025, + upstreamCost: 0.0387076, + upstreamInputCost: 0.0000051, + }, + }) + }) + it('generates multiple images', async () => { const mockResponse = createMockImageResponse([ { url: 'https://example.com/image1.png' }, From 278c69b40727ad8f13801d44372c2f99c47e4cc5 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Fri, 19 Jun 2026 12:32:27 +0000 Subject: [PATCH 2/2] ci: apply automated fixes --- packages/ai-openrouter/src/adapters/image.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/ai-openrouter/src/adapters/image.ts b/packages/ai-openrouter/src/adapters/image.ts index a61fe2b16..1c1a75657 100644 --- a/packages/ai-openrouter/src/adapters/image.ts +++ b/packages/ai-openrouter/src/adapters/image.ts @@ -206,8 +206,10 @@ export class OpenRouterImageAdapter< // response carries the same `usage` shape as text. Surface it (with any // detail breakdowns and provider-reported cost) when present. const baseUsage = buildOpenRouterUsage(response.usage) - const usage = - baseUsage && { ...baseUsage, ...extractUsageCost(response.usage) } + const usage = baseUsage && { + ...baseUsage, + ...extractUsageCost(response.usage), + } return { id: response.id || this.generateId(),