From 99ad65f2a2e0842ce7c40ce5e99441422cbbdd0e Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 30 May 2026 18:47:50 +0000 Subject: [PATCH] feat(ui): rewrite coding-agent prompt to surface gateway endpoints; drop key from prompt body The previous prompt described LiteLLM as 'OpenAI-compatible' and embedded the freshly-minted virtual key inline, which both undersold what the gateway actually does and bled the secret into anything the user pasted the prompt into. The new prompt body advertises the four endpoints reachable through one base URL (/chat/completions, /v1/messages, /v1/responses, /mcp) plus the /v1/models discovery hint, and links to the gateway quickstart, the Claude Code tutorial, the /v1/messages doc, and the MCP gateway doc. The key itself is no longer in the prompt; the agent is told to pull it from $LITELLM_API_KEY and pass it as Authorization: Bearer . The 'Your API Key' panel above the prompt still shows the raw key for the user to copy. Tests pin the new endpoint list, the new doc URLs, the $LITELLM_API_KEY placeholder, and that the literal key never appears inside the prompt. Co-authored-by: ishaan-berri --- .../shared/CreatedKeyDisplay.test.tsx | 31 +++++---- .../components/shared/CreatedKeyDisplay.tsx | 64 +++++++------------ 2 files changed, 40 insertions(+), 55 deletions(-) diff --git a/ui/litellm-dashboard/src/components/shared/CreatedKeyDisplay.test.tsx b/ui/litellm-dashboard/src/components/shared/CreatedKeyDisplay.test.tsx index bd789169885..9dbdebfe5d1 100644 --- a/ui/litellm-dashboard/src/components/shared/CreatedKeyDisplay.test.tsx +++ b/ui/litellm-dashboard/src/components/shared/CreatedKeyDisplay.test.tsx @@ -31,22 +31,30 @@ describe("CreatedKeyDisplay", () => { it("displays the security warning and modal heading", () => { render(); expect(screen.getByRole("heading", { name: /api key created/i })).toBeInTheDocument(); - expect( - screen.getByText(/make sure to copy your api key now/i), - ).toBeInTheDocument(); + expect(screen.getByText(/make sure to copy your api key now/i)).toBeInTheDocument(); expect(screen.getByText(/you won't be able to see it again/i)).toBeInTheDocument(); }); - it("builds a coding agent prompt that embeds the key, base URL, and docs links", () => { + it("builds a coding agent prompt that advertises the gateway endpoints and docs without leaking the key", () => { render(); const prompt = screen.getByTestId("coding-agent-prompt").textContent ?? ""; expect(prompt).toMatch(/Base URL: https:\/\/litellm\.example\.com/); - expect(prompt).toMatch(/API key: sk-test-123/); - expect(prompt).toContain("Authorization: Bearer sk-test-123"); - expect(prompt).toContain("https://litellm.example.com/v1/models"); + expect(prompt).not.toContain("sk-test-123"); + expect(prompt).toContain("$LITELLM_API_KEY"); + expect(prompt).toContain("Authorization: Bearer "); + + expect(prompt).toContain("/chat/completions"); + expect(prompt).toContain("/v1/messages"); + expect(prompt).toContain("/v1/responses"); + expect(prompt).toContain("/mcp"); + expect(prompt).toContain("/v1/models"); + + expect(prompt).toContain("https://docs.litellm.ai/docs/learn/gateway_quickstart"); + expect(prompt).toContain("https://docs.litellm.ai/docs/tutorials/claude_responses_api"); + expect(prompt).toContain("https://docs.litellm.ai/docs/anthropic_unified"); + expect(prompt).toContain("https://docs.litellm.ai/docs/mcp"); expect(prompt).toContain("https://docs.litellm.ai/llms.txt"); - expect(prompt).toContain("https://docs.litellm.ai/llms-full.txt"); }); it("does not produce a trailing slash in the base URL when proxyBaseUrl is provided", () => { @@ -71,12 +79,7 @@ describe("CreatedKeyDisplay", () => { const images = logos.querySelectorAll("img"); const altText = Array.from(images).map((img) => img.getAttribute("alt")); - expect(altText).toEqual([ - "Cursor", - "Claude Code", - "OpenAI Codex", - "GitHub Copilot", - ]); + expect(altText).toEqual(["Cursor", "Claude Code", "OpenAI Codex", "GitHub Copilot"]); }); it("copies the coding agent prompt to clipboard when its copy button is clicked", async () => { diff --git a/ui/litellm-dashboard/src/components/shared/CreatedKeyDisplay.tsx b/ui/litellm-dashboard/src/components/shared/CreatedKeyDisplay.tsx index efc747f1d79..237d23304a2 100644 --- a/ui/litellm-dashboard/src/components/shared/CreatedKeyDisplay.tsx +++ b/ui/litellm-dashboard/src/components/shared/CreatedKeyDisplay.tsx @@ -17,11 +17,7 @@ const codingAgentLogos: { name: string; src: string }[] = [ ]; const CodingAgentLogos: React.FC = () => ( -
+
{codingAgentLogos.map((logo, index) => ( (
); -const buildCodingAgentPrompt = (apiKey: string, baseUrl: string): string => { - return `You have access to LiteLLM, an OpenAI-compatible AI gateway that lets you call 100+ LLMs (OpenAI, Anthropic, Gemini, Bedrock, etc.) through a single API. +const buildCodingAgentPrompt = (baseUrl: string): string => { + return `You have access to LiteLLM, a single AI gateway that fronts 100+ LLMs (OpenAI, Anthropic, Gemini, Bedrock, Vertex, etc.) plus MCP tools. -Use these credentials: -- Base URL: ${baseUrl} -- API key: ${apiKey} +Base URL: ${baseUrl} +Auth: pass the user's LiteLLM virtual key (e.g. from \`$LITELLM_API_KEY\`) as \`Authorization: Bearer \`. Do not hardcode the key in source. -LiteLLM is a drop-in replacement for the OpenAI SDK. Point the SDK's \`base_url\` at the URL above and use the key as your \`OPENAI_API_KEY\`. To list the models available to this key, GET ${baseUrl}/v1/models with header \`Authorization: Bearer ${apiKey}\`. +Through this one base URL you can call: +- POST /chat/completions - OpenAI Chat Completions format +- POST /v1/messages - Anthropic Messages format (works with any provider) +- POST /v1/responses - OpenAI Responses API, including MCP tools via \`"server_url": "litellm_proxy"\` +- GET /mcp - MCP Gateway for tool discovery and invocation +- GET /v1/models - list the models this key can use -LiteLLM docs: -- llms.txt (overview + all doc links): https://docs.litellm.ai/llms.txt -- llms-full.txt (complete reference with inline code examples): https://docs.litellm.ai/llms-full.txt`; +Docs: +- Getting started: https://docs.litellm.ai/docs/learn/gateway_quickstart +- Claude Code with LiteLLM: https://docs.litellm.ai/docs/tutorials/claude_responses_api +- /v1/messages (Anthropic format) on LiteLLM: https://docs.litellm.ai/docs/anthropic_unified +- MCP gateway: https://docs.litellm.ai/docs/mcp +- Full doc index: https://docs.litellm.ai/llms.txt`; }; const resolveProxyBaseUrl = (): string => { @@ -70,10 +73,7 @@ const CreatedKeyDisplay: React.FC = ({ apiKey }) => { const [copiedKey, setCopiedKey] = useState(false); const [copiedPrompt, setCopiedPrompt] = useState(false); - const codingAgentPrompt = useMemo( - () => buildCodingAgentPrompt(apiKey, resolveProxyBaseUrl()), - [apiKey], - ); + const codingAgentPrompt = useMemo(() => buildCodingAgentPrompt(resolveProxyBaseUrl()), []); const handleCopyKey = () => { setCopiedKey(true); @@ -107,20 +107,12 @@ const CreatedKeyDisplay: React.FC = ({ apiKey }) => {
-
+
Your API Key -
@@ -140,25 +132,15 @@ const CreatedKeyDisplay: React.FC = ({ apiKey }) => {
-
+
- - Prompt for coding agents - + Prompt for coding agents
-