Create fresh mock objects within the test instead of reusing mocks
from setUp that have side_effect configured. The setUp's side_effect
on mock_langfuse_client.trace can interfere with return_value settings
when tests try to reset and reconfigure mocks.
Using dedicated mock objects for this test avoids state pollution
from setUp's side_effect configuration and makes the test more
deterministic in parallel execution environments.
Set cached tokenizer config directly and mock both sync and async
tokenizer functions to avoid race conditions when running with
parallel test execution (-n 16).
The issue was that parallel tests could populate the
litellm.known_tokenizer_config cache between clearing it and
when the code checked it. This caused the sync code path to be
used instead of the async path, bypassing the mocked async functions.
Fix:
1. Set cache directly instead of clearing it
2. Also mock sync versions _get_tokenizer_config and _get_chat_template_file
This ensures the test is deterministic regardless of test execution order.
Add Claude Opus 4.6 entries for Anthropic, Bedrock Converse, and Vertex AI.
Align pricing and capability metadata with Anthropic docs, including
long-context rates, above-200k prompt-caching rates, prefill removal,
and tool-use system prompt token counts.
Register the Bedrock Converse model ID in constants and add targeted
tests to validate model map values and converse registration.
* _translate_openai_content_to_anthropic
* test_response_format_consistency
* test fixes unit tests
* test fix
* fix: use dict access for anthropic content blocks in tests (#20447)
The translate_openai_response_to_anthropic method returns dicts, not objects.
Changed .type/.text/.thinking attribute access to dict ['key'] access.
---------
Co-authored-by: shin-bot-litellm <shin-bot-litellm@berri.ai>
* fix(a2a): use text/event-stream SSE format for message/stream endpoint
The A2A gateway's streaming response was using application/x-ndjson
Content-Type and raw NDJSON body format. The A2A protocol spec requires
text/event-stream with SSE framing (data: ...\n\n).
The official a2a-sdk client validates the Content-Type header and raises
SSEError when it doesn't contain text/event-stream.
Changes:
- Changed media_type from application/x-ndjson to text/event-stream
- Updated response body to use SSE framing (data: prefix + \n\n suffix)
- Added tests validating Content-Type and SSE body format
Fixes#20278
* Potential fix for code scanning alert no. 4045: Information exposure through an exception
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
* test(a2a): add manual SSE format validation script
Adds a manual test script that:
1. Starts a real A2A agent on port 10001
2. Starts LiteLLM proxy with the agent registered
3. Makes a streaming request to the proxy's A2A gateway
4. Validates Content-Type header is text/event-stream
5. Validates body uses SSE framing (data: ...\n\n)
Run: python tests/a2a_manual/test_a2a_sse_manual.py
---------
Co-authored-by: shin-bot-litellm <shin-bot-litellm@users.noreply.github.com>
Co-authored-by: Ishaan Jaff <ishaanjaffer0324@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
The unified guardrail's streaming iterator hook processes every Nth
chunk (sampling_rate, default 5). On each sampled chunk it calls
process_output_streaming_response, which combines all accumulated text
into the first chunk and clears all subsequent chunks to "".
The hook then yielded `processed_items[-1]` — the last item, whose
content had been cleared to "". This permanently lost every Nth
chunk's content, causing random missing words/tokens in the client
output (observed in Roo Code, Open WebUI, etc.).
Fix: deep-copy the current chunk before guardrail processing runs,
then yield the original (unmodified) chunk. The guardrail validation
still executes and can block if it detects a problem, but the stream
content is preserved.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* feat(guardrails/): allow custom code execution for guardrails
first step in allowing teams to submit custom code for guardrails
* feat: custom_code_guardrail.md
support passing custom code for guardrails
* feat: initial commit adding ui for custom code guardrails
allows users to write guardrails based on custom code
* feat: expose new test custom code guardrail endpoint
allows ui testing playground to sanity check if guardrail is working as expected
* fix: fix linting errors
* fix: fix max recursion check
* fix: fix linting error
* fix: enforce team MCP permissions when using JWT authentication
Root cause: When JWT auth was used with teams in groups (via team_ids_jwt_field),
the team's MCP permissions were not being enforced because:
1. The default team_allowed_routes did not include mcp_routes
2. allowed_routes_check() failed for MCP endpoints like /mcp/tools/list
3. find_team_with_model_access() skipped the team due to failed route check
4. team_id was None in UserAPIKeyAuth
5. MCPRequestHandler._get_allowed_mcp_servers_for_team() returned empty list
Fix: Add 'mcp_routes' to the default team_allowed_routes in LiteLLM_JWTAuth.
This ensures that teams can access MCP endpoints by default, allowing the
team's MCP server permissions to be properly enforced.
Added tests:
- test_reproduce_jwt_mcp_enforcement_issue: Reproduces the exact bug scenario
- test_verify_mcp_routes_in_default_team_allowed_routes: Verifies fix
- test_mcp_route_check_passes_for_team: Verifies route check works
Co-authored-by: ishaan <ishaan@berri.ai>
* test: add comprehensive E2E tests for JWT + team MCP permission enforcement
Added tests:
- test_e2e_jwt_team_mcp_permissions_enforced: Full E2E test verifying JWT auth
with teams in groups properly sets team_id and MCPRequestHandler returns
the team's MCP servers
- test_e2e_jwt_without_team_no_mcp_servers: Verifies no MCP servers returned
when JWT has no teams
- test_e2e_jwt_team_mcp_key_intersection: Verifies intersection logic when
both key and team have MCP permissions (result = intersection)
These tests verify the complete flow:
1. JWT token with team in groups field
2. JWT auth properly sets team_id on UserAPIKeyAuth
3. MCPRequestHandler.get_allowed_mcp_servers() returns team's MCP servers
4. Key/team permission intersection works correctly
Co-authored-by: ishaan <ishaan@berri.ai>
* test: add simple tests for JWT + MCP permission enforcement
Simple, focused tests that validate:
1. test_simple_jwt_mcp_permissions_enforced: JWT user with team gets team's MCP servers
2. test_simple_jwt_no_team_no_mcp_servers: JWT user without team gets no MCP servers
3. test_simple_jwt_team_id_required_for_mcp_permissions: Verifies team_id is required
4. test_jwt_auth_sets_team_id_for_mcp_route: JWT auth sets team_id for MCP routes
These tests directly verify the core MCP permission enforcement logic works
when using JWT authentication with teams.
Co-authored-by: ishaan <ishaan@berri.ai>
* Add test: MCP route without model still returns team_id
Co-authored-by: ishaan <ishaan@berri.ai>
* Add 2 debug logs for JWT+MCP troubleshooting
- handle_jwt.py: Log team route check result (team_id, route, is_allowed)
- user_api_key_auth_mcp.py: Log team_id when looking up MCP permissions
Co-authored-by: ishaan <ishaan@berri.ai>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: ishaan <ishaan@berri.ai>
AsyncHTTPHandler.__del__ was closing httpx clients still in use by
AsyncOpenAI/AsyncAzureOpenAI due to independent cache lifecycles.
Restores standalone httpx client creation for OpenAI/Azure providers.