Skip to content

Use the cost reported by the AI Gateway in instrument_openai and instrument_anthropic - #2701

Open
lakshya-dhariwal wants to merge 6 commits into
pydantic:mainfrom
lakshya-dhariwal:fix/gateway-reported-cost
Open

lakshya-dhariwal wants to merge 6 commits into
pydantic:mainfrom
lakshya-dhariwal:fix/gateway-reported-cost

Conversation

@lakshya-dhariwal

@lakshya-dhariwal lakshya-dhariwal commented Oct 30, 2026 •

Copy link
Copy Markdown

Fixes #2700.

get_usage_attributes now checks the response's usage object for the cost the Logfire AI Gateway reported (usage.logfire_ai_gateway.cost, then the deprecated usage.pydantic_ai_gateway.cost_estimate) and uses it for operation.cost instead of the genai-prices estimate. A reported 0 is treated as a real cost. The response is dumped once up front and the same dump feeds the estimate path, so the existing model_dump call pattern is unchanged.

Both instrument_openai and instrument_anthropic route through get_usage_attributes, so this covers streaming and non-streaming responses for both. The logfire-ai-gateway-cost header isn't read here: the openai and anthropic SDKs keep the gateway's usage block on their parsed responses, and pydantic-ai only needs the header for SDKs that drop it (google-genai, boto3).

Mirrors pydantic-ai's _gateway_cost.py (pydantic/pydantic-ai#7337).

Tests: 5 new cases in test_llm_usage_attributes.py covering string/number/zero costs, the deprecated block, and invalid values falling back to the estimate. pytest tests/otel_integrations/test_llm_usage_attributes.py passes (22 tests); the 4 cost-assertion tests fail on main without the change.

View guided diff

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 2 files

Confidence score: 4/5

  • tests/otel_integrations/test_llm_usage_attributes.py bypasses both SDK wrappers, so regressions in instrument_openai or instrument_anthropic could go unnoticed. Add a gateway-cost case that exercises the wrapper behavior.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="tests/otel_integrations/test_llm_usage_attributes.py">

<violation number="1" location="tests/otel_integrations/test_llm_usage_attributes.py:343">
P2: These regression tests bypass both SDK integration wrappers, so they do not verify the behavior promised for `instrument_openai` and `instrument_anthropic`. Add one gateway-cost case through `get_openai_usage_attributes` and one through `get_anthropic_usage_attributes` using representative SDK response models, covering the independently constructed runtime paths.</violation>
</file>

Reply with feedback, questions, or to request a fix.

View guided diff | Re-trigger cubic

model='gpt-4',
usage={'prompt_tokens': 10, 'completion_tokens': 5, 'logfire_ai_gateway': {'cost': '0.0038'}},
)
result = get_usage_attributes(response, usage, 10, 5, provider_id='openai', api_flavor='chat')

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: These regression tests bypass both SDK integration wrappers, so they do not verify the behavior promised for instrument_openai and instrument_anthropic. Add one gateway-cost case through get_openai_usage_attributes and one through get_anthropic_usage_attributes using representative SDK response models, covering the independently constructed runtime paths.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At tests/otel_integrations/test_llm_usage_attributes.py, line 343:

<comment>These regression tests bypass both SDK integration wrappers, so they do not verify the behavior promised for `instrument_openai` and `instrument_anthropic`. Add one gateway-cost case through `get_openai_usage_attributes` and one through `get_anthropic_usage_attributes` using representative SDK response models, covering the independently constructed runtime paths.</comment>

<file context>
@@ -326,3 +326,66 @@ def model_dump(self, **kwargs: Any) -> dict[str, Any]:
+        model='gpt-4',
+        usage={'prompt_tokens': 10, 'completion_tokens': 5, 'logfire_ai_gateway': {'cost': '0.0038'}},
+    )
+    result = get_usage_attributes(response, usage, 10, 5, provider_id='openai', api_flavor='chat')
+    assert result['operation.cost'] == snapshot(0.0038)
+
</file context>

@github-actions

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  logfire-sdk/logfire/_internal/integrations/llm_providers
  usage.py
Project Total  

This report was generated by python-coverage-comment-action

Add tests to ensure gateway check handles unusual response data gracefully.
Refactor cost validation to handle NaN, inf, and negative values more clearly.
Added a new invalid cost case ('1e400') to the test for gateway cost fallback. Updated the OpenAI wrapper test to check for the correct cost from the SDK response.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Use the cost reported by the AI Gateway in instrument_openai and instrument_anthropic

1 participant