* feat(proxy): add key_alias, key_hash, requested_model tags to DD APM spans
* refactor(proxy): consolidate DD APM tag helpers into DDSpanTagger class
* refactor(proxy): move DDSpanTagger to its own file litellm/proxy/dd_span_tagger.py
* Add minimal dev_config.yaml for proxy development
Co-authored-by: Ishaan Jaff <ishaan-jaff@users.noreply.github.com>
* feat(ui): wrap left nav items in <a> tags for open-in-new-tab support
Nav items are now rendered as <a> elements with proper href attributes,
enabling right-click → 'Open in new tab', Ctrl/Cmd+click, and
middle-click to open any sidebar page in a new browser tab.
Normal clicks continue to use SPA navigation (no full page reload).
Applied to both leftnav.tsx (query-param routing) and Sidebar2.tsx
(Next.js file-based routing).
Co-authored-by: Ishaan Jaff <ishaan-jaff@users.noreply.github.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Ishaan Jaff <ishaan-jaff@users.noreply.github.com>
* style(ui/): distinguish agent calls from llm calls on ui
* feat: initial grouping working
* feat: set stable contextid for a2a calls - allows for easily passing to downstream llm/mcp calls
* feat(a2a_endpoints.py): fix tracing to avoid recreating logging objects for the same call
allows stable trace id usage
* fix(guardrail_endpoints): handle string ui_type values in _build_field_dict
_build_field_dict unconditionally called .value on ui_type, which crashes
for guardrail configs that use plain strings (e.g. BlockCodeExecutionGuardrailConfigModel
uses "multiselect" and "percentage"). Now checks with hasattr before calling .value.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: propagate trace/session id from headers in MCP server calls
Cherry-picked mcp_server/server.py fixes from 6feb9bab: adds
get_chain_id_from_headers to extract x-litellm-trace-id /
x-litellm-session-id from raw headers, and uses it in call_tool
and list_tools to keep spend logs and tracing consistent with A2A.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Replace plain JsonBlock with CopyableJsonBlock: header row with label
and copy icon (CheckOutlined on success), pre block below — matches
the spend logs RequestResponsePanel pattern
- Key-table rows use the same card chrome for visual consistency
- Remove separate "Changes" section label (now redundant with block headers)
- Table loading spinner replaced with custom Spin + LoadingOutlined
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Table:
- Use DefaultProxyAdminTag for changed_by column
- Remove tooltips on Object ID and API Key columns
- Rename API Key column to API Key (Hash)
- Move pagination controls to upper-right of filter bar; add icon-only refresh button
Drawer:
- Object ID is now copyable
- API Key (Hash) is copyable and no longer truncated
- Changed By uses DefaultProxyAdminTag
- Expand JSON view boxes from max-h-72 to max-h-96
- Remove unnecessary vertical scrollbar (drop overflow-auto h-full from body div;
use flex column layout so header and content flow naturally)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The route-level auth check was blocking internal_user role (team admins)
from reaching /key/{key}/reset_spend because KEY_RESET_SPEND was missing
from key_management_routes. Added it so team admins pass the route check
and the endpoint's existing _check_proxy_or_team_admin_for_key enforces
actual authorization.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The _resolve_model_for_cost_lookup function was only checking
litellm_params.model when resolving model names from the router.
For Azure custom deployment names (e.g. azure/openai/gpt-5.3-codex),
this deployment name doesn't exist in the model cost map, so cost
returned /bin/zsh.
Now checks model_info.base_model and litellm_params.base_model first,
falling back to litellm_params.model only if no base_model is set.
This matches how the router resolves base_model everywhere else.
- Move Reset Spend button after Regenerate Key in header
- Make modal OK button danger style with text "Reset"
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Use TransactionOutlined icon and danger style to match Delete Key button
- Rewrite modal description: remove assumption about key being blocked,
clarify spend history is preserved in logs
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The _safe_get_request_headers caching (commit e7175a52) uses
request.state._cached_headers. With Mock(spec=Request), getattr on
state returns a Mock (truthy), causing RedactedDict to receive a Mock
instead of a dict. Using a real starlette State object fixes this.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Address Greptile review: test_resolve_jwks_url_resolves_oidc_discovery_document
also used the inconsistent patch.object pattern.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Vertex AI / Gemini uses Pydantic's model_json_schema() which omits
additionalProperties: False (Gemini rejects it). The test expected
the same schema for all providers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The patch.object with new_callable=AsyncMock can behave inconsistently
across Python versions, causing mock_response.status_code to return a
MagicMock instead of the assigned value. Direct assignment is simpler
and more reliable.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The CompletionTokensDetailsWrapper type now includes video_tokens field,
but this test's expected dict was not updated to include it.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Gemini API requires role="user" on function_response content blocks
(added in commit 273cf12afa), but these tests were never updated to match.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds a "Reset Spend" button to the key detail view so proxy admins and team
admins can immediately reset a key's spend to $0, unblocking keys that have
hit their budget limit without waiting for the next scheduled budget reset.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix object_team_id + object_key_hash combining incorrectly as OR — each
filter now adds an AND clause wrapping an internal OR over before_value
and updated_values, so both conditions must be satisfied simultaneously
- Rename helper to _build_json_field_or_condition to reflect its purpose
- Remove allTeams from AuditLogsProps and its call site in index.tsx
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Validate anchor is "created_at" in enforced_file_expires_after (matching
user-provided path). Add key existence validation to batch endpoint for
enforced_batch_output_expires_after.
Cleanup per review: this class attribute is no longer used after the
__next__ refactor to queue-based approach.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Two independent fixes for pre-existing test failures on main:
1. Anthropic streaming: The sync __next__ method used a simple
holding_chunk pattern that lost chunks when multiple events needed
to be returned. Refactored to use the same chunk_queue approach as
the async __anext__ method. Also fixed tests that used ModelResponse
(which defaults finish_reason to 'stop') instead of ModelResponseStream.
2. Azure GPT-5.1 logprobs: The base OpenAI class includes logprobs for
gpt-5.1+ models, but Azure hasn't verified support for gpt-5.1.
Added explicit removal of logprobs/top_logprobs for gpt-5.1 (non-5.2)
models in the Azure config.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace **kwargs with explicit tools and system parameters to match
the BaseTokenCounter.count_tokens abstract method signature.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>