The streamed-id regression test built a bare BaseLiteLLMOpenAIResponseObject with a
top-level id, hitting the wrong _encrypt_response_id branch. A real streamed create
emits ResponseCompletedEvent, whose client-visible id lives on event.response.id, so
the test now drives that production event shape and reads collected[0].response.id.
Mutating the alias route gate or disabling the .response.id encryption branch both
fail the test.
_get_tiered_base_costs documents that tiered pricing is all-or-nothing: a
tier is picked from the request's input tokens, and any rate that tier does
not declare falls back to the tier's own input rate so one request is never
priced from two tiers.
Nothing checked that. Every existing tiered test supplies a fully populated
tier, so the fallbacks were never reached: deleting them from the source
left the whole suite green. The fallbacks are not hypothetical either. Of
the 66 tiered rows shipped in model_prices_and_context_window.json, 54
declare no cache-creation rate and 44 declare no cache-read rate, so the
fallback is what prices their cached tokens today.
Adds three tests on the generic path:
- a tier with no cache rates bills cached and cache-creation tokens at
that tier's input rate, ignoring the model's top-level cache rates
- a tier with no above-1hr rate bills 1h cache writes at the tier's
cache-creation rate rather than zero
- a tier with no input rate is not a priced tier at all, so the model's
flat rates still apply instead of billing input at zero
Test-only change, no source touched.
The streaming security hook only encrypted response ids when request_route
matched "/v1/responses" exactly, so streamed creates on the /openai/v1/responses
and /responses aliases leaked the plain managed id. A second virtual key could
GET, continue, and DELETE another key's response. Normalize the route (strip the
provider prefix, accept the /responses alias) before gating, mirroring the
non-streaming hook which has no route gate.
Now that /v1/messages routes provider failures through exception_type, an
Anthropic permission_error fell through the anthropic branch to the generic
APIConnectionError and reached the client as a 500 where the raw exception
used to answer 403. Map 403 to PermissionDeniedError so the status survives
on every route.
Bugbot Autofix pushed e2e16d7e2d to split 403 out of the shared 401/403 branch in _map_openai_like_exception. That premise was the BaseLLMException fallback, which d2e4e74685 already removed, and remapping 403 for every openai-like provider is a separate contract change, so this merge resolves both files back to the base branch versions
The fallback mapped every unbranched provider error by status code on every route, which changed the exception class and HTTP status for those providers and failed four provider test suites in CI. The /v1/messages handler change alone covers the ticket, since the anthropic branch already maps its errors
* feat(prometheus): configure deployment caller identity
* test(prometheus): satisfy strict caller identity lint
* fix(prometheus): align caller identity on latency metrics
* fix(prometheus): validate caller identity mode before collectors register
Fail config load on an invalid prometheus_deployment_and_latency_caller_identity
value (including null) and on include_labels entries the selected mode removes
from a target metric, instead of booting green with an empty /metrics.
Validate the mode at the top of PrometheusLogger.__init__ so an invalid value
raises before any collector lands in the process-global registry, keeping
retries free of duplicated-timeseries errors. Label-validation errors now name
the mode setting alongside the rejected label.
---------
Co-authored-by: Mark Philipp <mphilipp622@gmail.com>
Co-authored-by: Yucheng Zhu <yucheng@berri.ai>
These four primitives still wrapped their body in React.forwardRef, which
the dashboard has not needed since it moved to React 19: a function
component receives ref as an ordinary prop and the existing {...props}
spread already hands it to the DOM node.
Re-pulling each from base-vega drops the wrapper and its displayName.
These four were picked because the ref plumbing is their only divergence
from current upstream, so the class strings, data-slot values and exports
are untouched and nothing renders differently. The other seven primitives
that still carry forwardRef have also drifted on their class strings, so
re-pulling them would ship a visual change alongside the cleanup and they
are left alone here.
Textarea is the one with real ref call sites, roughly seventeen of them
through react-hook-form's field.ref, and ref-forwarding.test.tsx did not
cover it. Add that case next to the Label, Separator and Skeleton ones
already there.
components/shared/Alert.tsx was base-vega's own alert.tsx copied in by
hand, carrying the same four exports and the same class strings, so
npx shadcn add could never reach it and it would drift from every
upstream fix silently. It also still wrapped each part in forwardRef,
which React 19 no longer needs.
Install the primitive into components/ui/ where the CLI can update it,
and reduce the shared file to a wrapper that adds the four status
variants (info, success, warning, error) the dashboard actually uses on
top of upstream's default and destructive.
Rendered output is unchanged: every variant produces byte-identical
classes, role and data-variant, so all 45 call sites look the same.
The auth handler stamps the requested model's provider onto BudgetExceededError before logging it, which made a key-over-budget 429 look provider-originated and regain its traceback (and an OTel stack_trace) after the provider 4xx carve-out. Any exception whose unified rate-limit category names litellm's own limiter is now a proxy rejection, matching the HTTPException rule.
ProxyRateLimitError derives from HTTPException but carries an llm_provider,
so it read as provider-originated and regained its traceback. Any
HTTPException is a proxy rejection regardless of llm_provider.
The /v1/messages route logs the provider's raw BaseLLMException, which carries
no llm_provider, so its 4xx still counted as an expected client error and lost
its traceback. Treat BaseLLMException as provider-originated as well.
is_expected_client_error treated every HTTP 4xx as a rejection the proxy
issued itself, so a 401 or 429 the provider returned lost its traceback in
the standard logging payload and the OTel error span dropped
litellm.provider.error.stack_trace. An exception carrying llm_provider is
an upstream or deployment problem and keeps its traceback; the proxy's own
pre-call rejections still skip it