fix(openrouter): remove usage injection that causes TypeError on OpenAI SDK path (#22774)

* fix(openrouter): remove usage injection that causes TypeError on OpenAI SDK path

The transform_request method injected `usage: {include: true}` into the
request dict for cost tracking (added in #9747). This causes a TypeError
when the request routes through the OpenAI SDK path, as
AsyncCompletions.create() does not accept `usage` as a keyword argument.

OpenRouter now returns cost data (token counts, cost, cost_details) by
default in all responses, making the usage request parameter unnecessary.

Remove the injection and update tests to assert usage is not present.

* fix: update stale comment referencing removed usage.include parameter

---------

Co-authored-by: tibG <naps@qubes.milou>
This commit is contained in:
Tib 2026-03-12 17:54:58 +01:00 • committed by GitHub
parent 0bec1e05fc
commit 011b8baeff
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 7 additions and 14 deletions

View file

@ -167,11 +167,6 @@ class OpenrouterConfig(OpenAIGPTConfig):
)
response.update(extra_body)
# ALWAYS add usage parameter to get cost data from OpenRouter
# This ensures cost tracking works for all OpenRouter models
if "usage" not in response:
response["usage"] = {"include": True}
return response
def transform_response(
@ -212,7 +207,7 @@ class OpenrouterConfig(OpenAIGPTConfig):
)
# Extract cost from OpenRouter response body
# OpenRouter returns cost information in the usage object when usage.include=true
# OpenRouter returns cost information in the usage object by default
try:
response_json = raw_response.json()
if "usage" in response_json and response_json["usage"]:

View file

@ -373,7 +373,7 @@ def test_openrouter_cost_tracking_non_streaming():
Test OpenRouter cost tracking for non-streaming completions.
Verifies:
1. Request includes usage.include=true to get cost data
1. Request does NOT inject usage parameter (OpenRouter returns cost data by default)
2. Response extracts cost from usage.cost and stores in _hidden_params
"""
from unittest.mock import Mock, patch
@ -381,7 +381,7 @@ def test_openrouter_cost_tracking_non_streaming():
config = OpenrouterConfig()
# Test request adds usage parameter
# Verify request does NOT add usage parameter — OpenRouter returns cost by default
transformed_request = config.transform_request(
model="openrouter/anthropic/claude-sonnet-4.5",
messages=[{"role": "user", "content": "Hello"}],
@ -389,8 +389,7 @@ def test_openrouter_cost_tracking_non_streaming():
litellm_params={},
headers={},
)
assert "usage" in transformed_request
assert transformed_request["usage"] == {"include": True}
assert "usage" not in transformed_request
# Test response extracts cost
mock_response = Mock(spec=httpx.Response)
@ -434,13 +433,13 @@ def test_openrouter_cost_tracking_streaming():
Test OpenRouter cost tracking for streaming completions.
Verifies:
1. Request includes usage.include=true (same as non-streaming)
1. Request does NOT inject usage parameter (OpenRouter returns cost data by default)
2. Streaming chunks preserve usage/cost data in the final chunk
3. Cost field is accessible in the usage object
"""
config = OpenrouterConfig()
# Test request adds usage parameter for streaming
# Verify request does NOT add usage parameter — OpenRouter returns cost by default
transformed_request = config.transform_request(
model="openrouter/anthropic/claude-sonnet-4.5",
messages=[{"role": "user", "content": "Hello"}],
@ -448,8 +447,7 @@ def test_openrouter_cost_tracking_streaming():
litellm_params={},
headers={},
)
assert "usage" in transformed_request
assert transformed_request["usage"] == {"include": True}
assert "usage" not in transformed_request
# Test streaming chunks preserve cost data
handler = OpenRouterChatCompletionStreamingHandler(