test(e2e): spendlog cost for streaming /v1/messages via responses bridge - #33713
test(e2e): spendlog cost for streaming /v1/messages via responses bridge#33713yassin-berriai wants to merge 2 commits into
Conversation
Add a live spend-tracking e2e that drives a streaming anthropic-format /v1/messages request through litellm's anthropic-messages -> OpenAI Responses adapter and asserts the consumed stream writes exactly one SpendLogs row with nonzero cost and token counts, attributed to the calling key under custom_llm_provider openai and the /v1/messages call_type. The deployment is a Responses-only OpenAI model (gpt-5.3-codex), so a served, costed row proves the Responses path was taken; the chat-completions bridge would have failed at OpenAI on an endpoint the model does not expose. Adds a streaming /v1/messages method to the shared Gateway and the suite client, the model to the inline compose config and driver-model registration, a coverage registry row (quota_management.spend_tracking.messages_bridge.logs_cost), and the matching variant vocab entry. Resolves LIT-4546
|
|
Greptile SummaryThis PR adds an e2e test that verifies spend tracking for streaming
Confidence Score: 5/5All changes are confined to the tests/e2e/ directory and do not touch any production code paths. The diff is entirely test infrastructure — a new e2e test, a shared gateway method, docker-compose and conftest additions, and registry/doc updates. Previous review findings (missing fields in _summarize, stale proof of fix) are addressed in this head commit. The test logic is well-isolated (scoped key per test, polling to a deadline, unambiguous bridge-path verification via a Responses-only model), and no production code is modified. No files require special attention.
|
| Filename | Overview |
|---|---|
| tests/e2e/quota_management/spend_tracking/test_spend_tracking_e2e.py | Adds test_streaming_messages_via_responses_bridge_tracks_spend and expands _summarize to include call_type and custom_llm_provider; assertions are well-formed and use a scoped key for isolation. |
| tests/e2e/quota_management/spend_tracking/spend_e2e_client.py | Adds messages_stream method delegating to gateway.messages_stream; mirrors the existing chat_stream pattern cleanly. |
| tests/e2e/e2e_gateway.py | Adds messages_stream route method to Gateway using the existing transport.stream helper; no functional concerns. |
| tests/e2e/docker-compose.yml | Registers openai-responses-codex → openai/gpt-5.3-codex deployment required by the new test; reads OPENAI_API_KEY from env consistently with other OpenAI deployments. |
| tests/e2e/quota_management/spend_tracking/conftest.py | Adds openai-responses-codex to DRIVER_MODELS following the exact same pattern as existing entries; registration/cleanup logic is unchanged. |
| tests/e2e/coverage_registry/quota_management.yaml | Adds a P1 coverage entry quota_management.spend_tracking.messages_bridge.logs_cost that accurately identifies the source file and rationale. |
| tests/e2e/CLAUDE.md | Adds messages_bridge to the <spend_tracking> variant vocabulary; a minor documentation update consistent with the new coverage entry. |
Reviews (3): Last reviewed commit: "test(e2e): surface call_type and provide..." | Re-trigger Greptile
| assert (row.total_tokens or 0) == prompt + completion | ||
|
|
||
|
|
||
| @pytest.mark.covers("quota_management.spend_tracking.messages_bridge.logs_cost") |
There was a problem hiding this comment.
Proof in PR description does not cover this test
The PR's "Screenshots / Proof of Fix" section describes and demonstrates MCP key-access tests (tests/e2e/mcp/test_mcp_key_access_e2e.py) — a completely different suite. The command shown (python -m pytest tests/e2e/mcp/ -v) and the collected items (2 MCP tests) have no relation to this new spend-tracking test for the /v1/messages bridge. No evidence is supplied that test_streaming_messages_via_responses_bridge_tracks_spend passes against a live proxy, which is the claimed proof-of-fix for LIT-4547.
Rule Used: What: Ensure that any PR claiming to fix an issue ... (source)
Greptile SummaryThis PR adds an e2e spend-tracking test that validates a streaming
Confidence Score: 3/5The code changes are internally consistent and follow established patterns, but the PR cannot be verified from the supplied proof. The "Screenshots / Proof of Fix" section and the "Changes" narrative in the PR description document MCP authorization tests that do not exist in the changed files — they appear to have been pasted from a different PR. No evidence is provided that the actual new test has ever been run successfully against a live proxy. The test's correctness depends on a chain of conditions — the responses bridge aggregating the SSE stream correctly, the spend row landing with call_type containing anthropic_messages, and custom_llm_provider being openai — none of which are demonstrated. tests/e2e/quota_management/spend_tracking/test_spend_tracking_e2e.py — the new test has no attached proof of a successful run.
|
| Filename | Overview |
|---|---|
| tests/e2e/quota_management/spend_tracking/test_spend_tracking_e2e.py | Adds test_streaming_messages_via_responses_bridge_tracks_spend; logic is well-structured but the PR provides no evidence this test actually passes — the proof section documents MCP tests, not this one. |
| tests/e2e/docker-compose.yml | Adds openai-responses-codex deployment (openai/gpt-5.3-codex) to the compose config; consistent with existing model entries and pattern. |
| tests/e2e/quota_management/spend_tracking/conftest.py | Adds openai-responses-codex to DRIVER_MODELS using the same registration pattern as existing entries. |
| tests/e2e/quota_management/spend_tracking/spend_e2e_client.py | Adds messages_stream helper wrapping AnthropicMessagesBody; follows the same pattern as the existing chat_stream method. |
| tests/e2e/e2e_gateway.py | Adds messages_stream gateway method that posts to /v1/messages; straightforward extension of the existing streaming pattern. |
| tests/e2e/coverage_registry/quota_management.yaml | Adds the messages_bridge.logs_cost coverage entry with accurate source/rationale. |
| tests/e2e/CLAUDE.md | Adds messages_bridge to the spend_tracking variant taxonomy; reformats surrounding items for line-length consistency. |
Comments Outside Diff (1)
-
tests/e2e/quota_management/spend_tracking/test_spend_tracking_e2e.py, line 125-199 (link)Proof of fix is for a different feature entirely
The PR's "Screenshots / Proof of Fix" section and "Changes" description document MCP authorization tests (
tests/e2e/mcp/test_mcp_key_access_e2e.py), which do not appear anywhere in the changed files. No evidence is provided thattest_streaming_messages_via_responses_bridge_tracks_spendactually passes — the spend-log polling, thebridged_costed_rowpredicate, and thecall_type/custom_llm_providerassertions are all untested by the supplied proof. Per the team's rule requiring PRs to include evidence that the addressed issue is resolved, the submitted screenshots fail to satisfy that bar for this change.Rule Used: What: Ensure that any PR claiming to fix an issue ... (source)
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Reviews (2): Last reviewed commit: "test(e2e): spendlog cost for streaming /..." | Re-trigger Greptile
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Include call_type and custom_llm_provider in the _summarize row detail so a failed spend assertion prints the two fields the messages-bridge test asserts on, instead of hiding them and forcing a re-run to diagnose.
|
@greptileai please review the current head fdec1af |
|
Superseded by #33753, which carries the identical e2e change rebased onto current litellm_internal_staging. Continuing the work there |
Pull request was closed
Relevant issues
Linear ticket
Resolves LIT-4546
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
@greptileaito re-request a review after pushing changes)Screenshots / Proof of Fix
Captured at commit
fdec1afd79against a live proxy running the publishedghcr.io/berriai/litellm:main-latestimage, hitting the real OpenAI Responses API and costing real dollars.Bring the suite's compose stack up (namespaced so it does not collide with other local proxies), with
OPENAI_API_KEYintests/e2e/.env:Run the new test against it:
The same behavior by hand against that live proxy. Generate a scoped key, then POST a streaming
/v1/messagesrequest (anthropic format) to the responses-bridged deploymentopenai-responses-codex->openai/gpt-5.3-codex, a Responses-only OpenAI model:Poll
/spend/logsfor that key once the batch write lands; exactly one row appears, carrying a nonzero cost and token counts, the openai provider, and the/v1/messagesbilling identity:custom_llm_provider: openaion agpt-5.3-codexrow that is only reachable via/v1/responses, undercall_type: anthropic_messages, is the combination that proves the Responses adapter served the/v1/messagesrequest. A chat-completions bridge would have failed at OpenAI on an endpoint the model does not expose, so the test cannot pass via the wrong path.The rest of the
tests/e2e/quota_management/spend_tracking/suite was run against the same stack and stays green, except two pre-existing gemini tests that fail only because this box has noGEMINI_API_KEY; thegemini-2.5-flashdeployment then 401s and the router falls back toopenai/gpt-5.5per the compose config, tripping their"gemini-2.5-flash" in modelassertion. That is an environment gap, not a regression from this change, and it is unrelated to the responses-bridge path this PR covers.Type
✅ Test
Changes
Existing in-suite spend coverage only drives streaming
/chat/completions; nothing exercised/v1/messagesthrough the OpenAI Responses adapter. In litellm anycustom_llm_provider == "openai"model called on/v1/messagesis bridged throughLiteLLMMessagesToResponsesAPIHandler(the anthropic-messages -> Responses adapter) unlessuse_chat_completions_url_for_anthropic_messagesis set, so the switch is provider-based rather than a per-model mode flag.The new test
test_streaming_messages_via_responses_bridge_tracks_spendcreates a scoped key, POSTs/v1/messageswithstream: trueto a Responses-only OpenAI deployment, consumes the whole SSE stream, then polls/spend/logsto a deadline and asserts exactly one costed row for the key with nonzero prompt and completion tokens that sum to the total,custom_llm_provider == "openai", and acall_typethat keeps the/v1/messagesbilling identity. Picking a Responses-only model (gpt-5.3-codex) makes the assertion path unambiguous, since the row could not have come from the chat-completions bridge.Supporting changes are a streaming
/v1/messagesmethod on the sharedGateway(so other suites get the route for free) and on the spend suite client, theopenai-responses-codexdeployment added to the inlinedocker-compose.ymlconfig and the suite's driver-model registration, a coverage-registry rowquota_management.spend_tracking.messages_bridge.logs_cost, and the matchingmessages_bridgeentry in the spend_tracking variant vocab. A follow-up commit addscall_typeandcustom_llm_providerto the_summarizediagnostic detail so a failed assertion prints the fields it asserts on.QA runbook
tests/e2e/quota_management/spend_tracking/test_spend_tracking_e2e.py::test_streaming_messages_via_responses_bridge_tracks_spend- a fully consumed streaming/v1/messagesrequest bridged to the OpenAI Responses adapter writes exactly one SpendLogs row with cost and token counts, attributed to the calling keydocker compose -f docker-compose.yml up -d) withOPENAI_API_KEYintests/e2e/.env; the inline config already registersopenai-responses-codex->openai/gpt-5.3-codexcurl -X POST http://localhost:4000/key/generate -H "Authorization: Bearer sk-1234" -d '{"models":[]}'/v1/messageswith that key,"model":"openai-responses-codex","stream":true, and a short message; read the SSE stream tomessage_stopand expect a 200 withcontent-type: text/event-streamGET /spend/logs?api_key=<key>until one row appears; expectspend > 0, nonzeroprompt_tokensandcompletion_tokenssumming tototal_tokens,custom_llm_provider == "openai", andcall_type == "anthropic_messages"Final Attestation