* test: drop the cwd-relative sys.path.insert calls from the test suite
TQ003 stands at 1,077 across 1,058 files, and 1,015 of them are the same shape:
sys.path.insert(0, os.path.abspath("../..")) and its deeper siblings. The
argument resolves against the working directory rather than the file, so from
the repo root, where every job runs pytest, it inserts the directory two levels
above the checkout. It has never pointed at litellm. The package is installed
into the environment anyway, which is what actually makes the import work, and
what the rule's message has said all along.
Removing them leaves 1,634 imports of sys and os with no remaining reference,
and those go too, except where another test module imports the name back out of
the file. The rest of TQ003 is 62 call sites that resolve against __file__ or a
variable, which are a different question and are left alone.
Collection is identical either way: 45,871 tests and the same 51 pre-existing
collection errors before and after, and ruff reports no new undefined name.
* test: drop the duplicate imports the sys.path sweep exposed to F811
* test(pre-call-utils): restore the os import the new bedrock tests need
The auto-router savings figure was computed only inside the spend-update
writer, downstream of where logging callbacks consume the standard logging
payload, so Datadog-style callbacks never received it. Compute it once in
the payload builder, stamp it as a top-level payload field beside
cost_breakdown, thread it into the spend log metadata, and have both
spend-writer call sites read the recorded value with recomputation as the
fallback for rows written before the field shipped. Internal sub-calls
(classifier, shadow eval) are never stamped, and a caller-forged metadata
value is discarded by the unconditional overwrite.
Resolves LIT-5973
A name bound twice keeps only the second binding. In `tests/` that is nearly
always a repeated import, harmless but misleading, and the same rule is what
catches the cases that are not harmless: a local that shadows an import the
module still calls, and a second `def test_x` that quietly replaces the first.
311 of the 344 sites were repeated imports and came out with ruff's own fix.
The remaining 33 needed a decision. Four modules imported a name they never
used because a local definition below already shadowed it. Two comprehensions
bound `call` over `unittest.mock.call`, which those modules import and use.
One test rebound the two module handles its nested reload closure had captured.
One class attribute shadowed an unused `status` import.
The load-test fixtures move to a conftest, which is how pytest is meant to share
them, so the test module no longer imports three fixture names it never calls.
The nine `prisma_client` parameters keep a narrow `noqa`: pytest resolves that
fixture by name before the body runs, so the parameter never shadows anything.
`assert False` inside a `try:` raises AssertionError, which the `except
Exception` right below it catches, so several tests reported green no matter
what the code did. `pytest.fail` raises Failed, a BaseException, and escapes.
A bare `a == b` statement is evaluated and discarded. Nine of those sat in
tests, and one was comparing against a model name the router never produces.
Selects B011, B015, B018, PT015, PLR0133 and PLW0127 in ruff-tests.toml
alongside F821, with all 50 existing violations fixed, so no budget file or
ratchet is needed. CI already runs this config over tests/.
* feat(spend): store litellm_call_id on spend logs for DB-to-trace correlation
Successful spend logs keyed request_id to the provider response id while
tracing uses x-litellm-call-id, so a DB row could not be correlated with its
trace; this only worked for failures, where request_id already fell back to
the call id. Add a nullable litellm_call_id column to LiteLLM_SpendLogs,
populate it in get_logging_payload, and surface it in the spend logs read
endpoints so correlation works both directions for successful calls
Fixes LIT-3868
* chore: sync schema.prisma copies from root
* test(spend): cover cache-hit and missing-response-id paths for litellm_call_id
Lock the intended behavior surfaced in review: on a cache hit request_id gets
the uniqueness suffix while litellm_call_id stays the raw call id, and when the
provider returns no id request_id falls back to the call id so both columns
match. Both assertions fail when the populate line is reverted
* test(spend): ignore litellm_call_id in spend logs payload comparisons
get_logging_payload now always writes litellm_call_id, so the full-payload
comparisons in test_spend_management_endpoints.py saw an unexpected key and
failed. litellm_call_id is a per-request runtime uuid like request_id, which
is already ignored, so add it to ignored_keys
* test(logging): ignore litellm_call_id in gcs pubsub spend logs comparison
The gcs pubsub spend logs payload comparison flags any key present in the
actual payload but absent from the golden snapshot. get_logging_payload now
always emits litellm_call_id, a per-request runtime uuid like request_id which
is already ignored, so add it to ignored_keys
* refactor(spend): store litellm_call_id in spend log metadata, drop column
Switch DB-to-trace correlation off a dedicated column and onto the existing
metadata JSON, avoiding a schema migration entirely. litellm_call_id is now
written into spend log metadata (already selected and re-hydrated on the read
paths) instead of a new LiteLLM_SpendLogs column, so the three schema.prisma
copies and the migration are reverted and the read SELECTs go back to their
original form. Correlation is queryable via metadata->>'litellm_call_id'
Trade-off: an unindexed JSON lookup rather than an indexed column; acceptable
for this use case and removes all migration risk
* refactor(spend): thread litellm_call_id into _get_spend_logs_metadata
Set litellm_call_id beside the other computed metadata values inside
_get_spend_logs_metadata rather than mutating clean_metadata back in the
caller, matching how applied_guardrails, cost_breakdown and the rest are
threaded. No behavior change; the value still comes from kwargs with a
litellm_params fallback
---------
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* feat(guardrails): add LLM_AS_A_JUDGE to SupportedGuardrailIntegrations
* feat(types): add EvalVerdict, StandardLoggingEvalInformation; wire eval_information into SpendLogsMetadata
* feat(guardrails): add self-contained llm_as_a_judge guardrail hook
* fix(a2a): filter agent-only litellm_params from acompletion kwargs; pass agent_id into body
* feat(ui): add LLMJudgeFields criteria builder component
* feat(ui): wire LLM-as-a-Judge into add guardrail form
* feat(ui): update EvalViewer — title 'LLM Judge Results', weighted score column, summary row
* fix(ui): wire EvalViewer into LogDetailContent to show LLM judge results on logs page
* fix(guardrails-ui): route llm_as_a_judge to criteria builder step; rename to LiteLLM LLM as a Judge; add litellm logo
* fix(guardrail-viewer): stack lifecycle + eval details vertically to avoid badge overflow in narrow drawer
* fix(guardrail-create): surface config validation errors on create instead of silently orphaning guardrail in DB
* fix(guardrail-registry): hardcode llm_as_a_judge in initializer registry so it loads regardless of package install path
* fix(llm-as-a-judge): fix P1 code quality issues - validate weights/on_failure, guard pre_call, handle multimodal, move imports to module level, fix spurious finally logging
* fix(guardrail_endpoints): use correct PK field in rollback delete and log rollback failure
* fix(llm_as_a_judge): support Pydantic object in _get_litellm_param fallback chain
* fix(LLMJudgeFields): replace @tremor/react Button with antd Button
* fix(llm_as_a_judge): remove dead registry dicts, fix KeyError in prompt builder, set correct status on judge failure
* test(llm_as_a_judge): add unit tests for guardrail hook
* fix(llm_as_a_judge): remove @log_guardrail_information decorator to fix duplicate guardrail_information entries
The decorator and the manual finally block both called add_standard_logging_guardrail_information_to_request_data, producing two entries per request. The decorator also misclassified HTTPException(422) blocks as guardrail_failed_to_respond (it checks for 400). The finally block correctly tracks status throughout, so removing the decorator is sufficient.
* fix(test_gcs_pub_sub): ignore metadata.eval_information in comparison
* fix(test_spend_management): ignore metadata.eval_information in payload comparison
* fix(types/guardrails): add input_type and messages to ApplyGuardrailRequest
* fix(guardrail_endpoints): pass input_type and messages through apply_guardrail endpoint
* fix(guardrail_endpoints): auto-detect post_call guardrails and use input_type=response
* fix(a2a_endpoints): merge agent litellm_params guardrails into data before post_call hooks
* fix(llm_as_a_judge): use float sum with tolerance for weight validation
* fix(guardrail_registry): split long import line for black formatting
* fix(llm_as_a_judge): guard guardrail_name Optional for mypy
* fix(llm_as_a_judge): set guardrail_status=guardrail_intervened when score fails, regardless of on_failure mode
* fix(a2a_endpoints): use try/finally so deferred spend log fires even when guardrail blocks with 422
* fix(litellm_logging): declare _defer_async_logging and _enqueue_deferred_logging on Logging class for mypy
* fix(logging_worker): restore queue.join() in flush() to wait for in-flight callbacks
* add session id in spendLogs
* fix log proxy server request as independant field
* use trace id for SpendLogs
* add _ENTERPRISE_ResponsesSessionHandler
* use _ENTERPRISE_ResponsesSessionHandler
* working session_ids
* working session management
* working session_ids
* test_async_gcs_pub_sub_v1
* test_spend_logs_payload_e2e
* working session_ids
* test_get_standard_logging_payload_trace_id
* test_get_standard_logging_payload_trace_id
* test_gcs_pub_sub.py
* fix all linting errors
* test_spend_logs_payload_with_prompts_enabled
* _ENTERPRISE_ResponsesSessionHandler
* _ENTERPRISE_ResponsesSessionHandler
* expose session id on ui
* get spend logs by session
* add sessionSpendLogsCall
* add session handling
* session logs
* ui session details
* fix on rowExpandDetails
* ui working sessions