Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1745,6 +1745,7 @@ jobs:
docker run -d \
-p 4000:4000 \
-e DATABASE_URL=postgresql://postgres:postgres@host.docker.internal:5432/circle_test \
-e LITELLM_MASTER_KEY="sk-1234" \
-e USE_PRISMA_MIGRATE=True \
-e FAKE_OPENAI_API_BASE=http://host.docker.internal:8190 \
-e AZURE_API_KEY=$AZURE_API_KEY \
Expand Down Expand Up @@ -1840,6 +1841,7 @@ jobs:
docker run -d \
-p 4000:4000 \
-e DATABASE_URL=postgresql://postgres:postgres@host.docker.internal:5432/circle_test \
-e LITELLM_MASTER_KEY="sk-1234" \
-e AZURE_API_KEY=$AZURE_API_KEY \
-e AZURE_API_BASE=$AZURE_API_BASE \
-e AZURE_API_VERSION="2024-05-01-preview" \
Expand Down
3 changes: 2 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ NOVITA_API_KEY = ""
INFINITY_API_KEY = ""

# Development Configs
LITELLM_MASTER_KEY = "sk-1234"
# Generate one with: echo "LITELLM_MASTER_KEY=sk-$(openssl rand -hex 32)"
LITELLM_MASTER_KEY = ""

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty master key locks out operators

Medium Severity

Copying the shipped .env examples sets LITELLM_MASTER_KEY to an empty string, which get_secret keeps as "" rather than None. Auth then requires a key, the empty master key never matches, and show_missing_vars_in_env only treats master_key is None as missing, so the setup page never appears.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit c8e0f2d. Configure here.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An empty key fails closed at this tip, verified live with 401s. #42019 merges first and refuses to boot on it, printing the generate command

DATABASE_URL = "postgresql://llmproxy:dbpassword9090@db:5432/litellm"
STORE_MODEL_IN_DB = "True"
5 changes: 4 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -268,10 +268,13 @@ If you want to build the Docker image yourself:
# Build using the non-root Dockerfile
docker build -f docker/Dockerfile.non_root -t litellm_dev .

# Generate a master key. Requests send it as the bearer token
export LITELLM_MASTER_KEY="sk-$(openssl rand -hex 32)"

# Run with your config
docker run \
-v $(pwd)/proxy_config.yaml:/app/config.yaml \
-e LITELLM_MASTER_KEY="sk-1234" \
-e LITELLM_MASTER_KEY \
-p 4000:4000 \
litellm_dev \
--config /app/config.yaml --detailed_debug
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ from a2a.utils.constants import TransportProtocol
from uuid import uuid4

base_url = "http://localhost:4000/a2a/my-agent" # LiteLLM proxy + agent name
headers = {"Authorization": "Bearer sk-1234"} # LiteLLM Virtual Key
headers = {"Authorization": "Bearer <your-master-key>"} # LiteLLM master key or a virtual key

async with httpx.AsyncClient(headers=headers, timeout=60.0) as http_client:
resolver = A2ACardResolver(httpx_client=http_client, base_url=base_url)
Expand Down Expand Up @@ -233,7 +233,7 @@ async with stdio_client(server_params) as (read, write):

```bash
curl -X POST 'http://0.0.0.0:4000/v1/chat/completions' \
-H 'Authorization: Bearer sk-1234' \
-H 'Authorization: Bearer <your-master-key>' \
-H 'Content-Type: application/json' \
-d '{
"model": "gpt-4o",
Expand All @@ -255,7 +255,7 @@ curl -X POST 'http://0.0.0.0:4000/v1/chat/completions' \
"LiteLLM": {
"url": "http://localhost:4000/mcp/",
"headers": {
"x-litellm-api-key": "Bearer sk-1234"
"x-litellm-api-key": "Bearer <your-master-key>"
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion docker/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
# YOU MUST CHANGE THESE BEFORE GOING INTO PRODUCTION
############

LITELLM_MASTER_KEY="sk-1234"
# Generate one with: echo "LITELLM_MASTER_KEY=sk-$(openssl rand -hex 32)"
LITELLM_MASTER_KEY=""

############
# Database - You can change these to any PostgreSQL database that has logical replication enabled.
Expand Down
2 changes: 1 addition & 1 deletion litellm/anthropic_interface/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ import anthropic
# point anthropic sdk to litellm proxy
client = anthropic.Anthropic(
base_url="http://0.0.0.0:4000",
api_key="sk-1234",
api_key="<your-master-key>",
Comment thread
greptile-apps[bot] marked this conversation as resolved.
)

response = client.messages.create(
Expand Down
9 changes: 5 additions & 4 deletions litellm/containers/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,14 +183,14 @@ def get_provider_container_config(
```bash
# Create container via Azure
curl -X POST "http://localhost:4000/v1/containers" \
-H "Authorization: Bearer sk-1234" \
-H "Authorization: Bearer <your-master-key>" \
-H "custom-llm-provider: azure" \
-H "Content-Type: application/json" \
-d '{"name": "My Azure Container"}'

# List container files via Azure
curl -X GET "http://localhost:4000/v1/containers/cntr_123/files" \
-H "Authorization: Bearer sk-1234" \
-H "Authorization: Bearer <your-master-key>" \
-H "custom-llm-provider: azure"
```

Expand Down Expand Up @@ -219,12 +219,13 @@ python -m pytest tests/test_litellm/containers/ -v
Test via proxy:

```bash
# Start proxy
# Start proxy (proxy_config.yaml reads its master key from LITELLM_MASTER_KEY)
export LITELLM_MASTER_KEY="sk-$(openssl rand -hex 32)"
cd litellm/proxy && python proxy_cli.py --config proxy_config.yaml --port 4000

# Test endpoints
curl -X GET "http://localhost:4000/v1/containers/cntr_123/files" \
-H "Authorization: Bearer sk-1234"
-H "Authorization: Bearer $LITELLM_MASTER_KEY"
```

---
Expand Down
2 changes: 1 addition & 1 deletion litellm/integrations/bitbucket/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ litellm --config config.yaml --detailed_debug
```bash
curl -L -X POST 'http://0.0.0.0:4000/v1/chat/completions' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer sk-1234' \
-H 'Authorization: Bearer <your-master-key>' \
-d '{
"model": "my-bitbucket-model",
"messages": [{"role": "user", "content": "IGNORED"}],
Expand Down
2 changes: 1 addition & 1 deletion litellm/integrations/gitlab/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ litellm --config config.yaml --detailed_debug
```bash
curl -L -X POST 'http://0.0.0.0:4000/v1/chat/completions' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer sk-1234' \
-H 'Authorization: Bearer <your-master-key>' \
-d '{
"model": "my-gitlab-model",
"messages": [{"role": "user", "content": "IGNORED"}],
Expand Down
2 changes: 1 addition & 1 deletion litellm/proxy/_new_secret_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,4 @@ litellm_settings:
drop_params: True

general_settings:
master_key: sk-1234 # REPLACE in production
master_key: os.environ/LITELLM_MASTER_KEY
3 changes: 2 additions & 1 deletion litellm/proxy/common_utils/admin_ui_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ def missing_keys_form(missing_key_names: str):
<h1>Environment Setup Instructions</h1>
<p>Please add the following variables to your environment variables:</p>
<pre>
<span class="env-var">LITELLM_MASTER_KEY="sk-1234"</span> <span class="comment"># Your master key for the proxy server. Can use this to send /chat/completion requests etc</span>
<span class="comment"># Generate one with: echo "LITELLM_MASTER_KEY=sk-$(openssl rand -hex 32)"</span>
<span class="env-var">LITELLM_MASTER_KEY=""</span> <span class="comment"># Your master key for the proxy server. Can use this to send /chat/completion requests etc</span>
<span class="env-var">LITELLM_SALT_KEY="sk-XXXXXXXX"</span> <span class="comment"># Can NOT CHANGE THIS ONCE SET - It is used to encrypt/decrypt credentials stored in DB. If value of 'LITELLM_SALT_KEY' changes your models cannot be retrieved from DB</span>
<span class="env-var">DATABASE_URL="postgres://..."</span> <span class="comment"># Need a postgres database? (Check out Supabase, Neon, etc)</span>
<span class="comment">## OPTIONAL ##</span>
Expand Down
2 changes: 1 addition & 1 deletion litellm/proxy/dev_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ model_list:
api_key: os.environ/OPENAI_API_KEY

general_settings:
master_key: sk-1234
master_key: os.environ/LITELLM_MASTER_KEY
# Opt-in: let CheckBatchCost track cost for unmanaged batches created with a raw
# gs:// (Vertex) or s3:// (Bedrock) input_file_id. Requires a matching deployment
# configured for the batched model. Defaults to false.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,4 @@ litellm_settings:
drop_params: True

general_settings:
master_key: sk-1234 # REPLACE in production
master_key: os.environ/LITELLM_MASTER_KEY
2 changes: 1 addition & 1 deletion litellm/proxy/example_config_yaml/oai_misc_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,4 @@ files_settings:
api_key: os.environ/OPENAI_API_KEY

general_settings:
master_key: sk-1234 # [OPTIONAL] Use to enforce auth on proxy. See - https://docs.litellm.ai/docs/proxy/virtual_keys
master_key: os.environ/LITELLM_MASTER_KEY # [OPTIONAL] Use to enforce auth on proxy. See - https://docs.litellm.ai/docs/proxy/virtual_keys
2 changes: 1 addition & 1 deletion litellm/proxy/example_config_yaml/pass_through_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ model_list:
model: openai/*
api_key: os.environ/OPENAI_API_KEY
general_settings:
master_key: sk-1234
master_key: os.environ/LITELLM_MASTER_KEY
custom_auth: custom_auth_basic.user_api_key_auth
pass_through_endpoints:
- path: "/azure-config-passthrough"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ model_list:
api_key: os.environ/OPENAI_API_KEY

general_settings:
master_key: sk-1234
master_key: os.environ/LITELLM_MASTER_KEY
database_url: "postgresql://user:password@localhost:5432/litellm"

# Reject requests that contain client-side metadata.tags
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ guardrails:

# Optional: Configure general settings
general_settings:
master_key: sk-1234
master_key: os.environ/LITELLM_MASTER_KEY

# Optional: Add logging configuration
litellm_settings:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ litellm_settings:

# 1. Apply guardrail to a specific request:
# curl --location 'http://localhost:4000/chat/completions' \
# --header 'Authorization: Bearer sk-1234' \
# --header 'Authorization: Bearer <your-master-key>' \
# --header 'Content-Type: application/json' \
# --data '{
# "model": "gpt-4",
Expand All @@ -35,7 +35,7 @@ litellm_settings:

# 2. Apply guardrail with dynamic parameters:
# curl --location 'http://localhost:4000/chat/completions' \
# --header 'Authorization: Bearer sk-1234' \
# --header 'Authorization: Bearer <your-master-key>' \
# --header 'Content-Type: application/json' \
# --data '{
# "model": "gpt-4",
Expand Down
2 changes: 1 addition & 1 deletion litellm/proxy/proxy_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ mcp_servers:

# General Settings
general_settings:
master_key: sk-1234
master_key: os.environ/LITELLM_MASTER_KEY
store_model_in_db: false

# LiteLLM Settings
Expand Down
2 changes: 1 addition & 1 deletion litellm/proxy/wildcard_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ model_list:
api_key: os.environ/OPENAI_API_KEY

general_settings:
master_key: sk-1234
master_key: os.environ/LITELLM_MASTER_KEY

litellm_settings:
drop_params: True
Expand Down
8 changes: 4 additions & 4 deletions litellm/proxy/workflows/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,27 +48,27 @@ GET /v1/workflows/runs/{run_id}/messages Conversation history (ordered by se
```bash
# Create a run
curl -X POST http://localhost:4000/v1/workflows/runs \
-H "Authorization: Bearer sk-1234" \
-H "Authorization: Bearer <your-master-key>" \
-H "Content-Type: application/json" \
-d '{"workflow_type": "shin-builder", "metadata": {"title": "Fix login bug"}}'

# {"run_id": "abc-123", "session_id": "xyz-456", "status": "pending", ...}

# Mark step started (sets status → running)
curl -X POST http://localhost:4000/v1/workflows/runs/abc-123/events \
-H "Authorization: Bearer sk-1234" \
-H "Authorization: Bearer <your-master-key>" \
-H "Content-Type: application/json" \
-d '{"event_type": "step.started", "step_name": "grill", "data": {"claude_session_id": "sess-789"}}'

# Store a conversation message
curl -X POST http://localhost:4000/v1/workflows/runs/abc-123/messages \
-H "Authorization: Bearer sk-1234" \
-H "Authorization: Bearer <your-master-key>" \
-H "Content-Type: application/json" \
-d '{"role": "user", "content": "What is the expected behavior?", "session_id": "sess-789"}'

# Restart recovery: fetch active runs and resume from last event's data.claude_session_id
curl "http://localhost:4000/v1/workflows/runs?status=running,paused&workflow_type=shin-builder" \
-H "Authorization: Bearer sk-1234"
-H "Authorization: Bearer <your-master-key>"
```

## Status Auto-Update Rules
Expand Down
2 changes: 1 addition & 1 deletion proxy_server_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ router_settings:
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
master_key: os.environ/LITELLM_MASTER_KEY # [OPTIONAL] Use to enforce auth on proxy. See - https://docs.litellm.ai/docs/proxy/virtual_keys
Comment thread
greptile-apps[bot] marked this conversation as resolved.
store_model_in_db: True
proxy_budget_rescheduler_min_time: 60
proxy_budget_rescheduler_max_time: 64
Expand Down
8 changes: 5 additions & 3 deletions scripts/adaptive_router_demo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ The repo ships with a working example config:

```bash
export OPENAI_API_KEY=sk-... # underlying models hit OpenAI
export LITELLM_MASTER_KEY="sk-$(openssl rand -hex 32)" # the example config reads its master key from here
echo "$LITELLM_MASTER_KEY" # copy it, the chat page and dashboard ask for it
uv run litellm \
--config litellm/proxy/example_config_yaml/adaptive_router_example.yaml \
--port 4000
Expand Down Expand Up @@ -83,19 +85,19 @@ The dashboard is a single static HTML file. Either:
In the connect bar, fill in:

- **Proxy URL:** `http://localhost:4000`
- **Master Key:** the `master_key` from your config (`sk-1234` in the example).
- **Master Key:** the `LITELLM_MASTER_KEY` printed in step 1.

Click **Connect**. The dashboard polls `GET /adaptive_router/state` every
500ms (admin-only endpoint, returns one snapshot per configured router).

## 5. Drive synthetic traffic

In a second terminal:
In a second terminal, replacing `<your-master-key>` with the key printed in step 1:

```bash
uv run python scripts/adaptive_router_demo/traffic.py \
--proxy-url http://localhost:4000 \
--api-key sk-1234 \
--api-key <your-master-key> \
--router smart-cheap-router \
--rounds 100 \
--rate 0.5
Expand Down
12 changes: 12 additions & 0 deletions tests/test_litellm/proxy/common_utils/test_admin_ui_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import re

from litellm.proxy.common_utils.admin_ui_utils import missing_keys_form


def test_missing_keys_form_shows_generate_command_instead_of_a_literal_master_key():
html = missing_keys_form(missing_key_names="DATABASE_URL, LITELLM_MASTER_KEY")

assert "DATABASE_URL, LITELLM_MASTER_KEY" in html
assert 'echo "LITELLM_MASTER_KEY=sk-$(openssl rand -hex 32)"' in html
suggested_master_key_values = re.findall(r'LITELLM_MASTER_KEY="([^"]*)"', html)
assert suggested_master_key_values == [""]
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,14 @@ llm = AzureOpenAI(
engine="azure-gpt-3.5", # model_name on litellm proxy
temperature=0.0,
azure_endpoint="${base_url}", # litellm proxy endpoint
api_key="sk-1234", # litellm proxy API Key
api_key="<your-master-key>", # litellm proxy API Key
api_version="2023-07-01-preview",
)
embed_model = AzureOpenAIEmbedding(
deployment_name="azure-embedding-model",
azure_endpoint="${base_url}",
api_key="sk-1234",
api_key="<your-master-key>",
api_version="2023-07-01-preview",
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ const HowItWorks: React.FC = () => {
language="bash"
code={`curl -X POST -i http://your-proxy:4000/chat/completions \\
-H "Content-Type: application/json" \\
-H "Authorization: Bearer sk-1234" \\
-H "Authorization: Bearer <your-master-key>" \\
-d '{
"model": "gemini/gemini-2.5-pro",
"messages": [{"role": "user", "content": "Hello"}]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
};

const controlUnder = (label: string): HTMLElement =>
within(screen.getByText(label).parentElement!).getByRole("combobox");

Check warning on line 71 in ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/AgentBuilderView.test.tsx

View workflow job for this annotation

GitHub Actions / frontend-lint

Avoid direct Node access. Prefer using the methods from Testing Library

const renderView = () => render(<AgentBuilderView {...props} />);

Expand Down Expand Up @@ -115,11 +115,11 @@

renderView();

expect(document.querySelector('[aria-busy="true"]')).toBeInTheDocument();

Check warning on line 118 in ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/AgentBuilderView.test.tsx

View workflow job for this annotation

GitHub Actions / frontend-lint

Avoid direct Node access. Prefer using the methods from Testing Library

release(AGENTS);
await waitForRoster();
expect(document.querySelector('[aria-busy="true"]')).not.toBeInTheDocument();

Check warning on line 122 in ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/AgentBuilderView.test.tsx

View workflow job for this annotation

GitHub Actions / frontend-lint

Avoid direct Node access. Prefer using the methods from Testing Library
});

it("lists every agent and opens the first one's configuration", async () => {
Expand Down Expand Up @@ -236,6 +236,7 @@
const snippet = await screen.findByTestId("code-block");
expect(snippet).toHaveTextContent("https://proxy.example.com/v1/chat/completions");
expect(snippet).toHaveTextContent('"model": "support-agent"');
expect(snippet).toHaveTextContent("x-litellm-api-key: Bearer <your-master-key>");
});

it("mints a key scoped to the selected agent", async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@
? createdKeyValue.startsWith("Bearer ")
? createdKeyValue
: `Bearer ${createdKeyValue}`
: "Bearer sk-1234";
: "Bearer <your-master-key>";
const curlExample = `curl -L -X POST '${baseUrl}/v1/chat/completions' \\
-H 'x-litellm-api-key: ${apiKeyForCurl}' \\
-d '{
Expand Down Expand Up @@ -184,7 +184,7 @@
.filter((id): id is string => id != null);
}

export default function AgentBuilderView({

Check warning on line 187 in ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/AgentBuilderView.tsx

View workflow job for this annotation

GitHub Actions / frontend-lint

Function 'AgentBuilderView' has a complexity of 41. Maximum allowed is 20
accessToken,
token,
userID,
Expand Down Expand Up @@ -245,7 +245,7 @@
} finally {
setLoadingAgents(false);
}
}, [accessToken, userID, userRole]);

Check warning on line 248 in ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/AgentBuilderView.tsx

View workflow job for this annotation

GitHub Actions / frontend-lint

React Hook useCallback has a missing dependency: 'selectedId'. Either include it or remove the dependency array

const loadModels = useCallback(async () => {
if (!effectiveApiKey) return;
Expand All @@ -258,7 +258,7 @@
} catch (e) {
console.error(e);
}
}, [effectiveApiKey]);

Check warning on line 261 in ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/AgentBuilderView.tsx

View workflow job for this annotation

GitHub Actions / frontend-lint

React Hook useCallback has a missing dependency: 'draftUnderlyingModel'. Either include it or remove the dependency array

useEffect(() => {
loadAgents();
Expand Down Expand Up @@ -304,7 +304,7 @@
const tools: MCPToolEntry[] = Array.isArray(rawTools)
? rawTools.filter(
(t): t is MCPToolEntry =>
t &&

Check warning on line 307 in ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/AgentBuilderView.tsx

View workflow job for this annotation

GitHub Actions / frontend-lint

Boolean expression combines 4 conditions; extract it into a named variable
typeof t === "object" &&
(t as MCPToolEntry).type === "mcp" &&
typeof (t as MCPToolEntry).server_url === "string",
Expand All @@ -312,7 +312,7 @@
: [];
setDraftTools(tools);
}
}, [selectedId, isNewAgent, selectedAgent?.model_name, selectedAgent?.litellm_params?.tools]);

Check warning on line 315 in ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/AgentBuilderView.tsx

View workflow job for this annotation

GitHub Actions / frontend-lint

React Hook useEffect has missing dependencies: 'modelGroups' and 'selectedAgent'. Either include them or remove the dependency array. You can also replace multiple useState variables with useReducer if 'setDraftUnderlyingModel' needs the current value of 'modelGroups'

const selectedMCPServerIds = getServerIdsFromTools(draftTools, mcpServers);

Expand Down Expand Up @@ -367,7 +367,7 @@
};

const handleUpdateAgent = async () => {
if (!accessToken || !selectedAgent || !selectedAgentModelId || !draftName?.trim() || !draftUnderlyingModel) {

Check warning on line 370 in ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/AgentBuilderView.tsx

View workflow job for this annotation

GitHub Actions / frontend-lint

Boolean expression combines 5 conditions; extract it into a named variable
toast.fromError("Name and underlying model are required");
return;
}
Expand Down Expand Up @@ -526,7 +526,7 @@

{/* Main content */}
<div className="flex flex-1 flex-col overflow-hidden">
{selectedId === null && !isNewAgent && agentModels.length === 0 && !loadingAgents && (

Check warning on line 529 in ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/AgentBuilderView.tsx

View workflow job for this annotation

GitHub Actions / frontend-lint

Boolean expression combines 5 conditions; extract it into a named variable
<div className="flex flex-1 items-center justify-center p-8 text-muted-foreground">
No agents yet. Add an agent to get started.
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ describe("PromptCodeSnippets", () => {
expect(screen.getByRole("combobox", { name: "Language" })).toHaveTextContent("Python (OpenAI SDK)");
});

it("shows a key placeholder when there is no access token", async () => {
const user = userEvent.setup({ pointerEventsCheck: PointerEventsCheckLevel.Never });
render(<PromptCodeSnippets promptId="welcome" model="gpt-4o" accessToken={null} version="2" />);
await user.click(screen.getByRole("button", { name: /get code/i }));
await screen.findByText("Generated Code");

await user.click(screen.getByRole("button", { name: /copy to clipboard/i }));
expect(await navigator.clipboard.readText()).toContain("'Authorization: Bearer <your-master-key>'");
});

it("includes the viewed environment in every generated request", async () => {
const user = userEvent.setup({ pointerEventsCheck: PointerEventsCheckLevel.Never });
render(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ const PromptCodeSnippets: React.FC<PromptCodeSnippetsProps> = ({
apiBase = proxySettings.PROXY_BASE_URL;
}

const effectiveApiKey = accessToken || "sk-1234";
const effectiveApiKey = accessToken || "<your-master-key>";

// Generate code based on selected language and tab
const generateCode = () => {
Expand Down
Loading
Loading