litellm/tests/llm_translation
ishaan-berri 5ed7ec8511
fix(lens): price agent traces by joining gen_ai.response.id to spend logs (#44738)
* fix(lens): price agent traces by joining gen_ai.response.id to spend logs

Trace spend now joins each model call to spend_logs on one key: the
span's response id (gen_ai.response.id or the id the normalizers read
from OpenInference/LangChain output) against spend_logs.response_id or
the upstream id embedded in a managed resp_ id. The litellm.call_id and
traceparent transport join paths and the per-row ownership gate are
removed; the spend SQL still restricts rows to what the reader can see.

A run with some unpriced calls now reports the sum of its priced calls
plus priced_calls, instead of an unknown total.

* test(lens): cover response id spend join and partial trace totals

* chore(lens): regenerate trace types for priced_calls

* feat(lens): show partial run cost as a lower bound with priced call count

* fix(lens): treat litellm.call_id as the same assigned call id for spend joins

The id LiteLLM assigned to a call is either the response id it returned
(gen_ai.response.id -> spend_logs.response_id) or its gateway call id
(litellm.call_id -> spend_logs.litellm_call_id). Both are exact ids the
gateway mints and logs, so the join stays one rule. Transport span
matching and the ownership gate stay removed.

* test(lens): cover litellm.call_id spend joins and restore captured totals

* feat(lens): link each priced model call to its spend log

Spans gain spend_log_request_id, the spend_logs.request_id the call was
priced from, and spend_match, which says whether a model call matched or
why not (no assigned id on the span, no spend log with that id, or an
ambiguous match). A model call span is priced from the same ids as the
run total, so its cost and the total agree.

* test(lens): cover spend log links on model call spans

* chore(lens): regenerate trace types for spend log links

* feat(lens): open the matched spend log from an LLM step

An LLM step's header now shows a Spend log chip with the matched
request id and cost; clicking it opens the request log drawer over the
run, fetched by the exact spend_logs.request_id instead of the span's
own response id. Unpriced steps say why (no assigned id on the span, or
no spend log with it). Tree rows show each model call's cost, and a
partial run cost shows its priced call count inline.

* test(lens): cover the spend log link and unmatched cost reasons

* feat(lens): show the spend log link as a bordered LiteLLM Spend Log button

* feat(lens): add a back link from the spend log drawer to the agent trace

* feat(lens): label the spend log back link Back to Lens trace with the Lens icon

* fix(lens): ignore assigned ids that name no spend log when pricing a call

An id that names no row no longer vetoes the call, so a span carrying
both a response id and a call id still prices from a spend row logged
before litellm_call_id existed. An id naming two or more rows makes the
call ambiguous, and the match reason comes from the same per-id result,
so a single matched row with no cost is reported as matched.

* fix(lens): price a trace only from spend logs in its own team

A reader with several teams could see the same assigned id in another
team's spend log; only rows from the trace's team now price it. The
user and key ownership gate stays removed.

* perf(lens): resolve each model call's spend once per trace

Model call matches are computed once when the trace is resolved and
looked up by span index, instead of scanning the model call list for
every span and walking the graph again for spans, agents and the run
total.

* fix(lens): hide a step's Cost fact only when its spend log link shows the cost

* chore(lens): drop narrative doc comments from the spend join

* fix(lens): price a model call only when its ids agree on one spend log per span

* fix(lens): keep pricing spend logs written before litellm_call_id by their request id

* fix(lens): price every attempt a model call's ids name when they agree
2026-10-06 19:55:26 +00:00
..
fixtures test fix 2025-10-16 18:00:46 -07:00
interactions test: remove 130 legacy tests owned by stronger unit proofs (#44157) 2026-10-02 10:18:50 -07:00
realtime test(e2e): move live-provider legacy tests into tests/e2e (#44120) 2026-10-02 00:02:18 -07:00
reasoning_effort_grid test(reasoning-effort-grid): bump the cell count for the four new Fable 5.1 cells 2026-09-01 18:28:33 +00:00
test-skill [Feat] New API - Claude Skills API (Anthropic) (#17042) 2025-11-24 15:01:40 -08:00
test_llm_response_utils fix(lens): price agent traces by joining gen_ai.response.id to spend logs (#44738) 2026-10-06 19:55:26 +00:00
test_skills_data Remove Apache 2 license from SKILL.md (#22322) 2026-02-27 19:33:55 -08:00
base_audio_transcription_unit_tests.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
base_embedding_unit_tests.py test: stop CI tests from downloading tokenizer files and images (#43257) 2026-09-25 19:27:48 -07:00
base_llm_unit_tests.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
base_rerank_unit_tests.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
conftest.py test(vcr): guard leaked cassette patches and make injected-transport embedding tests immune (#42542) 2026-09-22 14:20:18 -07:00
databricks_config.template.txt test: finish the non-proxy half of tests/test_litellm (#43281) 2026-09-25 22:43:41 -07:00
dog.wav (feat) Support audio param in responses streaming (#6312) 2024-10-18 19:16:14 +05:30
duck.png fix vertex ai multimodal embedding translation (#9471) 2025-03-24 23:23:28 -07:00
gettysburg.wav Litellm dev 12 25 2025 p2 (#7420) 2024-12-25 18:35:34 -08:00
guinea.png fix vertex ai multimodal embedding translation (#9471) 2025-03-24 23:23:28 -07:00
log.xt Litellm dev 04 05 2025 p2 (#9774) 2025-04-07 21:02:52 -07:00
Readme.md fix(tests): stop VCR recording and replaying a test's own localhost upstream (#43346) 2026-09-26 15:49:39 -07:00
test_a2a.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_anthropic_completion.py test: remove 130 legacy tests owned by stronger unit proofs (#44157) 2026-10-02 10:18:50 -07:00
test_aws_base_llm.py Add support for AWS assume_role with a session token 2025-08-23 22:37:21 -07:00
test_azure_agents.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_azure_ai.py test: remove 130 legacy tests owned by stronger unit proofs (#44157) 2026-10-02 10:18:50 -07:00
test_azure_o_series.py test: remove 130 legacy tests owned by stronger unit proofs (#44157) 2026-10-02 10:18:50 -07:00
test_azure_openai.py test: remove 130 legacy tests owned by stronger unit proofs (#44157) 2026-10-02 10:18:50 -07:00
test_bedrock_agentcore.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_bedrock_agents.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_bedrock_anthropic_regression.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_bedrock_common_utils.py style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00
test_bedrock_completion.py test: remove 130 legacy tests owned by stronger unit proofs (#44157) 2026-10-02 10:18:50 -07:00
test_bedrock_dynamic_auth_params_unit_tests.py test(bedrock): point unit tests at model ids still in the cost map (#42606) 2026-09-22 16:04:44 -07:00
test_bedrock_embedding.py test: drop static cost-map value assertions 2026-09-08 02:19:32 +00:00
test_bedrock_govcloud.py test: collapse blank lines left by removed tests 2026-09-08 02:21:55 +00:00
test_bedrock_gpt_oss.py test: remove 130 legacy tests owned by stronger unit proofs (#44157) 2026-10-02 10:18:50 -07:00
test_bedrock_invoke_tests.py test: remove 130 legacy tests owned by stronger unit proofs (#44157) 2026-10-02 10:18:50 -07:00
test_bedrock_llama.py test: remove 130 legacy tests owned by stronger unit proofs (#44157) 2026-10-02 10:18:50 -07:00
test_bedrock_mantle.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_bedrock_moonshot.py test: remove 130 legacy tests owned by stronger unit proofs (#44157) 2026-10-02 10:18:50 -07:00
test_bedrock_nova_embedding.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_bedrock_nova_json.py test: remove 130 legacy tests owned by stronger unit proofs (#44157) 2026-10-02 10:18:50 -07:00
test_cloudflare.py fix(cloudflare): route native Workers AI provider through OpenAI-compatible endpoint (#31053) 2026-06-23 12:09:11 -07:00
test_cohere.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_cometapi_chat_transformation.py test: finish the non-proxy half of tests/test_litellm (#43281) 2026-09-25 22:43:41 -07:00
test_compression.py test: finish the non-proxy half of tests/test_litellm (#43281) 2026-09-25 22:43:41 -07:00
test_convert_dict_to_image.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_crusoe.py test: drop static cost-map value assertions 2026-09-08 02:19:32 +00:00
test_databricks.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_databricks_e2e.py test: finish the non-proxy half of tests/test_litellm (#43281) 2026-09-25 22:43:41 -07:00
test_deepgram.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_deepseek_completion.py Litellm oss staging (#28161) 2026-05-18 16:27:44 -07:00
test_elevenlabs.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_evals_api.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_fireworks_ai_translation.py test: point CircleCI-only suites at models still in the cost map (#42617) 2026-09-22 17:28:34 -07:00
test_gemini.py test: remove 130 legacy tests owned by stronger unit proofs (#44157) 2026-10-02 10:18:50 -07:00
test_gemini_image_usage.py test: point CircleCI-only suites at models still in the cost map (#42617) 2026-09-22 17:28:34 -07:00
test_gigachat.py style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00
test_gpt4o_audio.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_groq.py test: remove 130 legacy tests owned by stronger unit proofs (#44157) 2026-10-02 10:18:50 -07:00
test_hosted_vllm_embedding_e2e.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_huggingface_chat_completion.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_hyperbolic.py test: collapse blank lines left by removed tests 2026-09-08 02:21:55 +00:00
test_infinity.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_jina_ai.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_json_providers.py test: finish the non-proxy half of tests/test_litellm (#43281) 2026-09-25 22:43:41 -07:00
test_lambda_ai.py test: keep the pinning-test removal free of unrelated reformatting 2026-09-18 04:27:28 +00:00
test_langgraph.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_litellm_proxy_provider.py fix(security): remove the publicly known master key from the repo (#44718) 2026-10-06 10:55:24 -07:00
test_minimax_tts.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_mistral_api.py test(e2e): move live-provider legacy tests into tests/e2e (#44120) 2026-10-02 00:02:18 -07:00
test_mistral_audio_transcription_transformation.py test: finish the non-proxy half of tests/test_litellm (#43281) 2026-09-25 22:43:41 -07:00
test_model_cost_map_resilience.py style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00
test_morph.py test: collapse blank lines left by removed tests 2026-09-08 02:21:55 +00:00
test_nvidia_nim.py test(vcr): guard leaked cassette patches and make injected-transport embedding tests immune (#42542) 2026-09-22 14:20:18 -07:00
test_openai.py test: remove 130 legacy tests owned by stronger unit proofs (#44157) 2026-10-02 10:18:50 -07:00
test_openai_o1.py test: remove 130 legacy tests owned by stronger unit proofs (#44157) 2026-10-02 10:18:50 -07:00
test_openai_record_replay_proxy.py Extend the record/replay proxy to chat, embeddings, moderations, rerank, and Anthropic (#29847) 2026-06-06 14:33:42 -07:00
test_openrouter.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_optional_params.py test: point CircleCI-only suites at models still in the cost map (#42617) 2026-09-22 17:28:34 -07:00
test_ovhcloud_audio_transcription_transformation.py test: finish the non-proxy half of tests/test_litellm (#43281) 2026-09-25 22:43:41 -07:00
test_ovhcloud_chat_transformation.py test: finish the non-proxy half of tests/test_litellm (#43281) 2026-09-25 22:43:41 -07:00
test_perplexity_reasoning.py test: keep the pinning-test removal free of unrelated reformatting 2026-09-18 04:27:28 +00:00
test_prompt_caching.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_prompt_factory.py test(llm_translation): expect unpaired server tool calls to replay as tool_use 2026-09-01 12:27:18 -07:00
test_replicate.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_rerank.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_router_llm_translation_tests.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_sambanova_chat_transformation.py style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00
test_skills_api.py test: move tests/test_litellm root and small trees into tests/unit (#43186) 2026-09-25 11:30:43 -07:00
test_snowflake.py Merge main and resolve Snowflake test conflict 2026-03-30 18:06:37 -07:00
test_text_completion.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_text_completion_unit_tests.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_together_ai.py test: remove 130 legacy tests owned by stronger unit proofs (#44157) 2026-10-02 10:18:50 -07:00
test_triton.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_unit_test_bedrock_invoke.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_v0.py test: drop static cost-map value assertions 2026-09-08 02:19:32 +00:00
test_vcr_classification.py fix(security): remove the publicly known master key from the repo (#44718) 2026-10-06 10:55:24 -07:00
test_vcr_conftest_common_banner.py fix(tests/vcr): make Redis cassette cache replay deterministically (zero VCR misses on consecutive runs) (#28826) 2026-05-26 11:30:44 -07:00
test_vcr_filters.py fix(tests/vcr): mint Google OAuth tokens live to prevent stale-token replay (#29229) 2026-05-28 17:12:02 -07:00
test_vcr_leak_guard.py test(vcr): guard leaked cassette patches and make injected-transport embedding tests immune (#42542) 2026-09-22 14:20:18 -07:00
test_vcr_redis_persister.py test(vcr): stop refreshing cassette TTL on read so cassettes lapse after 24h (#29784) 2026-06-05 10:22:41 -07:00
test_vertex_ai_image_generation_transformation.py test: finish the non-proxy half of tests/test_litellm (#43281) 2026-09-25 22:43:41 -07:00
test_voyage_ai.py Merge remote-tracking branch 'origin/litellm_internal_staging' into HEAD 2026-09-10 13:55:11 -07:00
test_watsonx.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_ws_vcr.py test(realtime): record and replay websocket traffic in redis vcr cassettes (#32390) 2026-07-08 00:19:06 -07:00
test_xai.py test: remove 130 legacy tests owned by stronger unit proofs (#44157) 2026-10-02 10:18:50 -07:00
test_xiaomi_mimo.py test: finish the non-proxy half of tests/test_litellm (#43281) 2026-09-25 22:43:41 -07:00

Unit tests for individual LLM providers.

Name of the test file is the name of the LLM provider - e.g. test_openai.py is for OpenAI.

Redis-backed VCR cache

Every test in this directory is auto-decorated with @pytest.mark.vcr (via conftest.py). The first time a test runs we hit the live provider and record the HTTP exchange into Redis under litellm:vcr:cassette:<test_id>. Every subsequent run within 24h replays from Redis without touching the network. The 24h TTL means each new day's first run records again, so upstream API drift surfaces within a day.

The persister, header scrubbing, and 2xx-only filtering are defined in tests/_vcr_redis_persister.py. Files that already use respx (which patches the same httpx transport vcrpy does) are excluded from the auto-marker — see _RESPX_CONFLICTING_FILES in conftest.py.

Requests to localhost, 127.0.0.1, or 0.0.0.0 are never recorded or replayed (ignore_localhost in vcr_config_dict()): a server the test process starts itself on an ephemeral port is not a provider, and a cassette entry for it would replay against whichever later test lands on that port

The same VCR cache is used by other test directories that exercise live provider APIs. The reusable conftest plumbing lives in tests/_vcr_conftest_common.py and is wired into:

  • tests/llm_translation/
  • tests/llm_responses_api_testing/
  • tests/audio_tests/
  • tests/batches_tests/
  • tests/guardrails_tests/
  • tests/image_gen_tests/
  • tests/litellm_utils_tests/
  • tests/local_testing/ (covers local_testing_part1, local_testing_part2, litellm_router_testing, litellm_assistants_api_testing, langfuse_logging_unit_tests)
  • tests/logging_callback_tests/
  • tests/pass_through_unit_tests/
  • tests/router_unit_tests/
  • tests/unified_google_tests/

Test directories that run LiteLLM proxy in Docker (e.g. build_and_test, proxy_logging_guardrails_model_info_tests, proxy_store_model_in_db_tests) are intentionally not included: VCR.py patches the in-process httpx transport, so it cannot intercept the LLM calls that originate inside the Docker container.

Required environment

CASSETTE_REDIS_URL — separate Redis instance from the application Redis (REDIS_URL/REDIS_HOST) so test cassettes are not flushed by proxy tests. Provider credentials (ANTHROPIC_API_KEY, OPENAI_API_KEY, AWS_*, etc.) are needed only on cache-miss (the daily re-record), not on replay.

Flushing the cache

When you want the next run to re-record immediately instead of waiting for the 24h TTL:

make test-llm-translation-flush-vcr-cache

Disabling VCR

Skip the cache entirely (every call goes live, no recording):

LITELLM_VCR_DISABLE=1 uv run pytest tests/llm_translation/test_<file>.py