litellm/tests/test_litellm/integrations
devin-ai-integration[bot] 4bf40c4e8d
fix(logging): stop billing and logging response reads as LLM calls (#36890)
* fix(logging): stop billing and logging response reads as LLM calls

Retrieving, deleting or cancelling a stored response, and vector store management calls, run through the same logging lifecycle as inference. A retrieved response replays the usage of the call that created it, so every read priced it again and wrote a second spend log row for the same tokens. Non-inference calls now cost 0, report no usage, log no placeholder chat message, and get a litellm.responses_management operation name instead of reading as chat.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(responses): keep billing background response jobs after the poll

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(logging): use an empty list for read-call messages

A tuple matches no branch in the loggers that walk this value, so lunary's
parse_messages falls through to clean_message and raises AttributeError on the
success hook. An empty list reads as no messages everywhere: it satisfies the
isinstance(list) checks in newrelic, mlflow and datadog, iterates zero times in
traceloop and helicone, and is what StandardLoggingPayload.messages is typed to
hold. None would be type-legal too but is not iterable, so it trades one crash
for another in mlflow and traceloop.

* fix(otel): stop the legacy emitter reporting replayed tokens on response reads

The zeroing so far lands in the standard logging payload, which the legacy
OpenTelemetry emitter does not read for usage: it takes prompt, completion and
total tokens straight off the response object, so a retrieval span still carried
the token counts of the call that produced the response, and the token usage
histogram still recorded them. That emitter is the default, so the spend row said
zero while the trace said otherwise. The background cost poller keeps its counts,
the same exemption the pricing path already makes.

* fix(logging): keep billing a background response when its retrieval is read

A response created with background=true comes back queued and carries no usage, so
its create bills nothing. The retrieval that first sees the finished job is the only
place that job's tokens are ever visible, and pricing every read at zero therefore
loses the spend outright rather than deduplicating it. On a proxy without the
enterprise cost poller a background job ended up costing $0 end to end.

is_unbilled_non_inference_call now takes the response it is deciding about and treats
a background response the same way it already treats the poller's own read, which is
the same exemption seen from the other side. The legacy OpenTelemetry emitter's time
per output token metric picks up the read gate it was missing, so it stops dividing a
read's latency by the replayed completion token count.

* test(proxy): pass the read response to the non-inference predicate

The poller test called is_unbilled_non_inference_call with the pre-background signature, so it broke when the predicate gained the response it classifies. It now hands the predicate a foreground read, and asserts that the same read is free without the origin stamp, so the stamp is what the test proves.

* fix(otel): stop the v2 metrics recorder reporting replayed tokens on response reads

The v2 span builder sources usage from the standard logging payload, so the
earlier fix already zeroes it there. The metrics recorder reads response_obj
directly, so a responses-management read still recorded the original
generation's tokens into gen_ai.client.token.usage and divided generation time
by them for gen_ai.server.time_per_output_token.

The read still records operation and response duration, under the
litellm.responses_management operation, so it stays observable.

* fix(proxy): keep the response-cost headers on calls priced at zero

Pricing responses reads and vector-store management routes at zero dropped the whole
x-litellm-response-cost family off those replies. The header build reads a falsy zero as
a cost this response never recorded and filters it out, and a call that returns before
pricing stores no cost breakdown for the component headers to read, so a client parsing
the cost off a read got a KeyError where it had previously been handed a number.

Those calls now advertise the family at zero. Retrieving a background response, and the
cost poller's read of one, still report their real cost.

The params-taking form of the predicate moves from opentelemetry into
internal_call_metadata so the proxy header build and the OTEL recorders share one copy.

* fix(proxy): report a zero cost split only under a zero cost total

The component headers were filled from call-type membership alone, while the
total they sit beside keeps its real value when the read priced normally, so a
breakdown that had not landed by the time headers were built could advertise a
real total next to an all-zero split. The split is now reported as zero only
when the total agrees with it, and is otherwise left absent.

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Yucheng Zhu <yucheng@berri.ai>
2026-08-26 18:34:17 -07:00
..
arize test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
azure_storage test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
bitbucket test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
cloudzero test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
code_interpreter_interception feat(sandbox): reuse e2b container across requests when metadata.session_id is set (#31688) 2026-06-30 18:58:09 -07:00
compression_interception feat(spend): track prompt compression saved tokens in daily spend aggregates (#33810) 2026-07-18 17:47:54 -07:00
datadog test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
dotprompt Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_fix_dotprompt_model_swap 2026-08-26 15:13:57 -07:00
focus test: require a match= on broad pytest.raises, and drop duplicate parametrize cases (#37769) 2026-08-20 20:24:49 -07:00
gcs_bucket test: unwind environment writes in tests/test_litellm with monkeypatch (#37806) 2026-08-21 20:28:37 -07:00
gcs_pubsub test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
gitlab test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
helicone test: run the 30 test files stranded in the second mirror (#37595) 2026-08-20 10:59:43 -07:00
langfuse Litellm oss staging 050626 (#29774) 2026-06-05 13:51:51 -07:00
levo test: require a match= on broad pytest.raises, and drop duplicate parametrize cases (#37769) 2026-08-20 20:24:49 -07:00
litellm_agent Agent Builder - support new experimental agent builder, to ensure agents pass compliance checks (#21817) 2026-02-21 15:32:47 -08:00
mavvrik_focus chore: litellm oss staging (#31185) 2026-06-26 09:17:44 -07:00
newrelic perf: build log messages lazily so filtered-out log records cost nothing (#35703) 2026-08-04 04:34:52 +00:00
open_telemetry test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
opik Litellm oss staging 030626 (#29578) 2026-06-03 11:01:51 -07:00
otel fix(logging): stop billing and logging response reads as LLM calls (#36890) 2026-08-26 18:34:17 -07:00
SlackAlerting test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
websearch_interception fix: keep accepting a loop ceiling that spells a whole number 2026-08-22 11:24:22 -07:00
rubrik_test_helpers.py Litellm oss staging 04 21 2026 2 (#26569) 2026-05-20 21:25:19 -07:00
test_agentops.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_cache_control_hook.py test(databricks): pin the cache-control test to the in-repo cost map 2026-08-22 15:51:17 -07:00
test_athina.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_sentinel.py test: remove tests that never execute 2026-08-12 10:45:38 -07:00
test_braintrust_logging.py style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00
test_braintrust_span_name.py style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00
test_custom_guardrail.py fix(guardrails): classify all 4xx HTTPException guardrail blocks as intervened (#33821) 2026-07-27 16:50:13 -07:00
test_custom_guardrail_recursion.py fix: recursive pydantic issue (#19531) 2026-01-22 19:56:41 -08:00
test_custom_prompt_management.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_deepeval.py fix: use fastuuid helper (#14903) 2025-09-25 15:47:01 -07:00
test_galileo.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_guardrail_logging_sync.py fix(guardrails): keep guardrail information in spend logs when the caller sends its own metadata 2026-07-24 16:20:44 -07:00
test_helicone.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_langfuse.py feat(langfuse): support langfuse_environment as a per-key dynamic callback param (#38264) 2026-08-26 16:56:55 -07:00
test_langfuse_otel.py feat(langfuse): support langfuse_environment as a per-key dynamic callback param (#38264) 2026-08-26 16:56:55 -07:00
test_langsmith_init.py fix(langsmith): keep root-run ids self-consistent so batch ingest stops rejecting header-tagged requests (#38116) 2026-08-24 19:47:12 -07:00
test_lunary.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_mlflow.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_openmeter.py test: unwind environment writes in tests/test_litellm with monkeypatch (#37806) 2026-08-21 20:28:37 -07:00
test_opentelemetry.py fix(logging): stop billing and logging response reads as LLM calls (#36890) 2026-08-26 18:34:17 -07:00
test_opentelemetry_dynamic_imports.py Make grpc dependency optional (#19447) 2026-01-20 19:03:52 -08:00
test_opik_utils.py chore(ci): merge oss branch (#33784) 2026-07-17 23:22:13 +00:00
test_otel_guardrail_violation_spans.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_otel_team_attributes_matrix.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_prometheus_api_promql_escape.py fix(prometheus): quote api_key for PromQL string literal in spend lookup 2026-05-01 21:38:19 +00:00
test_prometheus_budget_metric_guard.py fix(prometheus): skip budget metric DB lookups when gauges are NoOpMetric (#32834) 2026-07-10 20:25:47 -07:00
test_prometheus_budget_metrics_db_lookups.py perf(auth): negative-cache missing user/key lookups on the request hot path (#32368) 2026-07-08 09:59:57 +03:00
test_prometheus_budget_metrics_timeout.py feat: litellm oss staging (#31935) 2026-07-03 09:27:31 +05:30
test_prometheus_cache_metrics.py fix(prometheus): populate cache write token metrics for OpenAI-style usage (#34803) 2026-07-27 12:28:19 -07:00
test_prometheus_caller_identity.py test(prometheus): cover caller-identity config failure cases (#38380) 2026-08-26 11:53:49 -07:00
test_prometheus_client_ip_user_agent.py style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00
test_prometheus_custom_metadata_label_counts.py Fix Prometheus remaining metric zero values (#27348) 2026-05-06 17:22:20 -07:00
test_prometheus_end_user_cardinality.py perf: cap Prometheus end-user metric cardinality with TTL + LRU eviction (#27272) 2026-05-06 13:35:13 -07:00
test_prometheus_invalid_key_filtering.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_prometheus_labels.py test: rename tests that a later definition shadowed 2026-08-12 11:15:54 -07:00
test_prometheus_mcp_tool_metrics.py feat(prometheus): expose MCP tool metadata in Prometheus metrics (#31899) 2026-07-02 10:56:35 +03:00
test_prometheus_media_generation_metrics.py feat(prometheus): expose video duration and image count consumption metrics (#33138) 2026-07-13 18:51:13 -07:00
test_prometheus_metric_name_consistency.py style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00
test_prometheus_metrics_endpoint.py perf(prometheus): render /metrics off the event loop and coalesce concurrent scrapes (#37702) 2026-08-20 16:08:22 -07:00
test_prometheus_missing_metrics.py style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00
test_prometheus_none_metadata.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_prometheus_overhead_with_guardrails.py feat(prometheus): add litellm_total_overhead_latency_metric (SDK overhead + guardrails) (#31593) 2026-06-30 17:34:17 +08:00
test_prometheus_queue_guardrail_metrics.py fix(prometheus): fold auth/pre-call time into litellm_request_total_latency_metric (#37958) 2026-08-22 14:25:55 -07:00
test_prometheus_rate_limit_labels.py fix(prometheus): read v3 rate limiter remaining values for per-key model gauges (#33119) 2026-07-13 14:27:56 -07:00
test_prometheus_remaining_tokens_router_fallback.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_prometheus_service_tier_label.py feat(otel): stamp service tier attributes on inference spans (#35679) 2026-08-03 23:10:01 -07:00
test_prometheus_services.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_prometheus_spend_logs_metadata.py fix(prometheus): expose project_alias in custom metadata labels (LIT-3741) (#31784) 2026-07-01 10:44:02 +08:00
test_prometheus_stream_label.py style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00
test_prometheus_token_detail_metrics.py fix(prometheus): populate cache write token metrics for OpenAI-style usage (#34803) 2026-07-27 12:28:19 -07:00
test_prometheus_user_team_metrics.py fix(proxy): count only active users toward license seat limit (#31227) 2026-06-29 18:01:02 -07:00
test_prompt_manager_ssti.py fix(security): sandbox jinja2 in gitlab/arize/bitbucket prompt managers 2026-05-02 09:14:02 +00:00
test_responses_background_cost.py style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00
test_rubrik.py fix(guardrails/rubrik): attribute blocked requests to the caller that made them (#35734) 2026-08-03 19:56:24 -07:00
test_s3.py feat(s3): support SSE-KMS encryption params on both S3 logging paths (#35291) 2026-07-30 21:18:33 -07:00
test_s3_v2.py fix(s3_v2): percent-encode object keys once so signed and sent URLs match (#38005) 2026-08-24 18:16:17 -07:00
test_shadow_eval_logger.py feat(shadow_eval)!: gate the per-key budget on dollar spend instead of turns (#37555) 2026-08-20 14:55:21 -07:00
test_weave_otel.py style: run black formatter on files from main merge 2026-04-17 13:02:59 -07:00