* fix: empty guardrails/policies arrays should not trigger enterprise license check (#20304)
The UI sends empty arrays for enterprise-only fields (guardrails, policies,
logging) even when the user has not configured these features. The backend
`is not None` check treated `[]` as a truthy intent to use the feature,
falsely requiring an enterprise license for basic team operations.
Backend: Add `and updated_kv[field] != [] and updated_kv[field] != {}`
guards in `_update_metadata_fields` so empty collections are skipped.
UI: Conditionally omit guardrails, logging, and policies from the
payload when empty instead of defaulting to `[]`.
Fixes#20304
* fix: allow clearing fields with empty collections while skipping enterprise check
Address PR review feedback:
1. Move the empty-collection guard into _update_metadata_field (singular)
so that empty lists/dicts skip only the premium license check but still
get written into metadata. This lets users intentionally clear a
previously-set field (e.g. guardrails: []) without being blocked, while
the UI's default empty arrays still don't trigger a false enterprise
error.
2. Remove sys.path hack from test file; use standard imports that work
with pytest discovery.
3. Add tests verifying that empty collections are moved into metadata
(field clearing works) even though they bypass the premium check.
Fixes#20304
- Add paragraph on release validation, extensibility, and 100% coverage goal
- Include OOMs and CPU regressions as issues surfaced under sustained load
The warning 'Semantic tool filter hook not initialized' was appearing on
every startup, even when the mcp_semantic_tool_filter feature was not
configured. This was confusing for users.
Now the function checks if the feature is actually configured and enabled
before proceeding with initialization. The warning will only appear if
the feature was explicitly enabled but failed to initialize.
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Previously, PR #19818 (via #20205) removed the model_list check entirely,
causing Router to be created even with no models AND no search_tools.
This fix adds back a conditional check that creates the Router only when:
- There are models to route, OR
- There are search_tools configured
This preserves the PR #19818 goal (search-tools-only deployments) while
avoiding unnecessary Router creation when there's nothing to route.
Fixes test_add_and_delete_deployments[0-None]
The three loops in function_setup that called is_async_callable() on every
callback each request were redundant after the first request. Move the
async/sync routing into LoggingCallbackManager.add_litellm_*_callback()
so it happens once at registration time instead of on every request.
Move _get_cost_per_unit() calls for output audio/reasoning/image costs
inside their conditionals — only lookup when we actually have those token types.
Add early-out checks in _calculate_input_cost() to skip calculate_cost_component()
calls when audio_tokens, image_tokens, character_count, image_count,
video_length_seconds, or cache_creation_tokens are 0.
Fixes 15 failing tests in the MCP test suite:
1. **OAuth discoverable endpoints** (test_discoverable_endpoints.py):
- Added autouse fixture to mock IPAddressUtils.get_mcp_client_ip
- This bypasses IP-based access control which was blocking server lookup
- Fixes: test_authorize_*, test_token_*, test_oauth_*, test_register_*
2. **A2A endpoints** (test_a2a_endpoints.py):
- Fixed mock path for add_litellm_data_to_request
- Was patching litellm_pre_call_utils but function is called from common_request_processing
3. **MCP guardrail handler** (test_mcp_guardrail_handler.py):
- Updated tests to match new handler behavior
- Handler now passes tools (not texts) to guardrail
- Handler checks for mcp_tool_name (not messages array)
4. **MCP path-based segregation** (test_user_api_key_auth_mcp.py):
- Added client_ip to get_auth_context unpacking (7 values now)
- get_auth_context was updated to include client_ip
5. **MCP registry** (test_mcp_management_endpoints.py):
- Added mock for get_filtered_registry (not just get_registry)
- Registry endpoint uses get_filtered_registry for IP filtering
Co-authored-by: Shin <shin@openclaw.ai>