The new UsagePageView wiring test selected the user-filter combobox by
walking the DOM, adding testing-library/no-node-access warnings that
pushed the repo-wide count past its eslint-budgets.json ceiling and
failed the "Check lint budgets" step of frontend-lint. Target the
combobox by its placeholder text (a Testing Library query) instead, so
the test adds no node access.
Addresses review findings on the Max Budget tile fix:
- P1: while the selected user's info is loading or errored, the tile
fed `null` and falsely rendered "No limit". Thread the query's
loading/error state through a `budgetLoading` prop so the tile shows
a neutral placeholder until the budget is resolved.
- Add a UsagePageView wiring regression test proving the tile receives
the selected user's budget/duration (not the admin's) and is marked
loading while unresolved, plus a ViewUserSpend loading-state test.
- Remove explanatory source comments per the repo comment policy.
The Usage page Max Budget tile fed `userMaxBudget` from `currentUser`
(the logged-in admin, via a self-only `/v2/user/info`) instead of the
selected user's budget. This made every filtered user display the
admin's cap, showed a number for users with no limit, and never
rendered the budget period.
Fetch the selected user's info via a new `useUserInfo(userId)` hook
(mirroring `useCurrentUser`) and feed its `max_budget` +
`budget_duration` to `ViewUserSpend`. The global view still falls back
to `currentUser`. `ViewUserSpend` gains an optional `budgetDuration`
prop and renders "over <period>" via the canonical
`getBudgetDurationLabel`.
Adds tests for the hook and the period-aware tile rendering.
Trimming the streamed buffer to the retained tail could drop a category
exception phrase that suppresses a later keyword, or the identifier word
of an unfinished sentence that a conditional category pairs with a later
block word. Refuse the cut while either would leave the buffer so the
bounded scan masks and blocks exactly like a scan of the full text
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The streaming post-call hook rescanned the whole accumulated choice buffer on every chunk, so scan cost grew quadratically with output length. Keep a bounded per-choice buffer instead: once it exceeds twice the scan context, drop the head when masking the head and tail separately yields the same output as masking the whole buffer, so no pattern, phrase or exception straddles the cut. Detections from the dropped head are kept and merged, deduplicated, into the final log row
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
A body that serializes litellm_trace_id as null or an empty string carries no identity, so it must not
block the server span fallback. Also mark the nested metadata write as an out-param store
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
UserAPIKeyAuth.parent_otel_span is Any at runtime (opentelemetry is an optional extra), so the OTel
trace-id fallback must only format an int trace id, otherwise an object that merely quacks like a span
turns the whole request into a 500
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
When the otel callback is enabled and the client sends no trace or session identity, the request now inherits the W3C trace id of the proxy's server span as litellm_trace_id and metadata.trace_id. The missing_session_id policy and SpendLogs then persist that value as session_id, so a trace in the OTel backend and its row in the Logs UI carry the same id. Explicit x-litellm-trace-id, traceparent, body metadata.trace_id and litellm_trace_id keep priority.
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>