From c4e074f27707a509f76801d8532a9982b3643567 Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Tue, 28 Apr 2026 18:53:32 +0530 Subject: [PATCH] feat(proxy): add model-like search tool access control Treat search tools like models by adding team/key allowed_search_tools controls, enforcing search tool authorization checks, and moving credential ownership to search tool config only to avoid exposing secrets in team metadata. Made-with: Cursor --- .../docs/proxy/search_tools_access.md | 439 ++++++++++++ .../out/{404.html => 404/index.html} | 0 .../index.html} | 0 .../index.html} | 0 .../out/{chat.html => chat/index.html} | 0 .../index.html} | 0 .../{budgets.html => budgets/index.html} | 0 .../{caching.html => caching/index.html} | 0 .../index.html} | 0 .../{old-usage.html => old-usage/index.html} | 0 .../{prompts.html => prompts/index.html} | 0 .../index.html} | 0 .../index.html} | 0 .../out/{login.html => login/index.html} | 0 .../out/{logs.html => logs/index.html} | 0 .../{callback.html => callback/index.html} | 0 .../{model-hub.html => model-hub/index.html} | 0 .../{model_hub.html => model_hub/index.html} | 0 .../index.html} | 0 .../index.html} | 0 .../index.html} | 0 .../index.html} | 0 .../index.html} | 0 .../{policies.html => policies/index.html} | 0 .../index.html} | 0 .../index.html} | 0 .../index.html} | 0 .../{ui-theme.html => ui-theme/index.html} | 0 .../out/{skills.html => skills/index.html} | 0 .../out/{teams.html => teams/index.html} | 0 .../{test-key.html => test-key/index.html} | 0 .../index.html} | 0 .../index.html} | 0 .../out/{usage.html => usage/index.html} | 0 .../out/{users.html => users/index.html} | 0 .../index.html} | 0 litellm/proxy/_types.py | 11 +- litellm/proxy/auth/auth_checks.py | 94 +++ .../management_endpoints/team_endpoints.py | 103 --- litellm/proxy/schema.prisma | 2 + litellm/proxy/search_endpoints/endpoints.py | 35 +- litellm/router_utils/search_api_router.py | 63 +- proxy_server.log | 659 ++++++++++++++++++ proxy_server_config.yaml | 232 +----- tests/test_proxy_search_tool_auth.py | 212 ++++++ .../components/modals/CreateTeamModal.tsx | 50 +- .../src/components/OldTeams.tsx | 49 +- .../src/components/networking.tsx | 34 - .../src/components/team/TeamInfo.tsx | 92 ++- 49 files changed, 1597 insertions(+), 478 deletions(-) create mode 100644 docs/my-website/docs/proxy/search_tools_access.md rename litellm/proxy/_experimental/out/{404.html => 404/index.html} (100%) rename litellm/proxy/_experimental/out/{_not-found.html => _not-found/index.html} (100%) rename litellm/proxy/_experimental/out/{api-reference.html => api-reference/index.html} (100%) rename litellm/proxy/_experimental/out/{chat.html => chat/index.html} (100%) rename litellm/proxy/_experimental/out/experimental/{api-playground.html => api-playground/index.html} (100%) rename litellm/proxy/_experimental/out/experimental/{budgets.html => budgets/index.html} (100%) rename litellm/proxy/_experimental/out/experimental/{caching.html => caching/index.html} (100%) rename litellm/proxy/_experimental/out/experimental/{claude-code-plugins.html => claude-code-plugins/index.html} (100%) rename litellm/proxy/_experimental/out/experimental/{old-usage.html => old-usage/index.html} (100%) rename litellm/proxy/_experimental/out/experimental/{prompts.html => prompts/index.html} (100%) rename litellm/proxy/_experimental/out/experimental/{tag-management.html => tag-management/index.html} (100%) rename litellm/proxy/_experimental/out/{guardrails.html => guardrails/index.html} (100%) rename litellm/proxy/_experimental/out/{login.html => login/index.html} (100%) rename litellm/proxy/_experimental/out/{logs.html => logs/index.html} (100%) rename litellm/proxy/_experimental/out/mcp/oauth/{callback.html => callback/index.html} (100%) rename litellm/proxy/_experimental/out/{model-hub.html => model-hub/index.html} (100%) rename litellm/proxy/_experimental/out/{model_hub.html => model_hub/index.html} (100%) rename litellm/proxy/_experimental/out/{model_hub_table.html => model_hub_table/index.html} (100%) rename litellm/proxy/_experimental/out/{models-and-endpoints.html => models-and-endpoints/index.html} (100%) rename litellm/proxy/_experimental/out/{onboarding.html => onboarding/index.html} (100%) rename litellm/proxy/_experimental/out/{organizations.html => organizations/index.html} (100%) rename litellm/proxy/_experimental/out/{playground.html => playground/index.html} (100%) rename litellm/proxy/_experimental/out/{policies.html => policies/index.html} (100%) rename litellm/proxy/_experimental/out/settings/{admin-settings.html => admin-settings/index.html} (100%) rename litellm/proxy/_experimental/out/settings/{logging-and-alerts.html => logging-and-alerts/index.html} (100%) rename litellm/proxy/_experimental/out/settings/{router-settings.html => router-settings/index.html} (100%) rename litellm/proxy/_experimental/out/settings/{ui-theme.html => ui-theme/index.html} (100%) rename litellm/proxy/_experimental/out/{skills.html => skills/index.html} (100%) rename litellm/proxy/_experimental/out/{teams.html => teams/index.html} (100%) rename litellm/proxy/_experimental/out/{test-key.html => test-key/index.html} (100%) rename litellm/proxy/_experimental/out/tools/{mcp-servers.html => mcp-servers/index.html} (100%) rename litellm/proxy/_experimental/out/tools/{vector-stores.html => vector-stores/index.html} (100%) rename litellm/proxy/_experimental/out/{usage.html => usage/index.html} (100%) rename litellm/proxy/_experimental/out/{users.html => users/index.html} (100%) rename litellm/proxy/_experimental/out/{virtual-keys.html => virtual-keys/index.html} (100%) create mode 100644 proxy_server.log create mode 100644 tests/test_proxy_search_tool_auth.py diff --git a/docs/my-website/docs/proxy/search_tools_access.md b/docs/my-website/docs/proxy/search_tools_access.md new file mode 100644 index 0000000000..8c04735363 --- /dev/null +++ b/docs/my-website/docs/proxy/search_tools_access.md @@ -0,0 +1,439 @@ +# Search Tools Access Control + +Control which teams and keys can access specific search tools using model-like allowlists. + +## Overview + +Search tools in LiteLLM Proxy use the same access control pattern as models: + +- **Team-level allowlist**: `allowed_search_tools` on teams +- **Key-level allowlist**: `allowed_search_tools` on keys +- **Tool-only credentials**: API keys stored ONLY in search tool configuration +- **Secure by default**: Credentials never exposed in team/key metadata + +## Quick Start + +### Step 1: Configure Search Tools + +Define search tools in your `proxy_server_config.yaml`: + +```yaml +search_tools: + - search_tool_name: perplexity-search + litellm_params: + search_provider: perplexity + api_key: os.environ/PERPLEXITYAI_API_KEY + + - search_tool_name: tavily-search + litellm_params: + search_provider: tavily + api_key: os.environ/TAVILY_API_KEY + + - search_tool_name: tavily-marketing + litellm_params: + search_provider: tavily + api_key: os.environ/TAVILY_MARKETING_API_KEY + + - search_tool_name: brave-search + litellm_params: + search_provider: brave + api_key: os.environ/BRAVE_API_KEY +``` + +### Step 2: Create Teams with Search Tool Access + +```bash +curl -X POST 'http://localhost:4000/team/new' \ + -H 'Authorization: Bearer ' \ + -H 'Content-Type: application/json' \ + -d '{ + "team_alias": "marketing-team", + "models": ["gpt-4"], + "allowed_search_tools": ["tavily-marketing", "perplexity-search"] + }' +``` + +### Step 3: Generate Keys for Teams + +```bash +curl -X POST 'http://localhost:4000/key/generate' \ + -H 'Authorization: Bearer ' \ + -H 'Content-Type: application/json' \ + -d '{ + "team_id": "", + "models": ["gpt-4"], + "allowed_search_tools": ["tavily-marketing"] + }' +``` + +### Step 4: Use Search Tools + +```bash +curl -X POST 'http://localhost:4000/v1/search/tavily-marketing' \ + -H 'Authorization: Bearer sk-...' \ + -d '{"query": "latest marketing trends"}' +``` + +## Access Control Rules + +### Authorization Flow + +```mermaid +flowchart TD + Request["/v1/search/tavily-search"] --> KeyCheck{Key has access?} + KeyCheck -->|No| Deny403[403 Forbidden] + KeyCheck -->|Yes| TeamCheck{Team has access?} + TeamCheck -->|No| Deny403 + TeamCheck -->|Yes| GetCreds[Get credentials from tool config] + GetCreds --> CallAPI[Call Tavily API] +``` + +### Allowlist Behavior + +| Allowlist Value | Behavior | +|----------------|----------| +| `[]` (empty) | Access to **all** search tools | +| `["tool-a", "tool-b"]` | Access only to `tool-a` and `tool-b` | +| Not set / `null` | Access to **all** search tools | + +### Examples + +**Example 1: Team restricts tools, key further restricts** + +```yaml +# Team allows 3 tools +team.allowed_search_tools = ["tavily", "perplexity", "brave"] + +# Key only allows 1 tool +key.allowed_search_tools = ["tavily"] + +# Result: Key can ONLY access "tavily" +``` + +**Example 2: Empty allowlists grant full access** + +```yaml +# Team allows all +team.allowed_search_tools = [] + +# Key allows all +key.allowed_search_tools = [] + +# Result: Key can access ANY search tool +``` + +**Example 3: Team blocks access even if key allows** + +```yaml +# Team restricts to perplexity +team.allowed_search_tools = ["perplexity"] + +# Key allows tavily +key.allowed_search_tools = ["tavily"] + +# Result: Access DENIED - team doesn't allow tavily +``` + +## Configuration Patterns + +### Pattern 1: Per-Team Search Tool Isolation + +Each team gets their own search tool with dedicated credentials: + +```yaml +search_tools: + - search_tool_name: tavily-team-a + litellm_params: + search_provider: tavily + api_key: os.environ/TAVILY_TEAM_A_KEY + + - search_tool_name: tavily-team-b + litellm_params: + search_provider: tavily + api_key: os.environ/TAVILY_TEAM_B_KEY +``` + +```bash +# Create teams with isolated tools +curl -X POST 'http://localhost:4000/team/new' \ + -H 'Authorization: Bearer ' \ + -d '{ + "team_alias": "team-a", + "allowed_search_tools": ["tavily-team-a"] + }' +``` + +**Benefits**: +- Complete cost isolation (different Tavily accounts) +- Separate rate limits per team +- Independent billing + +### Pattern 2: Shared Tools with Access Control + +Share search tools across teams with allowlist restrictions: + +```yaml +search_tools: + - search_tool_name: tavily-premium + litellm_params: + search_provider: tavily + api_key: os.environ/TAVILY_PREMIUM_KEY + + - search_tool_name: perplexity-standard + litellm_params: + search_provider: perplexity + api_key: os.environ/PERPLEXITY_KEY +``` + +```bash +# Enterprise team gets premium tools +curl -X POST 'http://localhost:4000/team/new' \ + -d '{ + "team_alias": "enterprise", + "allowed_search_tools": ["tavily-premium", "perplexity-standard"] + }' + +# Regular team gets standard tools only +curl -X POST 'http://localhost:4000/team/new' \ + -d '{ + "team_alias": "standard", + "allowed_search_tools": ["perplexity-standard"] + }' +``` + +### Pattern 3: Open Access with Cost Tracking + +Allow all teams to access tools, track costs via `team_id`: + +```yaml +search_tools: + - search_tool_name: tavily-shared + litellm_params: + search_provider: tavily + api_key: os.environ/TAVILY_SHARED_KEY +``` + +```bash +# Teams with empty allowlists can access all tools +curl -X POST 'http://localhost:4000/team/new' \ + -d '{ + "team_alias": "team-a", + "allowed_search_tools": [] + }' +``` + +Query spend by team: + +```sql +SELECT + team_id, + SUM(spend) as total_spend, + COUNT(*) as request_count +FROM "LiteLLM_SpendLogs" +WHERE call_type = 'search' + AND model LIKE 'tavily%' +GROUP BY team_id; +``` + +## Security Model + +### Credentials Storage + +**Secure**: Credentials stored ONLY in search tool configuration + +```yaml +# ✅ CORRECT - Credentials in tool config +search_tools: + - search_tool_name: tavily-search + litellm_params: + api_key: os.environ/TAVILY_API_KEY # Stored here +``` + +**Never in team/key metadata**: + +```json +{ + "team_id": "team-123", + "allowed_search_tools": ["tavily-search"], + "metadata": {} // ✅ No credentials here +} +``` + +### Access Control Only + +Teams and keys only specify **which tools** they can access, not credentials: + +```json +{ + "team": { + "allowed_search_tools": ["tool-a", "tool-b"] // Access control + }, + "key": { + "allowed_search_tools": ["tool-a"] // Access control + } +} +``` + +## API Reference + +### Create Team with Search Tools + +```bash +POST /team/new + +{ + "team_alias": "marketing", + "models": ["gpt-4"], + "allowed_search_tools": ["tavily-search", "perplexity-search"] +} +``` + +### Update Team Search Tools + +```bash +POST /team/update + +{ + "team_id": "team-123", + "allowed_search_tools": ["brave-search"] +} +``` + +### Generate Key with Search Tools + +```bash +POST /key/generate + +{ + "team_id": "team-123", + "models": ["gpt-4"], + "allowed_search_tools": ["tavily-search"] +} +``` + +### List Available Search Tools + +```bash +GET /v1/search/tools + +# Response: +{ + "object": "list", + "data": [ + { + "search_tool_name": "tavily-search", + "search_provider": "tavily" + } + ] +} +``` + +## Cost Attribution + +Search requests are automatically attributed to the team via `team_id` in spend logs: + +```sql +SELECT + team_id, + model as search_tool, + SUM(spend) as cost, + COUNT(*) as requests +FROM "LiteLLM_SpendLogs" +WHERE call_type = 'search' + AND created_at >= NOW() - INTERVAL '30 days' +GROUP BY team_id, model +ORDER BY cost DESC; +``` + +**Example output**: + +| team_id | search_tool | cost | requests | +|---------|-------------|------|----------| +| team-marketing | tavily-search | $45.20 | 904 | +| team-engineering | perplexity-search | $32.15 | 643 | +| team-research | brave-search | $8.50 | 170 | + +## Migration from Legacy Approach + +If you previously stored credentials in team metadata, migrate to the new approach: + +### Before (Insecure) + +```json +{ + "team": { + "metadata": { + "search_provider_config": { + "tavily": {"api_key": "tvly-..."} // ❌ Exposed + } + } + } +} +``` + +### After (Secure) + +```yaml +# 1. Move credentials to search tool config +search_tools: + - search_tool_name: tavily-marketing + litellm_params: + search_provider: tavily + api_key: os.environ/TAVILY_MARKETING_KEY # ✅ Secure + +# 2. Update team with allowlist +team: + allowed_search_tools: ["tavily-marketing"] # ✅ Access control only +``` + +## Troubleshooting + +### 403 Forbidden Error + +```json +{ + "error": "Key not allowed to access search tool: tavily-search. + Allowed search tools: [perplexity-search]" +} +``` + +**Solution**: Add the search tool to key's `allowed_search_tools`: + +```bash +curl -X POST 'http://localhost:4000/key/update' \ + -d '{ + "key": "sk-...", + "allowed_search_tools": ["tavily-search", "perplexity-search"] + }' +``` + +### Search Tool Not Found + +```json +{"error": "Search tool not found: tavily-search"} +``` + +**Solution**: Add the search tool to your `proxy_server_config.yaml`: + +```yaml +search_tools: + - search_tool_name: tavily-search + litellm_params: + search_provider: tavily + api_key: os.environ/TAVILY_API_KEY +``` + +## Best Practices + +1. **Use descriptive tool names**: `tavily-marketing` vs `tavily-1` +2. **Empty allowlists for admins**: Grant full access to admin teams +3. **Restrict by role**: Marketing gets marketing tools, engineering gets code search +4. **Monitor costs per team**: Query spend logs regularly +5. **Rotate credentials in tools**: Update environment variables, not team metadata +6. **Start restrictive**: Add tools to allowlists as needed + +## Related + +- [Search API Reference](./search.md) +- [Team Management](./team_budgets.md) +- [Cost Tracking](./cost_tracking.md) diff --git a/litellm/proxy/_experimental/out/404.html b/litellm/proxy/_experimental/out/404/index.html similarity index 100% rename from litellm/proxy/_experimental/out/404.html rename to litellm/proxy/_experimental/out/404/index.html diff --git a/litellm/proxy/_experimental/out/_not-found.html b/litellm/proxy/_experimental/out/_not-found/index.html similarity index 100% rename from litellm/proxy/_experimental/out/_not-found.html rename to litellm/proxy/_experimental/out/_not-found/index.html diff --git a/litellm/proxy/_experimental/out/api-reference.html b/litellm/proxy/_experimental/out/api-reference/index.html similarity index 100% rename from litellm/proxy/_experimental/out/api-reference.html rename to litellm/proxy/_experimental/out/api-reference/index.html diff --git a/litellm/proxy/_experimental/out/chat.html b/litellm/proxy/_experimental/out/chat/index.html similarity index 100% rename from litellm/proxy/_experimental/out/chat.html rename to litellm/proxy/_experimental/out/chat/index.html diff --git a/litellm/proxy/_experimental/out/experimental/api-playground.html b/litellm/proxy/_experimental/out/experimental/api-playground/index.html similarity index 100% rename from litellm/proxy/_experimental/out/experimental/api-playground.html rename to litellm/proxy/_experimental/out/experimental/api-playground/index.html diff --git a/litellm/proxy/_experimental/out/experimental/budgets.html b/litellm/proxy/_experimental/out/experimental/budgets/index.html similarity index 100% rename from litellm/proxy/_experimental/out/experimental/budgets.html rename to litellm/proxy/_experimental/out/experimental/budgets/index.html diff --git a/litellm/proxy/_experimental/out/experimental/caching.html b/litellm/proxy/_experimental/out/experimental/caching/index.html similarity index 100% rename from litellm/proxy/_experimental/out/experimental/caching.html rename to litellm/proxy/_experimental/out/experimental/caching/index.html diff --git a/litellm/proxy/_experimental/out/experimental/claude-code-plugins.html b/litellm/proxy/_experimental/out/experimental/claude-code-plugins/index.html similarity index 100% rename from litellm/proxy/_experimental/out/experimental/claude-code-plugins.html rename to litellm/proxy/_experimental/out/experimental/claude-code-plugins/index.html diff --git a/litellm/proxy/_experimental/out/experimental/old-usage.html b/litellm/proxy/_experimental/out/experimental/old-usage/index.html similarity index 100% rename from litellm/proxy/_experimental/out/experimental/old-usage.html rename to litellm/proxy/_experimental/out/experimental/old-usage/index.html diff --git a/litellm/proxy/_experimental/out/experimental/prompts.html b/litellm/proxy/_experimental/out/experimental/prompts/index.html similarity index 100% rename from litellm/proxy/_experimental/out/experimental/prompts.html rename to litellm/proxy/_experimental/out/experimental/prompts/index.html diff --git a/litellm/proxy/_experimental/out/experimental/tag-management.html b/litellm/proxy/_experimental/out/experimental/tag-management/index.html similarity index 100% rename from litellm/proxy/_experimental/out/experimental/tag-management.html rename to litellm/proxy/_experimental/out/experimental/tag-management/index.html diff --git a/litellm/proxy/_experimental/out/guardrails.html b/litellm/proxy/_experimental/out/guardrails/index.html similarity index 100% rename from litellm/proxy/_experimental/out/guardrails.html rename to litellm/proxy/_experimental/out/guardrails/index.html diff --git a/litellm/proxy/_experimental/out/login.html b/litellm/proxy/_experimental/out/login/index.html similarity index 100% rename from litellm/proxy/_experimental/out/login.html rename to litellm/proxy/_experimental/out/login/index.html diff --git a/litellm/proxy/_experimental/out/logs.html b/litellm/proxy/_experimental/out/logs/index.html similarity index 100% rename from litellm/proxy/_experimental/out/logs.html rename to litellm/proxy/_experimental/out/logs/index.html diff --git a/litellm/proxy/_experimental/out/mcp/oauth/callback.html b/litellm/proxy/_experimental/out/mcp/oauth/callback/index.html similarity index 100% rename from litellm/proxy/_experimental/out/mcp/oauth/callback.html rename to litellm/proxy/_experimental/out/mcp/oauth/callback/index.html diff --git a/litellm/proxy/_experimental/out/model-hub.html b/litellm/proxy/_experimental/out/model-hub/index.html similarity index 100% rename from litellm/proxy/_experimental/out/model-hub.html rename to litellm/proxy/_experimental/out/model-hub/index.html diff --git a/litellm/proxy/_experimental/out/model_hub.html b/litellm/proxy/_experimental/out/model_hub/index.html similarity index 100% rename from litellm/proxy/_experimental/out/model_hub.html rename to litellm/proxy/_experimental/out/model_hub/index.html diff --git a/litellm/proxy/_experimental/out/model_hub_table.html b/litellm/proxy/_experimental/out/model_hub_table/index.html similarity index 100% rename from litellm/proxy/_experimental/out/model_hub_table.html rename to litellm/proxy/_experimental/out/model_hub_table/index.html diff --git a/litellm/proxy/_experimental/out/models-and-endpoints.html b/litellm/proxy/_experimental/out/models-and-endpoints/index.html similarity index 100% rename from litellm/proxy/_experimental/out/models-and-endpoints.html rename to litellm/proxy/_experimental/out/models-and-endpoints/index.html diff --git a/litellm/proxy/_experimental/out/onboarding.html b/litellm/proxy/_experimental/out/onboarding/index.html similarity index 100% rename from litellm/proxy/_experimental/out/onboarding.html rename to litellm/proxy/_experimental/out/onboarding/index.html diff --git a/litellm/proxy/_experimental/out/organizations.html b/litellm/proxy/_experimental/out/organizations/index.html similarity index 100% rename from litellm/proxy/_experimental/out/organizations.html rename to litellm/proxy/_experimental/out/organizations/index.html diff --git a/litellm/proxy/_experimental/out/playground.html b/litellm/proxy/_experimental/out/playground/index.html similarity index 100% rename from litellm/proxy/_experimental/out/playground.html rename to litellm/proxy/_experimental/out/playground/index.html diff --git a/litellm/proxy/_experimental/out/policies.html b/litellm/proxy/_experimental/out/policies/index.html similarity index 100% rename from litellm/proxy/_experimental/out/policies.html rename to litellm/proxy/_experimental/out/policies/index.html diff --git a/litellm/proxy/_experimental/out/settings/admin-settings.html b/litellm/proxy/_experimental/out/settings/admin-settings/index.html similarity index 100% rename from litellm/proxy/_experimental/out/settings/admin-settings.html rename to litellm/proxy/_experimental/out/settings/admin-settings/index.html diff --git a/litellm/proxy/_experimental/out/settings/logging-and-alerts.html b/litellm/proxy/_experimental/out/settings/logging-and-alerts/index.html similarity index 100% rename from litellm/proxy/_experimental/out/settings/logging-and-alerts.html rename to litellm/proxy/_experimental/out/settings/logging-and-alerts/index.html diff --git a/litellm/proxy/_experimental/out/settings/router-settings.html b/litellm/proxy/_experimental/out/settings/router-settings/index.html similarity index 100% rename from litellm/proxy/_experimental/out/settings/router-settings.html rename to litellm/proxy/_experimental/out/settings/router-settings/index.html diff --git a/litellm/proxy/_experimental/out/settings/ui-theme.html b/litellm/proxy/_experimental/out/settings/ui-theme/index.html similarity index 100% rename from litellm/proxy/_experimental/out/settings/ui-theme.html rename to litellm/proxy/_experimental/out/settings/ui-theme/index.html diff --git a/litellm/proxy/_experimental/out/skills.html b/litellm/proxy/_experimental/out/skills/index.html similarity index 100% rename from litellm/proxy/_experimental/out/skills.html rename to litellm/proxy/_experimental/out/skills/index.html diff --git a/litellm/proxy/_experimental/out/teams.html b/litellm/proxy/_experimental/out/teams/index.html similarity index 100% rename from litellm/proxy/_experimental/out/teams.html rename to litellm/proxy/_experimental/out/teams/index.html diff --git a/litellm/proxy/_experimental/out/test-key.html b/litellm/proxy/_experimental/out/test-key/index.html similarity index 100% rename from litellm/proxy/_experimental/out/test-key.html rename to litellm/proxy/_experimental/out/test-key/index.html diff --git a/litellm/proxy/_experimental/out/tools/mcp-servers.html b/litellm/proxy/_experimental/out/tools/mcp-servers/index.html similarity index 100% rename from litellm/proxy/_experimental/out/tools/mcp-servers.html rename to litellm/proxy/_experimental/out/tools/mcp-servers/index.html diff --git a/litellm/proxy/_experimental/out/tools/vector-stores.html b/litellm/proxy/_experimental/out/tools/vector-stores/index.html similarity index 100% rename from litellm/proxy/_experimental/out/tools/vector-stores.html rename to litellm/proxy/_experimental/out/tools/vector-stores/index.html diff --git a/litellm/proxy/_experimental/out/usage.html b/litellm/proxy/_experimental/out/usage/index.html similarity index 100% rename from litellm/proxy/_experimental/out/usage.html rename to litellm/proxy/_experimental/out/usage/index.html diff --git a/litellm/proxy/_experimental/out/users.html b/litellm/proxy/_experimental/out/users/index.html similarity index 100% rename from litellm/proxy/_experimental/out/users.html rename to litellm/proxy/_experimental/out/users/index.html diff --git a/litellm/proxy/_experimental/out/virtual-keys.html b/litellm/proxy/_experimental/out/virtual-keys/index.html similarity index 100% rename from litellm/proxy/_experimental/out/virtual-keys.html rename to litellm/proxy/_experimental/out/virtual-keys/index.html diff --git a/litellm/proxy/_types.py b/litellm/proxy/_types.py index 7b92af92f2..b0c8f54af4 100644 --- a/litellm/proxy/_types.py +++ b/litellm/proxy/_types.py @@ -1725,7 +1725,7 @@ class TeamBase(LiteLLMPydanticObjectBase): members: list = [] members_with_roles: List[Member] = [] team_member_permissions: Optional[List[str]] = None - metadata: Optional[dict] = None # may include search_provider_config + metadata: Optional[dict] = None tpm_limit: Optional[int] = None rpm_limit: Optional[int] = None @@ -1738,6 +1738,7 @@ class TeamBase(LiteLLMPydanticObjectBase): ) models: list = [] + allowed_search_tools: list = [] # list of search_tool_name values team can access blocked: bool = False router_settings: Optional[dict] = None access_group_ids: Optional[List[str]] = None @@ -1845,13 +1846,6 @@ class UpdateTeamRequest(LiteLLMPydanticObjectBase): ) -class TeamSearchProviderConfigUpdateRequest(LiteLLMPydanticObjectBase): - team_id: str - provider: str - api_key: Optional[str] = None - api_base: Optional[str] = None - - class ResetTeamBudgetRequest(LiteLLMPydanticObjectBase): """ internal type used to reset the budget on a team @@ -2451,6 +2445,7 @@ class LiteLLM_VerificationToken(LiteLLMPydanticObjectBase): max_budget: Optional[float] = None expires: Optional[Union[str, datetime]] = None models: List = [] + allowed_search_tools: List = [] # list of search_tool_name values key can access aliases: Dict = {} config: Dict = {} user_id: Optional[str] = None diff --git a/litellm/proxy/auth/auth_checks.py b/litellm/proxy/auth/auth_checks.py index 840f64cfed..7f37783595 100644 --- a/litellm/proxy/auth/auth_checks.py +++ b/litellm/proxy/auth/auth_checks.py @@ -2962,6 +2962,100 @@ async def can_user_call_model( ) +def _can_object_call_search_tool( + search_tool_name: str, + allowed_search_tools: List[str], + object_type: Literal["key", "team", "project"], +) -> Literal[True]: + """ + Check if an object (key/team/project) can access a specific search tool. + + Similar to _can_object_call_model but for search tools. + + Args: + search_tool_name: The search tool being requested + allowed_search_tools: List of allowed search tool names for this object + object_type: Type of object for error messaging + + Returns: + True if access is allowed + + Raises: + ProxyException if access is denied + """ + # Empty list means all search tools are allowed + if not allowed_search_tools: + return True + + # Check if the search tool is in the allowlist + if search_tool_name in allowed_search_tools: + return True + + # Access denied + raise ProxyException( + message=f"{object_type.capitalize()} not allowed to access search tool: {search_tool_name}. " + f"Allowed search tools: {allowed_search_tools}", + type=ProxyErrorTypes.key_model_access_denied, + param="search_tool_name", + code=status.HTTP_403_FORBIDDEN, + ) + + +async def can_key_call_search_tool( + search_tool_name: str, + valid_token: UserAPIKeyAuth, +) -> Literal[True]: + """ + Check if a key can access a specific search tool. + + Similar to can_key_call_model but for search tools. + + Args: + search_tool_name: The search tool being requested + valid_token: The authenticated key + + Returns: + True if access is allowed + + Raises: + ProxyException if access is denied + """ + return _can_object_call_search_tool( + search_tool_name=search_tool_name, + allowed_search_tools=valid_token.allowed_search_tools or [], + object_type="key", + ) + + +async def can_team_call_search_tool( + search_tool_name: str, + team_object: Optional[LiteLLM_TeamTable], +) -> Literal[True]: + """ + Check if a team can access a specific search tool. + + Similar to can_team_access_model but for search tools. + + Args: + search_tool_name: The search tool being requested + team_object: The team object + + Returns: + True if access is allowed + + Raises: + ProxyException if access is denied + """ + if team_object is None: + return True + + return _can_object_call_search_tool( + search_tool_name=search_tool_name, + allowed_search_tools=team_object.allowed_search_tools or [], + object_type="team", + ) + + async def is_valid_fallback_model( model: str, llm_router: Optional[Router], diff --git a/litellm/proxy/management_endpoints/team_endpoints.py b/litellm/proxy/management_endpoints/team_endpoints.py index abd5239c9a..e29b67724c 100644 --- a/litellm/proxy/management_endpoints/team_endpoints.py +++ b/litellm/proxy/management_endpoints/team_endpoints.py @@ -59,7 +59,6 @@ from litellm.proxy._types import ( TeamMemberUpdateResponse, TeamModelAddRequest, TeamModelDeleteRequest, - TeamSearchProviderConfigUpdateRequest, UpdateTeamRequest, UserAPIKeyAuth, ) @@ -1857,108 +1856,6 @@ async def update_team( # noqa: PLR0915 raise handle_exception_on_proxy(e) -@router.post( - "/team/search_provider_config/update", - tags=["team management"], - dependencies=[Depends(user_api_key_auth)], -) -@management_endpoint_wrapper -async def update_team_search_provider_config( - data: TeamSearchProviderConfigUpdateRequest, - user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth), -): - """ - Update per-team search provider credentials in team metadata. - - Stored under: - metadata.search_provider_config..{api_key, api_base} - """ - from litellm.proxy.auth.auth_checks import _cache_team_object - from litellm.proxy.proxy_server import ( - prisma_client, - proxy_logging_obj, - user_api_key_cache, - ) - - if prisma_client is None: - raise HTTPException( - status_code=500, - detail={"error": CommonProxyErrors.db_not_connected_error.value}, - ) - - provider = data.provider.strip().lower() - if provider == "": - raise HTTPException( - status_code=400, detail={"error": "provider cannot be empty"} - ) - - existing_team_row = await prisma_client.db.litellm_teamtable.find_unique( - where={"team_id": data.team_id} - ) - if existing_team_row is None: - raise HTTPException( - status_code=404, - detail={"error": f"Team not found, passed team_id={data.team_id}"}, - ) - - await _verify_team_access( - team_obj=LiteLLM_TeamTable(**existing_team_row.model_dump()), - user_api_key_dict=user_api_key_dict, - ) - - metadata: Dict[str, Any] = {} - if isinstance(existing_team_row.metadata, dict): - metadata = dict(existing_team_row.metadata) - - search_provider_config = metadata.get("search_provider_config") - if not isinstance(search_provider_config, dict): - search_provider_config = {} - - provider_config = search_provider_config.get(provider) - if not isinstance(provider_config, dict): - provider_config = {} - - if data.api_key is not None: - provider_config["api_key"] = data.api_key - if data.api_base is not None: - provider_config["api_base"] = data.api_base - - if provider_config.get("api_key") in (None, "") and provider_config.get( - "api_base" - ) in ( - None, - "", - ): - search_provider_config.pop(provider, None) - else: - search_provider_config[provider] = provider_config - - metadata["search_provider_config"] = search_provider_config - - team_row: Optional[LiteLLM_TeamTable] = ( - await prisma_client.db.litellm_teamtable.update( - where={"team_id": data.team_id}, - data={"metadata": metadata}, - include={"litellm_model_table": True}, # type: ignore - ) - ) - - if team_row is not None and team_row.team_id is not None: - await _cache_team_object( - team_id=team_row.team_id, - team_table=LiteLLM_TeamTableCachedObj(**team_row.model_dump()), - user_api_key_cache=user_api_key_cache, - proxy_logging_obj=proxy_logging_obj, - ) - - return { - "message": "Team search provider configuration updated", - "team_id": data.team_id, - "provider": provider, - "search_provider_config": search_provider_config, - } - - def _set_budget_reset_at(data: UpdateTeamRequest, updated_kv: dict) -> None: """Set budget_reset_at in updated_kv if budget_duration is provided.""" if data.budget_duration is not None: diff --git a/litellm/proxy/schema.prisma b/litellm/proxy/schema.prisma index 8f07c5afa3..558b4433c2 100644 --- a/litellm/proxy/schema.prisma +++ b/litellm/proxy/schema.prisma @@ -127,6 +127,7 @@ model LiteLLM_TeamTable { soft_budget Float? spend Float @default(0.0) models String[] + allowed_search_tools String[] @default([]) // search_tool_name values team can access max_parallel_requests Int? tpm_limit BigInt? rpm_limit BigInt? @@ -369,6 +370,7 @@ model LiteLLM_VerificationToken { spend Float @default(0.0) expires DateTime? models String[] + allowed_search_tools String[] @default([]) // search_tool_name values key can access aliases Json @default("{}") config Json @default("{}") router_settings Json? @default("{}") diff --git a/litellm/proxy/search_endpoints/endpoints.py b/litellm/proxy/search_endpoints/endpoints.py index ce2949f707..3d79afc7cf 100644 --- a/litellm/proxy/search_endpoints/endpoints.py +++ b/litellm/proxy/search_endpoints/endpoints.py @@ -134,10 +134,41 @@ async def search( if "search_tool_name" in data and data["search_tool_name"]: data["model"] = data["search_tool_name"] + search_tool_name_value = data["search_tool_name"] + + # Authorization check: verify key can access this search tool + from litellm.proxy.auth.auth_checks import ( + can_key_call_search_tool, + can_team_call_search_tool, + get_team_object, + ) + + try: + # Check key-level access + await can_key_call_search_tool( + search_tool_name=search_tool_name_value, + valid_token=user_api_key_dict, + ) + + # Check team-level access if key is associated with a team + if user_api_key_dict.team_id: + team_object = await get_team_object( + team_id=user_api_key_dict.team_id, + user_api_key_cache=None, # Will use internal cache + parent_otel_span=None, + proxy_logging_obj=None, + ) + await can_team_call_search_tool( + search_tool_name=search_tool_name_value, + team_object=team_object, + ) + except Exception as e: + verbose_proxy_logger.error( + f"Search tool authorization failed for {search_tool_name_value}: {str(e)}" + ) + raise if llm_router is not None and hasattr(llm_router, "search_tools"): - search_tool_name_value = data["search_tool_name"] - verbose_proxy_logger.debug( f"Search endpoint - Looking for search_tool_name: {search_tool_name_value}. " f"Available search tools in router: {[tool.get('search_tool_name') for tool in llm_router.search_tools]}. " diff --git a/litellm/router_utils/search_api_router.py b/litellm/router_utils/search_api_router.py index e2e98a6573..4db337a420 100644 --- a/litellm/router_utils/search_api_router.py +++ b/litellm/router_utils/search_api_router.py @@ -56,58 +56,19 @@ class SearchAPIRouter: team_config: Optional[Dict[str, Any]] = None, ) -> Tuple[Optional[str], Optional[str]]: """ - Resolve search provider credentials with precedence: - 1. request metadata.search_provider_config.{provider} - 2. team metadata.search_provider_config.{provider} - 3. default_team_settings.search_provider_config.{provider} - 4. search_tool.litellm_params - 5. env fallback in provider validate_environment() + Resolve search provider credentials from tool configuration ONLY. + + Credentials are stored only in search_tool.litellm_params, never in team/key metadata. + This ensures secrets are not exposed in team/key API responses. + + Args: + tool_litellm_params: Search tool litellm_params with credentials + + Returns: + Tuple of (api_key, api_base) from tool configuration """ - resolved_api_key: Optional[str] = None - resolved_api_base: Optional[str] = None - - request_provider_config = {} - if isinstance(request_metadata, dict): - search_provider_config = request_metadata.get("search_provider_config") - if isinstance(search_provider_config, dict): - request_provider_config = search_provider_config.get( - search_provider, {} - ) - - team_provider_config = {} - if isinstance(team_metadata, dict): - search_provider_config = team_metadata.get("search_provider_config") - if isinstance(search_provider_config, dict): - team_provider_config = search_provider_config.get(search_provider, {}) - - team_settings_provider_config = {} - if isinstance(team_config, dict): - search_provider_config = team_config.get("search_provider_config") - if isinstance(search_provider_config, dict): - team_settings_provider_config = search_provider_config.get( - search_provider, {} - ) - - if isinstance(request_provider_config, dict): - resolved_api_key = request_provider_config.get("api_key") - resolved_api_base = request_provider_config.get("api_base") - - if resolved_api_key is None and isinstance(team_provider_config, dict): - resolved_api_key = team_provider_config.get("api_key") - if resolved_api_base is None and isinstance(team_provider_config, dict): - resolved_api_base = team_provider_config.get("api_base") - - if resolved_api_key is None and isinstance(team_settings_provider_config, dict): - resolved_api_key = team_settings_provider_config.get("api_key") - if resolved_api_base is None and isinstance( - team_settings_provider_config, dict - ): - resolved_api_base = team_settings_provider_config.get("api_base") - - if resolved_api_key is None: - resolved_api_key = tool_litellm_params.get("api_key") - if resolved_api_base is None: - resolved_api_base = tool_litellm_params.get("api_base") + resolved_api_key: Optional[str] = tool_litellm_params.get("api_key") + resolved_api_base: Optional[str] = tool_litellm_params.get("api_base") return resolved_api_key, resolved_api_base diff --git a/proxy_server.log b/proxy_server.log new file mode 100644 index 0000000000..381b28a784 --- /dev/null +++ b/proxy_server.log @@ -0,0 +1,659 @@ +:128: RuntimeWarning: 'litellm.proxy.proxy_cli' found in sys.modules after import of package 'litellm.proxy', but prior to execution of 'litellm.proxy.proxy_cli'; this may result in unpredictable behaviour +2026-04-28 18:52:10,288 - litellm_proxy_extras - INFO - Running prisma migrate deploy +2026-04-28 18:52:13,736 - litellm_proxy_extras - INFO - prisma migrate deploy stdout: Environment variables loaded from ../../.env +Prisma schema loaded from schema.prisma +Datasource "client": PostgreSQL database "litellm", schema "public" at "localhost:5432" + +118 migrations found in prisma/migrations + + +No pending migrations to apply. + +2026-04-28 18:52:13,737 - litellm_proxy_extras - INFO - prisma migrate deploy completed +2026-04-28 18:52:13,737 - litellm_proxy_extras - INFO - No pending migrations — skipping post-migration sanity check +INFO: Started server process [19856] +INFO: Waiting for application startup. +18:52:13 - LiteLLM Proxy:DEBUG: proxy_server.py:803 - litellm.proxy.proxy_server.py::startup() - CHECKING PREMIUM USER - True +18:52:13 - LiteLLM Proxy:DEBUG: proxy_server.py:816 - worker_config: {"model": null, "alias": null, "api_base": null, "api_version": "2025-02-01-preview", "debug": false, "detailed_debug": true, "temperature": null, "max_tokens": null, "request_timeout": null, "max_budget": null, "telemetry": true, "drop_params": false, "add_function_to_prompt": false, "headers": null, "save": false, "config": "proxy_server_config.yaml", "use_queue": false} +LiteLLM Proxy: Using default (v1) migration resolver. If your deployment has seen schema thrashing during rolling deploys, try --use_v2_migration_resolver (safer: avoids the diff-and-force recovery that caused the thrash). + + ██╗ ██╗████████╗███████╗██╗ ██╗ ███╗ ███╗ + ██║ ██║╚══██╔══╝██╔════╝██║ ██║ ████╗ ████║ + ██║ ██║ ██║ █████╗ ██║ ██║ ██╔████╔██║ + ██║ ██║ ██║ ██╔══╝ ██║ ██║ ██║╚██╔╝██║ + ███████╗██║ ██║ ███████╗███████╗███████╗██║ ╚═╝ ██║ + ╚══════╝╚═╝ ╚═╝ ╚══════╝╚══════╝╚══════╝╚═╝ ╚═╝ + +18:52:13 - LiteLLM:DEBUG: utils.py:5620 - checking potential_model_names in litellm.model_cost: {'split_model': '170fb9c8e18f87663825b69e7e54393b7a3392d1ecbfb0d6a8a543f0723173fd', 'combined_model_name': '170fb9c8e18f87663825b69e7e54393b7a3392d1ecbfb0d6a8a543f0723173fd', 'stripped_model_name': '170fb9c8e18f87663825b69e7e54393b7a3392d1ecbfb0d6a8a543f0723173fd', 'combined_stripped_model_name': '170fb9c8e18f87663825b69e7e54393b7a3392d1ecbfb0d6a8a543f0723173fd', 'custom_llm_provider': None} +18:52:13 - LiteLLM:DEBUG: utils.py:5921 - Error getting model info: This model isn't mapped yet. Add it here - https://github.com/BerriAI/litellm/blob/main/model_prices_and_context_window.json +18:52:13 - LiteLLM:DEBUG: utils.py:2900 - added/updated model=170fb9c8e18f87663825b69e7e54393b7a3392d1ecbfb0d6a8a543f0723173fd in litellm.model_cost: 170fb9c8e18f87663825b69e7e54393b7a3392d1ecbfb0d6a8a543f0723173fd +18:52:13 - LiteLLM:DEBUG: utils.py:5620 - checking potential_model_names in litellm.model_cost: {'split_model': 'gpt-5.3-codex', 'combined_model_name': 'openai/gpt-5.3-codex', 'stripped_model_name': 'gpt-5.3-codex', 'combined_stripped_model_name': 'openai/gpt-5.3-codex', 'custom_llm_provider': 'openai'} +18:52:13 - LiteLLM:DEBUG: utils.py:5620 - checking potential_model_names in litellm.model_cost: {'split_model': 'gpt-5.3-codex', 'combined_model_name': 'openai/gpt-5.3-codex', 'stripped_model_name': 'gpt-5.3-codex', 'combined_stripped_model_name': 'openai/gpt-5.3-codex', 'custom_llm_provider': 'openai'} +18:52:13 - LiteLLM:DEBUG: utils.py:5620 - checking potential_model_names in litellm.model_cost: {'split_model': 'gpt-5.3-codex', 'combined_model_name': 'openai/gpt-5.3-codex', 'stripped_model_name': 'openai/gpt-5.3-codex', 'combined_stripped_model_name': 'openai/gpt-5.3-codex', 'custom_llm_provider': 'openai'} +18:52:13 - LiteLLM:DEBUG: utils.py:2900 - added/updated model=gpt-5.3-codex in litellm.model_cost: gpt-5.3-codex +18:52:13 - LiteLLM Router:DEBUG: router.py:7223 - +Initialized Model List ['gpt-5.3-codex'] +18:52:13 - LiteLLM Router:INFO: router.py:812 - Routing strategy: simple-shuffle +18:52:13 - LiteLLM Proxy:DEBUG: proxy_server.py:3915 - Policy engine: no policies in config, skipping +18:52:13 - LiteLLM Proxy:DEBUG: utils.py:2460 - Creating Prisma Client.. +18:52:13 - LiteLLM Proxy:DEBUG: utils.py:2527 - Success - Created Prisma Client +18:52:13 - LiteLLM Proxy:DEBUG: utils.py:3745 - PrismaClient: connect() called Attempting to Connect to DB +18:52:13 - LiteLLM Proxy:DEBUG: utils.py:3749 - PrismaClient: DB not connected, Attempting to Connect to DB +query-engine ac9d7041ed77bcc8a8dbd2ab6616b39013829574 +18:52:13 - LiteLLM Proxy:DEBUG: prisma_client.py:247 - IAM token auth not enabled, skipping token refresh task +18:52:13 - LiteLLM Proxy:INFO: utils.py:4307 - Started Prisma DB health watchdog (interval=30s, reconnect_cooldown=15s, probe_timeout=5.0s, reconnect_timeout=30.0s) +18:52:13 - LiteLLM Proxy:INFO: utils.py:4062 - Found prisma-query-engine at PID 20355. +18:52:13 - LiteLLM Proxy:INFO: utils.py:4066 - Watching engine PID 20355 via waitpid thread. +18:52:13 - LiteLLM:DEBUG: logging_callback_manager.py:336 - Custom logger of type SkillsInjectionHook, key: SkillsInjectionHook-max_iterations=10-sandbox_timeout=120-message_logging=True-turn_off_message_logging=False already exists in [, , , , , , ], not adding again.. +18:52:13 - LiteLLM Proxy:DEBUG: proxy_server.py:895 - About to initialize semantic tool filter +18:52:13 - LiteLLM Proxy:DEBUG: proxy_server.py:898 - litellm_settings keys = [] +18:52:13 - LiteLLM Proxy:DEBUG: proxy_server.py:6220 - Semantic tool filter not configured or not enabled, skipping initialization +18:52:13 - LiteLLM Proxy:DEBUG: proxy_server.py:905 - After semantic tool filter initialization +18:52:13 - LiteLLM Proxy:DEBUG: proxy_server.py:919 - prisma_client: +18:52:13 - LiteLLM Proxy:INFO: proxy_server.py:6467 - Tag spend update job scheduled at 25s interval (2.3x main job interval) +18:52:13 - LiteLLM Proxy:DEBUG: hanging_request_check.py:148 - Checking for hanging requests.... +18:52:13 - LiteLLM Proxy:INFO: utils.py:5083 - Starting spend logs queue monitor (threshold: 100, poll_interval: 2.0s) +18:52:14 - LiteLLM Proxy:INFO: utils.py:2634 - All necessary views exist! +18:52:14 - LiteLLM Proxy:INFO: proxy_server.py:874 - Password migration: No plaintext passwords found +18:52:14 - LiteLLM Proxy:DEBUG: proxy_server.py:4256 - len new_models: 2 +18:52:14 - LiteLLM:DEBUG: utils.py:5620 - checking potential_model_names in litellm.model_cost: {'split_model': '88d4dde8-817a-4c20-9bec-442961096d25', 'combined_model_name': '88d4dde8-817a-4c20-9bec-442961096d25', 'stripped_model_name': '88d4dde8-817a-4c20-9bec-442961096d25', 'combined_stripped_model_name': '88d4dde8-817a-4c20-9bec-442961096d25', 'custom_llm_provider': None} +18:52:14 - LiteLLM:DEBUG: utils.py:5921 - Error getting model info: This model isn't mapped yet. Add it here - https://github.com/BerriAI/litellm/blob/main/model_prices_and_context_window.json +18:52:14 - LiteLLM:DEBUG: utils.py:2900 - added/updated model=88d4dde8-817a-4c20-9bec-442961096d25 in litellm.model_cost: 88d4dde8-817a-4c20-9bec-442961096d25 +18:52:14 - LiteLLM:DEBUG: utils.py:5620 - checking potential_model_names in litellm.model_cost: {'split_model': '2ab3179b-62e9-4720-9ba7-0a2f12536cfa', 'combined_model_name': '2ab3179b-62e9-4720-9ba7-0a2f12536cfa', 'stripped_model_name': '2ab3179b-62e9-4720-9ba7-0a2f12536cfa', 'combined_stripped_model_name': '2ab3179b-62e9-4720-9ba7-0a2f12536cfa', 'custom_llm_provider': None} +18:52:14 - LiteLLM:DEBUG: utils.py:5921 - Error getting model info: This model isn't mapped yet. Add it here - https://github.com/BerriAI/litellm/blob/main/model_prices_and_context_window.json +18:52:14 - LiteLLM:DEBUG: utils.py:2900 - added/updated model=2ab3179b-62e9-4720-9ba7-0a2f12536cfa in litellm.model_cost: 2ab3179b-62e9-4720-9ba7-0a2f12536cfa +18:52:14 - LiteLLM Proxy:DEBUG: proxy_server.py:5461 - guardrails from the DB [] +18:52:14 - LiteLLM Proxy:INFO: policy_registry.py:577 - Synced 0 production policies and 0 draft/published (by ID) from DB to in-memory registry +18:52:14 - LiteLLM Proxy:INFO: attachment_registry.py:481 - Synced 0 attachments from DB to in-memory registry +18:52:14 - LiteLLM Proxy:DEBUG: proxy_server.py:5497 - Successfully synced policies and attachments from DB +18:52:14 - LiteLLM:DEBUG: mcp_server_manager.py:2644 - Loading MCP servers from database into registry... +18:52:14 - LiteLLM:INFO: mcp_server_manager.py:2664 - Found 1 MCP servers in database +18:52:14 - LiteLLM:DEBUG: mcp_server_manager.py:2688 - Building server from DB: 28a195c6-0224-4765-af9b-46f7a7f65ccb (deepwiki) +18:52:14 - LiteLLM:DEBUG: mcp_server_manager.py:2697 - MCP registry refreshed (1 servers in registry) +18:52:14 - LiteLLM Proxy:DEBUG: pass_through_endpoints.py:2409 - initializing pass through endpoints +18:52:14 - LiteLLM Proxy:DEBUG: prompt_registry.py:54 - Discovering prompt integrations in: litellm.integrations.weave +18:52:14 - LiteLLM Proxy:DEBUG: prompt_registry.py:54 - Discovering prompt integrations in: litellm.integrations.litellm_agent +18:52:14 - LiteLLM Proxy:DEBUG: prompt_registry.py:54 - Discovering prompt integrations in: litellm.integrations.dotprompt +18:52:14 - LiteLLM Proxy:DEBUG: prompt_registry.py:65 - Found prompt_initializer_registry in litellm.integrations.dotprompt: ['dotprompt'] +18:52:14 - LiteLLM Proxy:DEBUG: prompt_registry.py:54 - Discovering prompt integrations in: litellm.integrations.gitlab +18:52:14 - LiteLLM Proxy:DEBUG: prompt_registry.py:65 - Found prompt_initializer_registry in litellm.integrations.gitlab: ['gitlab'] +18:52:14 - LiteLLM Proxy:DEBUG: prompt_registry.py:54 - Discovering prompt integrations in: litellm.integrations.azure_sentinel +18:52:14 - LiteLLM Proxy:DEBUG: prompt_registry.py:54 - Discovering prompt integrations in: litellm.integrations.arize +18:52:14 - LiteLLM Proxy:DEBUG: prompt_registry.py:65 - Found prompt_initializer_registry in litellm.integrations.arize: ['arize_phoenix'] +18:52:14 - LiteLLM Proxy:DEBUG: prompt_registry.py:54 - Discovering prompt integrations in: litellm.integrations.agentops +18:52:14 - LiteLLM Proxy:DEBUG: prompt_registry.py:54 - Discovering prompt integrations in: litellm.integrations.compression_interception +18:52:14 - LiteLLM Proxy:DEBUG: prompt_registry.py:54 - Discovering prompt integrations in: litellm.integrations.focus +18:52:14 - LiteLLM Proxy:DEBUG: prompt_registry.py:54 - Discovering prompt integrations in: litellm.integrations.prometheus_helpers +18:52:14 - LiteLLM Proxy:DEBUG: prompt_registry.py:54 - Discovering prompt integrations in: litellm.integrations.generic_prompt_management +18:52:14 - LiteLLM Proxy:DEBUG: prompt_registry.py:65 - Found prompt_initializer_registry in litellm.integrations.generic_prompt_management: ['generic_prompt_management'] +18:52:14 - LiteLLM Proxy:DEBUG: prompt_registry.py:54 - Discovering prompt integrations in: litellm.integrations.levo +18:52:14 - LiteLLM Proxy:DEBUG: prompt_registry.py:54 - Discovering prompt integrations in: litellm.integrations.websearch_interception +18:52:14 - LiteLLM Proxy:DEBUG: prompt_registry.py:54 - Discovering prompt integrations in: litellm.integrations.deepeval +18:52:14 - LiteLLM Proxy:DEBUG: prompt_registry.py:54 - Discovering prompt integrations in: litellm.integrations.bitbucket +18:52:14 - LiteLLM Proxy:DEBUG: prompt_registry.py:65 - Found prompt_initializer_registry in litellm.integrations.bitbucket: ['bitbucket'] +18:52:14 - LiteLLM Proxy:DEBUG: prompt_registry.py:54 - Discovering prompt integrations in: litellm.integrations.vantage +18:52:14 - LiteLLM Proxy:DEBUG: prompt_registry.py:76 - Discovered 5 prompt initializers: ['dotprompt', 'gitlab', 'arize_phoenix', 'generic_prompt_management', 'bitbucket'] +18:52:14 - LiteLLM Proxy:INFO: proxy_server.py:5640 - Loading 0 search tool(s) from database into router +18:52:14 - LiteLLM Proxy:DEBUG: proxy_server.py:5660 - No search tools found in database, keeping config-loaded search tools (if any) +18:52:14 - LiteLLM Proxy:INFO: tool_registry_writer.py:329 - ToolPolicyRegistry: synced 17 tool policies and 1 object permissions from DB +18:52:14 - LiteLLM Proxy:DEBUG: proxy_server.py:5517 - Successfully synced tool policy from DB +18:52:14 - LiteLLM:DEBUG: focus_logger.py:167 - No Focus export logger registered; skipping scheduler +18:52:14 - LiteLLM Proxy:DEBUG: proxy_server.py:6759 - key_rotation_enabled: False +18:52:14 - LiteLLM Proxy:DEBUG: proxy_server.py:6793 - Key rotation disabled (set LITELLM_KEY_ROTATION_ENABLED=true to enable) +18:52:14 - LiteLLM Proxy:DEBUG: proxy_server.py:6824 - expired_ui_session_key_cleanup_enabled: False +18:52:14 - LiteLLM Proxy:DEBUG: proxy_server.py:6869 - Expired UI session key cleanup disabled (set LITELLM_EXPIRED_UI_SESSION_KEY_CLEANUP_ENABLED=true to enable) +18:52:14 - LiteLLM Proxy:INFO: proxy_server.py:6622 - Batch cost check job scheduled successfully +18:52:14 - LiteLLM Proxy:INFO: proxy_server.py:6653 - Responses cost check job scheduled successfully +18:52:14 - LiteLLM Proxy:INFO: proxy_server.py:6672 - APScheduler started with memory leak prevention settings: removed jitter, increased intervals, misfire_grace_time=3600 +18:52:14 - LiteLLM Proxy:DEBUG: proxy_server.py:7036 - LiteLLM: Pyroscope profiling is disabled (set LITELLM_ENABLE_PYROSCOPE=true to enable). +18:52:14 - LiteLLM Proxy:INFO: proxy_server.py:755 - SESSION REUSE: Created shared aiohttp session for connection pooling (ID: 6165409104, limit=1000, limit_per_host=500) +INFO: Application startup complete. +INFO: Uvicorn running on http://0.0.0.0:4000 (Press CTRL+C to quit) +18:52:21 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/organization/list +18:52:21 - LiteLLM:DEBUG: user_api_key_auth.py:1023 - api key not found in cache. +18:52:21 - LiteLLM Proxy:DEBUG: utils.py:3061 - PrismaClient: find_unique for token: 00f60cfa9df317dade7cb93c0bdb83b44250c865daf6920ea0de433d523a894e +18:52:21 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/team/list +18:52:21 - LiteLLM:DEBUG: user_api_key_auth.py:1023 - api key not found in cache. +18:52:21 - LiteLLM Proxy:DEBUG: utils.py:3061 - PrismaClient: find_unique for token: 00f60cfa9df317dade7cb93c0bdb83b44250c865daf6920ea0de433d523a894e +18:52:21 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/tag/list +18:52:21 - LiteLLM:DEBUG: user_api_key_auth.py:1023 - api key not found in cache. +18:52:21 - LiteLLM Proxy:DEBUG: utils.py:3061 - PrismaClient: find_unique for token: 00f60cfa9df317dade7cb93c0bdb83b44250c865daf6920ea0de433d523a894e +18:52:21 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/key/list +18:52:21 - LiteLLM:DEBUG: user_api_key_auth.py:1023 - api key not found in cache. +18:52:21 - LiteLLM Proxy:DEBUG: utils.py:3061 - PrismaClient: find_unique for token: 00f60cfa9df317dade7cb93c0bdb83b44250c865daf6920ea0de433d523a894e + +#------------------------------------------------------------# +# # +# 'The thing I wish you improved is...' # +# https://github.com/BerriAI/litellm/issues/new # +# # +#------------------------------------------------------------# + + Thank you for using LiteLLM! - Krrish & Ishaan + + + +Give Feedback / Get Help: https://github.com/BerriAI/litellm/issues/new + + +LiteLLM: Proxy initialized with Config, Set models: + gpt-5.3-codex +INFO: 127.0.0.1:65291 - "GET /project/list HTTP/1.1" 404 Not Found +INFO: 127.0.0.1:65293 - "HEAD / HTTP/1.1" 200 OK +INFO: 127.0.0.1:65293 - "GET /__next._tree.txt?_rsc=1r34m HTTP/1.1" 404 Not Found +18:52:21 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:22:21.984645+00:00 +18:52:21 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:22:21.987707+00:00 +18:52:21 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:22:21.988286+00:00 +18:52:21 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:22:21.988897+00:00 +18:52:21 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +18:52:22 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +18:52:22 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +18:52:22 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +18:52:22 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +18:52:22 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +18:52:22 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +18:52:22 - LiteLLM Proxy:DEBUG: key_management_endpoints.py:4526 - Entering list_keys function +18:52:22 - LiteLLM Proxy:DEBUG: key_management_endpoints.py:4950 - Filter conditions: {'OR': [{'team_id': None}, {'team_id': {'not': 'litellm-dashboard'}}]} +18:52:22 - LiteLLM Proxy:DEBUG: key_management_endpoints.py:5020 - Pagination: skip=0, take=50 +18:52:22 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +INFO: 127.0.0.1:65283 - "GET /organization/list HTTP/1.1" 200 OK +18:52:22 - LiteLLM Proxy:DEBUG: key_management_endpoints.py:5062 - Fetched 4 keys +18:52:22 - LiteLLM Proxy:DEBUG: key_management_endpoints.py:5074 - Total count of keys: 4 +INFO: 127.0.0.1:65285 - "GET /team/list HTTP/1.1" 200 OK +18:52:22 - LiteLLM Proxy:DEBUG: key_management_endpoints.py:4604 - Successfully prepared response +INFO: 127.0.0.1:65290 - "GET /key/list?page=1&size=50&sort_by=created_at&sort_order=desc&expand=user&return_full_object=true&include_team_keys=true&include_created_by_keys=true HTTP/1.1" 200 OK +INFO: 127.0.0.1:65288 - "GET /tag/list HTTP/1.1" 200 OK +INFO: 127.0.0.1:65290 - "GET /project/list HTTP/1.1" 404 Not Found +18:52:24 - LiteLLM Proxy:DEBUG: spend_update_queue.py:39 - Aggregating updates by entity type: [] +18:52:24 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1122 - User Spend transactions: {} +18:52:24 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1165 - End-User Spend transactions: {} +18:52:24 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1180 - KEY Spend transactions: {} +18:52:24 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1221 - Team Spend transactions: {} +18:52:24 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1269 - Team Membership Spend transactions: {} +18:52:24 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1342 - Org Spend transactions: {} +18:52:24 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1435 - Tag Spend transactions: {} +18:52:24 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1435 - Agent Spend transactions: {} +18:52:24 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:52:24 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1576 - Daily User Spend transactions: 0 +18:52:24 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1609 - No new transactions to process for daily user spend update +18:52:24 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:52:24 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1576 - Daily Team Spend transactions: 0 +18:52:24 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1609 - No new transactions to process for daily team spend update +18:52:24 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:52:24 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1576 - Daily Org Spend transactions: 0 +18:52:24 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1609 - No new transactions to process for daily org spend update +18:52:24 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:52:24 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1576 - Daily End_user Spend transactions: 0 +18:52:24 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1609 - No new transactions to process for daily end_user spend update +18:52:24 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:52:24 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1576 - Daily Agent Spend transactions: 0 +18:52:24 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1609 - No new transactions to process for daily agent spend update +18:52:24 - LiteLLM Proxy:DEBUG: utils.py:4936 - Spend Logs transactions: 0 +INFO: 127.0.0.1:65290 - "GET /project/list HTTP/1.1" 404 Not Found +18:52:28 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/organization/list +18:52:28 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:52:28 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:22:28.414705+00:00 +18:52:28 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/team/list +18:52:28 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:52:28 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:22:28.416982+00:00 +18:52:28 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/models +18:52:28 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:52:28 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:22:28.426995+00:00 +18:52:28 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/v2/user/info +18:52:28 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:52:28 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:22:28.430882+00:00 +18:52:28 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/v1/access_group +18:52:28 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:52:28 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:22:28.434375+00:00 +18:52:28 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/v1/mcp/server +18:52:28 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:52:28 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:22:28.437819+00:00 +18:52:28 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +18:52:28 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +18:52:28 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +18:52:28 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +18:52:28 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +18:52:28 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +18:52:28 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +18:52:28 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +18:52:28 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +INFO: 127.0.0.1:65326 - "GET /v2/user/info HTTP/1.1" 200 OK +18:52:28 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +18:52:28 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/v1/mcp/access_groups +18:52:28 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:52:28 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:22:28.460826+00:00 +18:52:28 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +INFO: 127.0.0.1:65324 - "GET /models?include_model_access_groups=True&return_wildcard_routes=True&scope=expand HTTP/1.1" 200 OK +18:52:28 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/v1/mcp/toolset +18:52:28 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:52:28 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:22:28.463333+00:00 +INFO: 127.0.0.1:65290 - "GET /organization/list HTTP/1.1" 200 OK +INFO: 127.0.0.1:65328 - "GET /v1/access_group HTTP/1.1" 200 OK +18:52:28 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +18:52:28 - LiteLLM:DEBUG: mcp_server_manager.py:796 - Admin user without explicit object_permission - returning all servers +INFO: 127.0.0.1:65329 - "GET /v1/mcp/server HTTP/1.1" 200 OK +18:52:28 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +18:52:28 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +INFO: 127.0.0.1:65321 - "GET /team/list HTTP/1.1" 200 OK +18:52:28 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +18:52:28 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +18:52:28 - LiteLLM Proxy:WARNING: toolset_db.py:60 - litellm.proxy._experimental.mcp_server.toolset_db::list_mcp_toolsets - 'Prisma' object has no attribute 'litellm_mcptoolsettable' +INFO: 127.0.0.1:65324 - "GET /v1/mcp/toolset HTTP/1.1" 200 OK +INFO: 127.0.0.1:65326 - "GET /v1/mcp/access_groups HTTP/1.1" 200 OK +18:52:30 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/organization/list +18:52:30 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:52:30 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:22:30.307066+00:00 +18:52:30 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/team/list +18:52:30 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:52:30 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:22:30.310005+00:00 +INFO: 127.0.0.1:65321 - "GET /project/list HTTP/1.1" 404 Not Found +18:52:30 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/tag/list +18:52:30 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:52:30 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:22:30.314509+00:00 +18:52:30 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +18:52:30 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +18:52:30 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +18:52:30 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +18:52:30 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +18:52:30 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +INFO: 127.0.0.1:65326 - "GET /organization/list HTTP/1.1" 200 OK +INFO: 127.0.0.1:65324 - "GET /team/list HTTP/1.1" 200 OK +INFO: 127.0.0.1:65329 - "GET /tag/list HTTP/1.1" 200 OK +INFO: 127.0.0.1:65329 - "GET /project/list HTTP/1.1" 404 Not Found +18:52:34 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/organization/list +18:52:34 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:52:34 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:22:34.018157+00:00 +18:52:34 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/team/list +18:52:34 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:52:34 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:22:34.038105+00:00 +18:52:34 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/tag/list +18:52:34 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:52:34 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:22:34.045120+00:00 +INFO: 127.0.0.1:65321 - "GET /project/list HTTP/1.1" 404 Not Found +18:52:34 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +18:52:34 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +18:52:34 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +18:52:34 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +18:52:34 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +18:52:34 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +INFO: 127.0.0.1:65329 - "GET /organization/list HTTP/1.1" 200 OK +INFO: 127.0.0.1:65324 - "GET /team/list HTTP/1.1" 200 OK +INFO: 127.0.0.1:65326 - "GET /tag/list HTTP/1.1" 200 OK +18:52:35 - LiteLLM Proxy:DEBUG: spend_update_queue.py:39 - Aggregating updates by entity type: [] +18:52:35 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1122 - User Spend transactions: {} +18:52:35 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1165 - End-User Spend transactions: {} +18:52:35 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1180 - KEY Spend transactions: {} +18:52:35 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1221 - Team Spend transactions: {} +18:52:35 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1269 - Team Membership Spend transactions: {} +18:52:35 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1342 - Org Spend transactions: {} +18:52:35 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1435 - Tag Spend transactions: {} +18:52:35 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1435 - Agent Spend transactions: {} +18:52:35 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:52:35 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1576 - Daily User Spend transactions: 0 +18:52:35 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1609 - No new transactions to process for daily user spend update +18:52:35 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:52:35 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1576 - Daily Team Spend transactions: 0 +18:52:35 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1609 - No new transactions to process for daily team spend update +18:52:35 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:52:35 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1576 - Daily Org Spend transactions: 0 +18:52:35 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1609 - No new transactions to process for daily org spend update +18:52:35 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:52:35 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1576 - Daily End_user Spend transactions: 0 +18:52:35 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1609 - No new transactions to process for daily end_user spend update +18:52:35 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:52:35 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1576 - Daily Agent Spend transactions: 0 +18:52:35 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1609 - No new transactions to process for daily agent spend update +18:52:35 - LiteLLM Proxy:DEBUG: utils.py:4936 - Spend Logs transactions: 0 +INFO: 127.0.0.1:65326 - "GET /project/list HTTP/1.1" 404 Not Found +18:52:39 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:52:44 - LiteLLM Proxy:DEBUG: proxy_server.py:4256 - len new_models: 2 +18:52:44 - LiteLLM Proxy:DEBUG: proxy_server.py:5461 - guardrails from the DB [] +18:52:44 - LiteLLM Proxy:INFO: policy_registry.py:577 - Synced 0 production policies and 0 draft/published (by ID) from DB to in-memory registry +18:52:44 - LiteLLM Proxy:INFO: attachment_registry.py:481 - Synced 0 attachments from DB to in-memory registry +18:52:44 - LiteLLM Proxy:DEBUG: proxy_server.py:5497 - Successfully synced policies and attachments from DB +18:52:44 - LiteLLM:DEBUG: mcp_server_manager.py:2644 - Loading MCP servers from database into registry... +18:52:44 - LiteLLM:INFO: mcp_server_manager.py:2664 - Found 1 MCP servers in database +18:52:44 - LiteLLM:DEBUG: mcp_server_manager.py:2697 - MCP registry refreshed (1 servers in registry) +18:52:44 - LiteLLM Proxy:DEBUG: pass_through_endpoints.py:2409 - initializing pass through endpoints +18:52:44 - LiteLLM Proxy:INFO: proxy_server.py:5640 - Loading 0 search tool(s) from database into router +18:52:44 - LiteLLM Proxy:DEBUG: proxy_server.py:5660 - No search tools found in database, keeping config-loaded search tools (if any) +18:52:44 - LiteLLM Proxy:INFO: tool_registry_writer.py:329 - ToolPolicyRegistry: synced 17 tool policies and 1 object permissions from DB +18:52:44 - LiteLLM Proxy:DEBUG: proxy_server.py:5517 - Successfully synced tool policy from DB +18:52:46 - LiteLLM Proxy:DEBUG: spend_update_queue.py:39 - Aggregating updates by entity type: [] +18:52:46 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1122 - User Spend transactions: {} +18:52:46 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1165 - End-User Spend transactions: {} +18:52:46 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1180 - KEY Spend transactions: {} +18:52:46 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1221 - Team Spend transactions: {} +18:52:46 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1269 - Team Membership Spend transactions: {} +18:52:46 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1342 - Org Spend transactions: {} +18:52:46 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1435 - Tag Spend transactions: {} +18:52:46 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1435 - Agent Spend transactions: {} +18:52:46 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:52:46 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1576 - Daily User Spend transactions: 0 +18:52:46 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1609 - No new transactions to process for daily user spend update +18:52:46 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:52:46 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1576 - Daily Team Spend transactions: 0 +18:52:46 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1609 - No new transactions to process for daily team spend update +18:52:46 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:52:46 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1576 - Daily Org Spend transactions: 0 +18:52:46 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1609 - No new transactions to process for daily org spend update +18:52:46 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:52:46 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1576 - Daily End_user Spend transactions: 0 +18:52:46 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1609 - No new transactions to process for daily end_user spend update +18:52:46 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:52:46 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1576 - Daily Agent Spend transactions: 0 +18:52:46 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1609 - No new transactions to process for daily agent spend update +18:52:46 - LiteLLM Proxy:DEBUG: utils.py:4936 - Spend Logs transactions: 0 +18:52:54 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/organization/list +18:52:54 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:52:54 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:22:54.075515+00:00 +18:52:54 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/team/list +18:52:54 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:52:54 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:22:54.133027+00:00 +INFO: 127.0.0.1:65389 - "GET /project/list HTTP/1.1" 404 Not Found +18:52:54 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/tag/list +18:52:54 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:52:54 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:22:54.284965+00:00 +18:52:54 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/key/list +18:52:54 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:52:54 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:22:54.295543+00:00 +18:52:54 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +18:52:54 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +18:52:54 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +18:52:54 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +18:52:54 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +18:52:54 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +18:52:54 - LiteLLM Proxy:DEBUG: key_management_endpoints.py:4526 - Entering list_keys function +18:52:54 - LiteLLM Proxy:DEBUG: key_management_endpoints.py:4950 - Filter conditions: {'OR': [{'team_id': None}, {'team_id': {'not': 'litellm-dashboard'}}]} +18:52:54 - LiteLLM Proxy:DEBUG: key_management_endpoints.py:5020 - Pagination: skip=0, take=50 +18:52:54 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +18:52:54 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +INFO: 127.0.0.1:65385 - "GET /organization/list HTTP/1.1" 200 OK +18:52:54 - LiteLLM Proxy:DEBUG: key_management_endpoints.py:5062 - Fetched 4 keys +INFO: 127.0.0.1:65392 - "GET /tag/list HTTP/1.1" 200 OK +INFO: 127.0.0.1:65387 - "GET /team/list HTTP/1.1" 200 OK +18:52:54 - LiteLLM Proxy:DEBUG: key_management_endpoints.py:5074 - Total count of keys: 4 +18:52:54 - LiteLLM Proxy:DEBUG: key_management_endpoints.py:4604 - Successfully prepared response +INFO: 127.0.0.1:65393 - "GET /key/list?page=1&size=50&sort_by=created_at&sort_order=desc&expand=user&return_full_object=true&include_team_keys=true&include_created_by_keys=true HTTP/1.1" 200 OK +INFO: 127.0.0.1:65393 - "GET /project/list HTTP/1.1" 404 Not Found +18:52:58 - LiteLLM Proxy:DEBUG: spend_update_queue.py:39 - Aggregating updates by entity type: [] +18:52:58 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1122 - User Spend transactions: {} +18:52:58 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1165 - End-User Spend transactions: {} +18:52:58 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1180 - KEY Spend transactions: {} +18:52:58 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1221 - Team Spend transactions: {} +18:52:58 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1269 - Team Membership Spend transactions: {} +18:52:58 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1342 - Org Spend transactions: {} +18:52:58 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1435 - Tag Spend transactions: {} +18:52:58 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1435 - Agent Spend transactions: {} +18:52:58 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:52:58 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1576 - Daily User Spend transactions: 0 +18:52:58 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1609 - No new transactions to process for daily user spend update +18:52:58 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:52:58 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1576 - Daily Team Spend transactions: 0 +18:52:58 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1609 - No new transactions to process for daily team spend update +18:52:58 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:52:58 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1576 - Daily Org Spend transactions: 0 +18:52:58 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1609 - No new transactions to process for daily org spend update +18:52:58 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:52:58 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1576 - Daily End_user Spend transactions: 0 +18:52:58 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1609 - No new transactions to process for daily end_user spend update +18:52:58 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:52:58 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1576 - Daily Agent Spend transactions: 0 +18:52:58 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1609 - No new transactions to process for daily agent spend update +18:52:58 - LiteLLM Proxy:DEBUG: utils.py:4936 - Spend Logs transactions: 0 +18:53:04 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:53:05 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/health/readiness +18:53:05 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/organization/list +18:53:05 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:53:05 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:23:05.652862+00:00 +18:53:06 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/team/list +18:53:06 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:53:06 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:23:06.042541+00:00 +18:53:06 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/tag/list +18:53:06 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:53:06 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:23:06.085990+00:00 +INFO: 127.0.0.1:65443 - "GET /project/list HTTP/1.1" 404 Not Found +18:53:06 - LiteLLM:DEBUG: http_handler.py:840 - Using AiohttpTransport... +INFO: 127.0.0.1:65436 - "GET /health/readiness HTTP/1.1" 200 OK +18:53:06 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +18:53:06 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +18:53:06 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +18:53:06 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +18:53:06 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +18:53:06 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +INFO: 127.0.0.1:65438 - "GET /organization/list HTTP/1.1" 200 OK +INFO: 127.0.0.1:65442 - "GET /tag/list HTTP/1.1" 200 OK +INFO: 127.0.0.1:65440 - "GET /team/list HTTP/1.1" 200 OK +18:53:08 - LiteLLM Proxy:DEBUG: spend_update_queue.py:39 - Aggregating updates by entity type: [] +18:53:09 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1122 - User Spend transactions: {} +18:53:09 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1165 - End-User Spend transactions: {} +18:53:09 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1180 - KEY Spend transactions: {} +18:53:09 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1221 - Team Spend transactions: {} +18:53:09 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1269 - Team Membership Spend transactions: {} +18:53:09 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1342 - Org Spend transactions: {} +18:53:09 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1435 - Tag Spend transactions: {} +18:53:09 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1435 - Agent Spend transactions: {} +18:53:09 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:53:09 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1576 - Daily User Spend transactions: 0 +18:53:09 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1609 - No new transactions to process for daily user spend update +18:53:09 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:53:09 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1576 - Daily Team Spend transactions: 0 +18:53:09 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1609 - No new transactions to process for daily team spend update +18:53:09 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:53:09 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1576 - Daily Org Spend transactions: 0 +18:53:09 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1609 - No new transactions to process for daily org spend update +18:53:09 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:53:09 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1576 - Daily End_user Spend transactions: 0 +18:53:09 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1609 - No new transactions to process for daily end_user spend update +18:53:09 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:53:09 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1576 - Daily Agent Spend transactions: 0 +18:53:09 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1609 - No new transactions to process for daily agent spend update +18:53:09 - LiteLLM Proxy:DEBUG: utils.py:4936 - Spend Logs transactions: 0 +18:53:09 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/v1/mcp/server +18:53:09 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:53:09 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:23:09.447694+00:00 +18:53:09 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/v1/mcp/toolset +18:53:09 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:53:09 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:23:09.480143+00:00 +18:53:09 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/get/mcp_semantic_filter_settings +18:53:09 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:53:09 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:23:09.511525+00:00 +18:53:09 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/model_group/info +18:53:09 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:53:09 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:23:09.521031+00:00 +18:53:09 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/config/list +18:53:09 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:53:09 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:23:09.525741+00:00 +18:53:09 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/v1/mcp/network/client-ip +18:53:09 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:53:09 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:23:09.533092+00:00 +18:53:09 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +18:53:09 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +18:53:09 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +18:53:09 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +18:53:09 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +18:53:09 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +18:53:09 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +INFO: 127.0.0.1:65461 - "GET /v1/mcp/network/client-ip HTTP/1.1" 200 OK +18:53:09 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +18:53:09 - LiteLLM Proxy:DEBUG: model_checks.py:131 - ALL KEY MODELS - 0 +18:53:09 - LiteLLM Proxy:DEBUG: model_checks.py:166 - ALL TEAM MODELS - 0 +18:53:09 - LiteLLM:DEBUG: utils.py:5620 - checking potential_model_names in litellm.model_cost: {'split_model': 'gpt-5.3-codex', 'combined_model_name': 'openai/gpt-5.3-codex', 'stripped_model_name': 'gpt-5.3-codex', 'combined_stripped_model_name': 'openai/gpt-5.3-codex', 'custom_llm_provider': 'openai'} +18:53:09 - LiteLLM:DEBUG: utils.py:5620 - checking potential_model_names in litellm.model_cost: {'split_model': 'gpt-5.3-codex', 'combined_model_name': 'openai/gpt-5.3-codex', 'stripped_model_name': 'gpt-5.3-codex', 'combined_stripped_model_name': 'openai/gpt-5.3-codex', 'custom_llm_provider': 'openai'} +18:53:09 - LiteLLM:DEBUG: utils.py:5620 - checking potential_model_names in litellm.model_cost: {'split_model': 'gpt-5.3-codex', 'combined_model_name': 'openai/gpt-5.3-codex', 'stripped_model_name': 'openai/gpt-5.3-codex', 'combined_stripped_model_name': 'openai/gpt-5.3-codex', 'custom_llm_provider': 'openai'} +18:53:09 - LiteLLM:DEBUG: utils.py:5620 - checking potential_model_names in litellm.model_cost: {'split_model': 'oia-gpt-realtime', 'combined_model_name': 'azure/oia-gpt-realtime', 'stripped_model_name': 'azure/oia-gpt-realtime', 'combined_stripped_model_name': 'azure/oia-gpt-realtime', 'custom_llm_provider': 'azure'} +18:53:09 - LiteLLM:DEBUG: utils.py:5921 - Error getting model info: This model isn't mapped yet. Add it here - https://github.com/BerriAI/litellm/blob/main/model_prices_and_context_window.json +18:53:09 - LiteLLM:DEBUG: utils.py:5620 - checking potential_model_names in litellm.model_cost: {'split_model': 'oia-gpt-realtime', 'combined_model_name': 'azure/oia-gpt-realtime', 'stripped_model_name': 'azure/oia-gpt-realtime', 'combined_stripped_model_name': 'azure/oia-gpt-realtime', 'custom_llm_provider': 'azure'} +18:53:09 - LiteLLM:DEBUG: utils.py:5921 - Error getting model info: This model isn't mapped yet. Add it here - https://github.com/BerriAI/litellm/blob/main/model_prices_and_context_window.json +18:53:09 - LiteLLM:DEBUG: utils.py:5620 - checking potential_model_names in litellm.model_cost: {'split_model': 'gemini-3.1-flash-image-preview', 'combined_model_name': 'vertex_ai/gemini-3.1-flash-image-preview', 'stripped_model_name': 'gemini-3.1-flash-image-preview', 'combined_stripped_model_name': 'vertex_ai/gemini-3.1-flash-image-preview', 'custom_llm_provider': 'vertex_ai'} +18:53:09 - LiteLLM:DEBUG: utils.py:5620 - checking potential_model_names in litellm.model_cost: {'split_model': 'gemini-3.1-flash-image-preview', 'combined_model_name': 'gemini-3.1-flash-image-preview', 'stripped_model_name': 'gemini-3.1-flash-image-preview', 'combined_stripped_model_name': 'gemini-3.1-flash-image-preview', 'custom_llm_provider': 'vertex_ai'} +18:53:09 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/v1/mcp/server/submissions +18:53:09 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:53:09 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:23:09.669506+00:00 +18:53:09 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +18:53:09 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +18:53:09 - LiteLLM:DEBUG: mcp_server_manager.py:796 - Admin user without explicit object_permission - returning all servers +INFO: 127.0.0.1:65440 - "GET /v1/mcp/server HTTP/1.1" 200 OK +18:53:09 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +18:53:09 - LiteLLM Proxy:WARNING: toolset_db.py:60 - litellm.proxy._experimental.mcp_server.toolset_db::list_mcp_toolsets - 'Prisma' object has no attribute 'litellm_mcptoolsettable' +INFO: 127.0.0.1:65442 - "GET /v1/mcp/toolset HTTP/1.1" 200 OK +18:53:09 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +18:53:09 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/v1/mcp/server/health +18:53:09 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:53:09 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:23:09.692446+00:00 +INFO: 127.0.0.1:65442 - "HEAD / HTTP/1.1" 200 OK +INFO: 127.0.0.1:65436 - "GET /model_group/info HTTP/1.1" 200 OK +INFO: 127.0.0.1:65443 - "GET /config/list?config_type=general_settings HTTP/1.1" 200 OK +18:53:09 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/config/list +18:53:09 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:53:09 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:23:09.731878+00:00 +INFO: 127.0.0.1:65436 - "GET /ui/assets/logos/github.svg HTTP/1.1" 304 Not Modified +INFO: 127.0.0.1:65443 - "GET /ui/assets/logos/slack.svg HTTP/1.1" 304 Not Modified +18:53:09 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +INFO: 127.0.0.1:65436 - "GET /ui/assets/logos/notion.svg HTTP/1.1" 304 Not Modified +INFO: 127.0.0.1:65443 - "GET /ui/assets/logos/linear.svg HTTP/1.1" 304 Not Modified +18:53:09 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +18:53:09 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +INFO: 127.0.0.1:65436 - "GET /ui/assets/logos/jira.svg HTTP/1.1" 304 Not Modified +INFO: 127.0.0.1:65438 - "GET /get/mcp_semantic_filter_settings HTTP/1.1" 200 OK +INFO: 127.0.0.1:65443 - "GET /ui/assets/logos/figma.svg HTTP/1.1" 304 Not Modified +18:53:09 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +18:53:09 - LiteLLM:DEBUG: mcp_server_manager.py:796 - Admin user without explicit object_permission - returning all servers +18:53:09 - LiteLLM:DEBUG: client.py:273 - litellm headers for streamable_http_client: {} +18:53:09 - LiteLLM:DEBUG: client.py:402 - MCP client using SSL configuration: SSLContext +18:53:09 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +INFO: 127.0.0.1:65436 - "GET /ui/assets/logos/gmail.svg HTTP/1.1" 304 Not Modified +18:53:09 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/model_group/info +18:53:09 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:53:09 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:23:09.989425+00:00 +INFO: 127.0.0.1:65443 - "GET /ui/assets/logos/stripe.svg HTTP/1.1" 304 Not Modified +INFO: 127.0.0.1:65438 - "GET /ui/assets/logos/google_drive.svg HTTP/1.1" 304 Not Modified +18:53:09 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +INFO: 127.0.0.1:65443 - "GET /ui/assets/logos/shopify.svg HTTP/1.1" 304 Not Modified +INFO: 127.0.0.1:65438 - "GET /ui/assets/logos/salesforce.svg HTTP/1.1" 304 Not Modified +INFO: 127.0.0.1:65442 - "GET /config/list?config_type=general_settings HTTP/1.1" 200 OK +INFO: 127.0.0.1:65438 - "GET /ui/assets/logos/hubspot.svg HTTP/1.1" 304 Not Modified +INFO: 127.0.0.1:65443 - "GET /ui/assets/logos/twilio.svg HTTP/1.1" 304 Not Modified +INFO: 127.0.0.1:65461 - "GET /v1/mcp/server/submissions HTTP/1.1" 200 OK +INFO: 127.0.0.1:65442 - "GET /ui/assets/logos/cloudflare.svg HTTP/1.1" 304 Not Modified +18:53:10 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +INFO: 127.0.0.1:65438 - "GET /ui/assets/logos/postgresql.svg HTTP/1.1" 304 Not Modified +INFO: 127.0.0.1:65443 - "GET /ui/assets/logos/sentry.svg HTTP/1.1" 304 Not Modified +INFO: 127.0.0.1:65461 - "GET /ui/assets/logos/snowflake.svg HTTP/1.1" 304 Not Modified +INFO: 127.0.0.1:65442 - "GET /ui/assets/logos/zapier.svg HTTP/1.1" 304 Not Modified +INFO: 127.0.0.1:65461 - "GET /__next._tree.txt?_rsc=1r34m HTTP/1.1" 404 Not Found +18:53:10 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +18:53:10 - LiteLLM Proxy:DEBUG: model_checks.py:131 - ALL KEY MODELS - 0 +18:53:10 - LiteLLM Proxy:DEBUG: model_checks.py:166 - ALL TEAM MODELS - 0 +18:53:10 - LiteLLM:DEBUG: utils.py:5620 - checking potential_model_names in litellm.model_cost: {'split_model': 'oia-gpt-realtime', 'combined_model_name': 'azure/oia-gpt-realtime', 'stripped_model_name': 'azure/oia-gpt-realtime', 'combined_stripped_model_name': 'azure/oia-gpt-realtime', 'custom_llm_provider': 'azure'} +18:53:10 - LiteLLM:DEBUG: utils.py:5921 - Error getting model info: This model isn't mapped yet. Add it here - https://github.com/BerriAI/litellm/blob/main/model_prices_and_context_window.json +18:53:10 - LiteLLM:DEBUG: utils.py:5620 - checking potential_model_names in litellm.model_cost: {'split_model': 'oia-gpt-realtime', 'combined_model_name': 'azure/oia-gpt-realtime', 'stripped_model_name': 'azure/oia-gpt-realtime', 'combined_stripped_model_name': 'azure/oia-gpt-realtime', 'custom_llm_provider': 'azure'} +18:53:10 - LiteLLM:DEBUG: utils.py:5921 - Error getting model info: This model isn't mapped yet. Add it here - https://github.com/BerriAI/litellm/blob/main/model_prices_and_context_window.json +INFO: 127.0.0.1:65443 - "GET /ui/assets/logos/gitlab.svg HTTP/1.1" 304 Not Modified +INFO: 127.0.0.1:65438 - "GET /ui/assets/logos/google.svg HTTP/1.1" 304 Not Modified +INFO: 127.0.0.1:65436 - "GET /model_group/info HTTP/1.1" 200 OK +INFO: 127.0.0.1:65440 - "GET /v1/mcp/server/health HTTP/1.1" 200 OK +INFO: 127.0.0.1:65440 - "GET / HTTP/1.1" 200 OK +18:53:17 - LiteLLM Proxy:DEBUG: custom_openapi_spec.py:311 - Successfully added ProxyChatCompletionRequest schema to OpenAPI spec +18:53:17 - LiteLLM Proxy:DEBUG: custom_openapi_spec.py:311 - Successfully added EmbeddingRequest schema to OpenAPI spec +18:53:17 - LiteLLM Proxy:DEBUG: custom_openapi_spec.py:315 - Could not get schema for ResponsesAPIRequestParams +INFO: 127.0.0.1:65440 - "GET /openapi.json HTTP/1.1" 200 OK +18:53:17 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/organization/list +18:53:17 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:53:17 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:23:17.073159+00:00 +18:53:17 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/team/list +18:53:17 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:53:17 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:23:17.085893+00:00 +18:53:17 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/v1/mcp/server +18:53:17 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:53:17 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:23:17.089077+00:00 +18:53:17 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/v1/mcp/server/health +18:53:17 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:53:17 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:23:17.093754+00:00 +18:53:17 - LiteLLM Proxy:DEBUG: http_parsing_utils.py:529 - populate_request_with_path_params: No vector_store_id present in path=/v1/mcp/toolset +18:53:17 - LiteLLM:DEBUG: user_api_key_auth.py:1099 - 404: {'error': "Team doesn't exist in cache + check_cache_only=True. Team=litellm-dashboard."} +18:53:17 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1348 - Checking if token expired, expiry time 2026-04-29 11:16:22.190000+00:00 and current time 2026-04-28 13:23:17.096736+00:00 +18:53:17 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +18:53:17 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +18:53:17 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +18:53:17 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +18:53:17 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +18:53:17 - LiteLLM:DEBUG: mcp_server_manager.py:796 - Admin user without explicit object_permission - returning all servers +INFO: 127.0.0.1:65438 - "GET /v1/mcp/server HTTP/1.1" 200 OK +18:53:17 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +18:53:17 - LiteLLM Proxy:DEBUG: user_api_key_auth.py:1567 - centralized auth: team fetch failed (HTTPException: 404: {'error': "Team doesn't exist in db. Team=litellm-dashboard. Create team via `/team/new` call."}) +18:53:17 - LiteLLM Proxy:DEBUG: proxy_server.py:4256 - len new_models: 2 +18:53:17 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +18:53:17 - LiteLLM:DEBUG: mcp_server_manager.py:796 - Admin user without explicit object_permission - returning all servers +18:53:17 - LiteLLM:DEBUG: client.py:273 - litellm headers for streamable_http_client: {} +18:53:17 - LiteLLM:DEBUG: client.py:402 - MCP client using SSL configuration: SSLContext +18:53:17 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +18:53:17 - LiteLLM Proxy:WARNING: toolset_db.py:60 - litellm.proxy._experimental.mcp_server.toolset_db::list_mcp_toolsets - 'Prisma' object has no attribute 'litellm_mcptoolsettable' +INFO: 127.0.0.1:65442 - "GET /v1/mcp/toolset HTTP/1.1" 200 OK +18:53:17 - LiteLLM Proxy:DEBUG: auth_checks.py:4036 - Vector store registry not found, skipping vector store access check +INFO: 127.0.0.1:65436 - "GET /organization/list HTTP/1.1" 200 OK +INFO: 127.0.0.1:65443 - "GET /team/list HTTP/1.1" 200 OK +18:53:17 - LiteLLM Proxy:DEBUG: proxy_server.py:5461 - guardrails from the DB [] +18:53:17 - LiteLLM Proxy:INFO: policy_registry.py:577 - Synced 0 production policies and 0 draft/published (by ID) from DB to in-memory registry +18:53:17 - LiteLLM Proxy:INFO: attachment_registry.py:481 - Synced 0 attachments from DB to in-memory registry +18:53:17 - LiteLLM Proxy:DEBUG: proxy_server.py:5497 - Successfully synced policies and attachments from DB +18:53:17 - LiteLLM:DEBUG: mcp_server_manager.py:2644 - Loading MCP servers from database into registry... +18:53:17 - LiteLLM:INFO: mcp_server_manager.py:2664 - Found 1 MCP servers in database +18:53:17 - LiteLLM:DEBUG: mcp_server_manager.py:2697 - MCP registry refreshed (1 servers in registry) +18:53:17 - LiteLLM Proxy:DEBUG: pass_through_endpoints.py:2409 - initializing pass through endpoints +18:53:17 - LiteLLM Proxy:INFO: proxy_server.py:5640 - Loading 0 search tool(s) from database into router +18:53:17 - LiteLLM Proxy:DEBUG: proxy_server.py:5660 - No search tools found in database, keeping config-loaded search tools (if any) +18:53:17 - LiteLLM Proxy:INFO: tool_registry_writer.py:329 - ToolPolicyRegistry: synced 17 tool policies and 1 object permissions from DB +18:53:17 - LiteLLM Proxy:DEBUG: proxy_server.py:5517 - Successfully synced tool policy from DB +INFO: 127.0.0.1:65461 - "GET /v1/mcp/server/health HTTP/1.1" 200 OK +18:53:19 - LiteLLM Proxy:DEBUG: spend_update_queue.py:39 - Aggregating updates by entity type: [] +18:53:20 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1122 - User Spend transactions: {} +18:53:20 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1165 - End-User Spend transactions: {} +18:53:20 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1180 - KEY Spend transactions: {} +18:53:20 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1221 - Team Spend transactions: {} +18:53:20 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1269 - Team Membership Spend transactions: {} +18:53:20 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1342 - Org Spend transactions: {} +18:53:20 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1435 - Tag Spend transactions: {} +18:53:20 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1435 - Agent Spend transactions: {} +18:53:20 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:53:20 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1576 - Daily User Spend transactions: 0 +18:53:20 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1609 - No new transactions to process for daily user spend update +18:53:20 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:53:20 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1576 - Daily Team Spend transactions: 0 +18:53:20 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1609 - No new transactions to process for daily team spend update +18:53:20 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:53:20 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1576 - Daily Org Spend transactions: 0 +18:53:20 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1609 - No new transactions to process for daily org spend update +18:53:20 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:53:20 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1576 - Daily End_user Spend transactions: 0 +18:53:20 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1609 - No new transactions to process for daily end_user spend update +18:53:20 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:53:20 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1576 - Daily Agent Spend transactions: 0 +18:53:20 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1609 - No new transactions to process for daily agent spend update +18:53:20 - LiteLLM Proxy:DEBUG: utils.py:4936 - Spend Logs transactions: 0 +18:53:29 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:53:31 - LiteLLM Proxy:DEBUG: spend_update_queue.py:39 - Aggregating updates by entity type: [] +18:53:31 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1122 - User Spend transactions: {} +18:53:31 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1165 - End-User Spend transactions: {} +18:53:31 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1180 - KEY Spend transactions: {} +18:53:31 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1221 - Team Spend transactions: {} +18:53:31 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1269 - Team Membership Spend transactions: {} +18:53:31 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1342 - Org Spend transactions: {} +18:53:31 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1435 - Tag Spend transactions: {} +18:53:31 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1435 - Agent Spend transactions: {} +18:53:31 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:53:31 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1576 - Daily User Spend transactions: 0 +18:53:31 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1609 - No new transactions to process for daily user spend update +18:53:31 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:53:31 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1576 - Daily Team Spend transactions: 0 +18:53:31 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1609 - No new transactions to process for daily team spend update +18:53:31 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:53:31 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1576 - Daily Org Spend transactions: 0 +18:53:31 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1609 - No new transactions to process for daily org spend update +18:53:31 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:53:31 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1576 - Daily End_user Spend transactions: 0 +18:53:31 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1609 - No new transactions to process for daily end_user spend update +18:53:31 - LiteLLM Proxy:DEBUG: daily_spend_update_queue.py:99 - Aggregated daily spend update transactions: {} +18:53:31 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1576 - Daily Agent Spend transactions: 0 +18:53:31 - LiteLLM Proxy:DEBUG: db_spend_update_writer.py:1609 - No new transactions to process for daily agent spend update +18:53:31 - LiteLLM Proxy:DEBUG: utils.py:4936 - Spend Logs transactions: 0 diff --git a/proxy_server_config.yaml b/proxy_server_config.yaml index 5d3d810926..5a34fd4745 100644 --- a/proxy_server_config.yaml +++ b/proxy_server_config.yaml @@ -1,231 +1,7 @@ model_list: - - model_name: gpt-3.5-turbo-end-user-test + # Gemini 2.5 Flash Native Audio (Latest - recommended) + - model_name: gpt-5.3-codex litellm_params: - model: gpt-3.5-turbo - region_name: "eu" - model_info: - id: "1" - - model_name: gpt-3.5-turbo-end-user-test - litellm_params: - model: openai/gpt-4.1-mini - api_key: os.environ/OPENAI_API_KEY # The `os.environ/` prefix tells litellm to read this from the env. See https://docs.litellm.ai/docs/simple_proxy#load-api-keys-from-vault - - model_name: gpt-3.5-turbo - litellm_params: - model: openai/gpt-4.1-mini - api_key: os.environ/OPENAI_API_KEY # The `os.environ/` prefix tells litellm to read this from the env. See https://docs.litellm.ai/docs/simple_proxy#load-api-keys-from-vault - - model_name: gpt-3.5-turbo-large - litellm_params: - model: "gpt-3.5-turbo-1106" + model: openai/gpt-5.3-codex api_key: os.environ/OPENAI_API_KEY - rpm: 480 - timeout: 300 - stream_timeout: 60 - - model_name: gpt-4 - litellm_params: - model: openai/gpt-4.1-mini - api_key: os.environ/OPENAI_API_KEY # The `os.environ/` prefix tells litellm to read this from the env. See https://docs.litellm.ai/docs/simple_proxy#load-api-keys-from-vault - rpm: 480 - timeout: 300 - stream_timeout: 60 - - model_name: sagemaker-completion-model - litellm_params: - model: sagemaker/berri-benchmarking-Llama-2-70b-chat-hf-4 - input_cost_per_second: 0.000420 - - model_name: text-embedding-ada-002 - litellm_params: - model: openai/text-embedding-ada-002 - api_key: os.environ/OPENAI_API_KEY - model_info: - mode: embedding - base_model: text-embedding-ada-002 - - model_name: dall-e-2 # some tests use dall-e-2 which is now deprecated, alias to dall-e-3 - litellm_params: - model: openai/dall-e-3 - - model_name: openai-dall-e-3 - litellm_params: - model: dall-e-3 - - model_name: fake-openai-endpoint - litellm_params: - model: openai/gpt-3.5-turbo - api_key: fake-key - api_base: https://exampleopenaiendpoint-production.up.railway.app/ - - model_name: fake-openai-endpoint-2 - litellm_params: - model: openai/my-fake-model - api_key: my-fake-key - api_base: https://exampleopenaiendpoint-production.up.railway.app/ - stream_timeout: 0.001 - rpm: 1 - - model_name: fake-openai-endpoint-3 - litellm_params: - model: openai/my-fake-model - api_key: my-fake-key - api_base: https://exampleopenaiendpoint-production.up.railway.app/ - stream_timeout: 0.001 - rpm: 1000 - - model_name: fake-openai-endpoint-4 - litellm_params: - model: openai/my-fake-model - api_key: my-fake-key - api_base: https://exampleopenaiendpoint-production.up.railway.app/ - num_retries: 50 - - model_name: fake-openai-endpoint-3 - litellm_params: - model: openai/my-fake-model-2 - api_key: my-fake-key - api_base: https://exampleopenaiendpoint-production.up.railway.app/ - stream_timeout: 0.001 - rpm: 1000 - - model_name: bad-model - litellm_params: - model: openai/bad-model - api_key: os.environ/OPENAI_API_KEY - api_base: https://exampleopenaiendpoint-production.up.railway.app/ - mock_timeout: True - timeout: 60 - rpm: 1000 - model_info: - health_check_timeout: 1 - - model_name: good-model - litellm_params: - model: openai/bad-model - api_key: os.environ/OPENAI_API_KEY - api_base: https://exampleopenaiendpoint-production.up.railway.app/ - rpm: 1000 - model_info: - health_check_timeout: 1 - - model_name: "*" - litellm_params: - model: openai/* - api_key: os.environ/OPENAI_API_KEY - - model_name: realtime-v1 - litellm_params: - model: azure/gpt-realtime-20250828-standard - api_version: "2025-08-28" - realtime_protocol: GA # Possible values: "GA"/ "v1", "beta" - - - model_name: realtime-beta - litellm_params: - model: azure/gpt-realtime-20250828-standard - api_version: 2025-04-01-preview - - - # provider specific wildcard routing - - model_name: "anthropic/*" - litellm_params: - model: "anthropic/*" - api_key: os.environ/ANTHROPIC_API_KEY - - model_name: "bedrock/*" - litellm_params: - model: "bedrock/*" - - model_name: "groq/*" - litellm_params: - model: "groq/*" - api_key: os.environ/GROQ_API_KEY - - model_name: mistral-embed - litellm_params: - model: mistral/mistral-embed - - model_name: gpt-instruct # [PROD TEST] - tests if `/health` automatically infers this to be a text completion model - litellm_params: - model: text-completion-openai/gpt-3.5-turbo-instruct - - model_name: fake-openai-endpoint-5 - litellm_params: - model: openai/my-fake-model - api_key: my-fake-key - api_base: https://exampleopenaiendpoint-production.up.railway.app/ - timeout: 1 - - model_name: badly-configured-openai-endpoint - litellm_params: - model: openai/my-fake-model - api_key: my-fake-key - api_base: https://exampleopenaiendpoint-production.up.railway.appxxxx/ - - model_name: gemini-1.5-flash - litellm_params: - model: gemini/gemini-1.5-flash - api_key: os.environ/GOOGLE_API_KEY - - model_name: gpt-4o - litellm_params: - model: gpt-4o - api_key: os.environ/OPENAI_API_KEY - - -litellm_settings: - # set_verbose: True # Uncomment this if you want to see verbose logs; not recommended in production - drop_params: True - success_callback: ["prometheus"] - # max_budget: 100 - # budget_duration: 30d - num_retries: 5 - request_timeout: 600 - telemetry: False - context_window_fallbacks: [{"gpt-3.5-turbo": ["gpt-3.5-turbo-large"]}] - default_team_settings: - - team_id: team-1 - success_callback: ["langfuse"] - failure_callback: ["langfuse"] - langfuse_public_key: os.environ/LANGFUSE_PROJECT1_PUBLIC # Project 1 - langfuse_secret: os.environ/LANGFUSE_PROJECT1_SECRET # Project 1 - - team_id: team-2 - success_callback: ["langfuse"] - failure_callback: ["langfuse"] - langfuse_public_key: os.environ/LANGFUSE_PROJECT2_PUBLIC # Project 2 - langfuse_secret: os.environ/LANGFUSE_PROJECT2_SECRET # Project 2 - langfuse_host: https://us.cloud.langfuse.com - # cache: true # [OPTIONAL] use for caching responses - # enable_caching_on_provider_specific_optional_params: True # Include provider-specific params in cache keys - # cache_params: # And for shared health check - # type: redis - # host: localhost - # port: 6379 - -# For /fine_tuning/jobs endpoints -finetune_settings: - - custom_llm_provider: azure - api_base: os.environ/AZURE_API_BASE - api_key: os.environ/AZURE_API_KEY - api_version: "2023-03-15-preview" - - custom_llm_provider: openai - api_key: os.environ/OPENAI_API_KEY - -# for /files endpoints -files_settings: - - custom_llm_provider: azure - api_base: os.environ/AZURE_API_BASE - api_key: os.environ/AZURE_API_KEY - api_version: "2023-03-15-preview" - - custom_llm_provider: openai - api_key: os.environ/OPENAI_API_KEY - -router_settings: - routing_strategy: usage-based-routing-v2 - redis_host: os.environ/REDIS_HOST - redis_password: os.environ/REDIS_PASSWORD - redis_port: os.environ/REDIS_PORT - enable_pre_call_checks: true - model_group_alias: {"my-special-fake-model-alias-name": "fake-openai-endpoint-3"} - -general_settings: - master_key: sk-1234 # [OPTIONAL] Use to enforce auth on proxy. See - https://docs.litellm.ai/docs/proxy/virtual_keys - store_model_in_db: True - proxy_budget_rescheduler_min_time: 60 - proxy_budget_rescheduler_max_time: 64 - proxy_batch_write_at: 1 - database_connection_pool_limit: 10 - # background_health_checks: true - # use_shared_health_check: true - # health_check_interval: 30 - # database_url: "postgresql://:@:/" # [OPTIONAL] use for token-based auth to proxy - - pass_through_endpoints: - - path: "/v1/rerank" # route you want to add to LiteLLM Proxy Server - target: "https://api.cohere.com/v1/rerank" # URL this route should forward requests to - headers: # headers to forward to this URL - content-type: application/json # (Optional) Extra Headers to pass to this endpoint - accept: application/json - forward_headers: True - -# environment_variables: - # settings for using redis caching - # REDIS_HOST: redis-16337.c322.us-east-1-2.ec2.cloud.redislabs.com - # REDIS_PORT: "16337" - # REDIS_PASSWORD: \ No newline at end of file + \ No newline at end of file diff --git a/tests/test_proxy_search_tool_auth.py b/tests/test_proxy_search_tool_auth.py new file mode 100644 index 0000000000..502bc655ce --- /dev/null +++ b/tests/test_proxy_search_tool_auth.py @@ -0,0 +1,212 @@ +""" +Test search tool authorization - verify model-like access control for search tools. + +Tests that: +1. Keys can only access search tools in their allowed_search_tools list +2. Teams can only access search tools in their allowed_search_tools list +3. Empty allowlists grant access to all search tools +4. Credentials are never exposed in team/key metadata +""" + +import pytest +from unittest.mock import MagicMock, patch +from fastapi import HTTPException + +# Import types and functions to test +from litellm.proxy._types import LiteLLM_TeamTable, UserAPIKeyAuth +from litellm.proxy.auth.auth_checks import ( + can_key_call_search_tool, + can_team_call_search_tool, +) + + +@pytest.mark.asyncio +async def test_key_can_access_allowed_search_tool(): + """Test that a key can access a search tool in its allowlist.""" + # Create a mock key with allowed_search_tools + mock_key = UserAPIKeyAuth( + token="sk-test-key", + models=["gpt-4"], + allowed_search_tools=["tavily-search", "perplexity-search"], + ) + + # Should succeed - tool is in allowlist + result = await can_key_call_search_tool( + search_tool_name="tavily-search", + valid_token=mock_key, + ) + assert result is True + + +@pytest.mark.asyncio +async def test_key_denied_non_allowed_search_tool(): + """Test that a key is denied access to a search tool not in its allowlist.""" + mock_key = UserAPIKeyAuth( + token="sk-test-key", + models=["gpt-4"], + allowed_search_tools=["tavily-search"], # Only tavily allowed + ) + + # Should raise exception - brave-search not in allowlist + with pytest.raises(Exception) as exc_info: + await can_key_call_search_tool( + search_tool_name="brave-search", + valid_token=mock_key, + ) + assert "not allowed to access search tool" in str(exc_info.value) + assert "brave-search" in str(exc_info.value) + + +@pytest.mark.asyncio +async def test_key_empty_allowlist_grants_all_access(): + """Test that an empty allowlist grants access to all search tools.""" + mock_key = UserAPIKeyAuth( + token="sk-test-key", + models=["gpt-4"], + allowed_search_tools=[], # Empty = all allowed + ) + + # Should succeed - empty list allows all + result = await can_key_call_search_tool( + search_tool_name="any-search-tool", + valid_token=mock_key, + ) + assert result is True + + +@pytest.mark.asyncio +async def test_team_can_access_allowed_search_tool(): + """Test that a team can access a search tool in its allowlist.""" + mock_team = LiteLLM_TeamTable( + team_id="team-123", + team_alias="Marketing Team", + models=["gpt-4"], + allowed_search_tools=["tavily-search", "exa-search"], + ) + + # Should succeed - tool is in allowlist + result = await can_team_call_search_tool( + search_tool_name="tavily-search", + team_object=mock_team, + ) + assert result is True + + +@pytest.mark.asyncio +async def test_team_denied_non_allowed_search_tool(): + """Test that a team is denied access to a search tool not in its allowlist.""" + mock_team = LiteLLM_TeamTable( + team_id="team-123", + team_alias="Engineering Team", + models=["gpt-4"], + allowed_search_tools=["perplexity-search"], # Only perplexity allowed + ) + + # Should raise exception - tavily-search not in allowlist + with pytest.raises(Exception) as exc_info: + await can_team_call_search_tool( + search_tool_name="tavily-search", + team_object=mock_team, + ) + assert "not allowed to access search tool" in str(exc_info.value) + assert "tavily-search" in str(exc_info.value) + + +@pytest.mark.asyncio +async def test_team_empty_allowlist_grants_all_access(): + """Test that an empty team allowlist grants access to all search tools.""" + mock_team = LiteLLM_TeamTable( + team_id="team-123", + team_alias="Admin Team", + models=["gpt-4"], + allowed_search_tools=[], # Empty = all allowed + ) + + # Should succeed - empty list allows all + result = await can_team_call_search_tool( + search_tool_name="any-search-tool", + team_object=mock_team, + ) + assert result is True + + +@pytest.mark.asyncio +async def test_team_none_allowed_search_tools(): + """Test that None for allowed_search_tools (not set) grants access to all.""" + mock_team = LiteLLM_TeamTable( + team_id="team-123", + team_alias="Legacy Team", + models=["gpt-4"], + allowed_search_tools=None, # Not set = all allowed + ) + + # Should succeed - None allows all + result = await can_team_call_search_tool( + search_tool_name="any-search-tool", + team_object=mock_team, + ) + assert result is True + + +def test_credentials_not_in_team_metadata(): + """Verify that search provider credentials are never stored in team metadata.""" + mock_team = LiteLLM_TeamTable( + team_id="team-123", + team_alias="Test Team", + models=["gpt-4"], + allowed_search_tools=["tavily-search"], + metadata={"custom_field": "value"}, # No search_provider_config + ) + + # Verify metadata does not contain search_provider_config + assert mock_team.metadata is not None + assert "search_provider_config" not in mock_team.metadata + assert "api_key" not in str(mock_team.metadata) + + +def test_credentials_not_in_key_metadata(): + """Verify that search provider credentials are never stored in key metadata.""" + mock_key = UserAPIKeyAuth( + token="sk-test-key", + models=["gpt-4"], + allowed_search_tools=["tavily-search"], + metadata={"user_info": "test"}, # No search_provider_config + ) + + # Verify metadata does not contain search_provider_config + assert mock_key.metadata is not None + assert "search_provider_config" not in mock_key.metadata + assert "api_key" not in str(mock_key.metadata) + + +@pytest.mark.asyncio +async def test_both_key_and_team_checks_required(): + """Test that both key-level and team-level checks are enforced.""" + # Key has access to tool + mock_key = UserAPIKeyAuth( + token="sk-test-key", + models=["gpt-4"], + allowed_search_tools=["tavily-search"], + ) + + # Team does NOT have access to tool + mock_team = LiteLLM_TeamTable( + team_id="team-123", + team_alias="Restricted Team", + models=["gpt-4"], + allowed_search_tools=["perplexity-search"], # Different tool + ) + + # Key check passes + await can_key_call_search_tool( + search_tool_name="tavily-search", + valid_token=mock_key, + ) + + # Team check fails + with pytest.raises(Exception) as exc_info: + await can_team_call_search_tool( + search_tool_name="tavily-search", + team_object=mock_team, + ) + assert "not allowed to access search tool" in str(exc_info.value) diff --git a/ui/litellm-dashboard/src/app/(dashboard)/teams/components/modals/CreateTeamModal.tsx b/ui/litellm-dashboard/src/app/(dashboard)/teams/components/modals/CreateTeamModal.tsx index 1859970091..2e14897792 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/teams/components/modals/CreateTeamModal.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/teams/components/modals/CreateTeamModal.tsx @@ -15,7 +15,15 @@ import ModelAliasManager from "@/components/common_components/ModelAliasManager" import React, { useEffect, useState } from "react"; import { useQueryClient } from "@tanstack/react-query"; import NotificationsManager from "@/components/molecules/notifications_manager"; -import { fetchMCPAccessGroups, getGuardrailsList, getPoliciesList, Organization, Team, teamCreateCall } from "@/components/networking"; +import { + fetchMCPAccessGroups, + fetchSearchTools, + getGuardrailsList, + getPoliciesList, + Organization, + Team, + teamCreateCall, +} from "@/components/networking"; import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized"; import { organizationKeys } from "@/app/(dashboard)/hooks/organizations/useOrganizations"; import MCPToolPermissions from "@/components/mcp_server_management/MCPToolPermissions"; @@ -80,6 +88,7 @@ const CreateTeamModal = ({ const [modelsToPick, setModelsToPick] = useState([]); const [guardrailsList, setGuardrailsList] = useState([]); const [policiesList, setPoliciesList] = useState([]); + const [searchToolNames, setSearchToolNames] = useState([]); const [mcpAccessGroups, setMcpAccessGroups] = useState([]); const [mcpAccessGroupsLoaded, setMcpAccessGroupsLoaded] = useState(false); @@ -158,6 +167,24 @@ const CreateTeamModal = ({ fetchPolicies(); }, [accessToken]); + useEffect(() => { + const loadSearchTools = async () => { + try { + if (!accessToken) return; + const response = await fetchSearchTools(accessToken); + const tools = Array.isArray(response?.data) ? response.data : []; + setSearchToolNames( + tools + .map((tool: any) => tool?.search_tool_name) + .filter((name: unknown): name is string => typeof name === "string" && name.length > 0), + ); + } catch (error) { + console.error("Failed to fetch search tools for team create modal:", error); + } + }; + loadSearchTools(); + }, [accessToken]); + const handleCreate = async (formValues: Record) => { try { console.log(`formValues: ${JSON.stringify(formValues)}`); @@ -395,6 +422,27 @@ const CreateTeamModal = ({ + + Allowed Search Tools{" "} + + + + + } + name="allowed_search_tools" + > + ({ label: name, value: name }))} + showSearch + optionFilterProp="label" + /> + + Team Member Settings diff --git a/ui/litellm-dashboard/src/components/OldTeams.tsx b/ui/litellm-dashboard/src/components/OldTeams.tsx index 8349e271b8..c7f39c0dcd 100644 --- a/ui/litellm-dashboard/src/components/OldTeams.tsx +++ b/ui/litellm-dashboard/src/components/OldTeams.tsx @@ -57,7 +57,14 @@ import type { KeyResponse, Team } from "./key_team_helpers/key_list"; import MCPServerSelector from "./mcp_server_management/MCPServerSelector"; import MCPToolPermissions from "./mcp_server_management/MCPToolPermissions"; import NotificationsManager from "./molecules/notifications_manager"; -import { Organization, fetchMCPAccessGroups, getGuardrailsList, getPoliciesList, teamDeleteCall } from "./networking"; +import { + Organization, + fetchMCPAccessGroups, + fetchSearchTools, + getGuardrailsList, + getPoliciesList, + teamDeleteCall, +} from "./networking"; import NumericalInput from "./shared/numerical_input"; import VectorStoreSelector from "./vector_store_management/VectorStoreSelector"; @@ -267,6 +274,7 @@ const Teams: React.FC = ({ // Add this state near the other useState declarations const [guardrailsList, setGuardrailsList] = useState([]); const [policiesList, setPoliciesList] = useState([]); + const [searchToolNames, setSearchToolNames] = useState([]); const [loggingSettings, setLoggingSettings] = useState([]); const [mcpAccessGroups, setMcpAccessGroups] = useState([]); const [mcpAccessGroupsLoaded, setMcpAccessGroupsLoaded] = useState(false); @@ -334,6 +342,24 @@ const Teams: React.FC = ({ fetchPolicies(); }, [accessToken]); + useEffect(() => { + const loadSearchTools = async () => { + try { + if (!accessToken) return; + const response = await fetchSearchTools(accessToken); + const tools = Array.isArray(response?.data) ? response.data : []; + setSearchToolNames( + tools + .map((tool: any) => tool?.search_tool_name) + .filter((name: unknown): name is string => typeof name === "string" && name.length > 0), + ); + } catch (error) { + console.error("Failed to fetch search tools:", error); + } + }; + loadSearchTools(); + }, [accessToken]); + const fetchMcpAccessGroups = async () => { try { if (accessToken == null) { @@ -1207,6 +1233,27 @@ const Teams: React.FC = ({ /> + + Allowed Search Tools{" "} + + + + + } + name="allowed_search_tools" + > + ({ label: name, value: name }))} + showSearch + filterOption={(input, option) => + (option?.label ?? "").toLowerCase().includes(input.toLowerCase()) + } + /> + + @@ -1416,29 +1439,6 @@ const TeamInfoView: React.FC = ({ /> - { - if (!value || (typeof value === "string" && value.trim() === "")) { - return Promise.resolve(); - } - try { - JSON.parse(value); - return Promise.resolve(); - } catch (error) { - return Promise.reject(new Error("Please enter valid JSON")); - } - }, - }, - ]} - > - - - = ({ )} - {info.metadata?.search_provider_config && ( -
- Search Provider Configuration -
-                          {JSON.stringify(info.metadata.search_provider_config, null, 2)}
-                        
-
- )} )}