mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-01 02:02:20 +00:00
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 <key>. 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 <ishaan-berri@users.noreply.github.com>
This commit is contained in:
parent
679a690679
commit
99ad65f2a2
2 changed files with 40 additions and 55 deletions
|
|
@ -31,22 +31,30 @@ describe("CreatedKeyDisplay", () => {
|
|||
it("displays the security warning and modal heading", () => {
|
||||
render(<CreatedKeyDisplay apiKey="sk-test-123" />);
|
||||
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(<CreatedKeyDisplay apiKey="sk-test-123" />);
|
||||
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 <key>");
|
||||
|
||||
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 () => {
|
||||
|
|
|
|||
|
|
@ -17,11 +17,7 @@ const codingAgentLogos: { name: string; src: string }[] = [
|
|||
];
|
||||
|
||||
const CodingAgentLogos: React.FC = () => (
|
||||
<div
|
||||
className="flex items-center"
|
||||
aria-label="Compatible coding agents"
|
||||
data-testid="coding-agent-logos"
|
||||
>
|
||||
<div className="flex items-center" aria-label="Compatible coding agents" data-testid="coding-agent-logos">
|
||||
{codingAgentLogos.map((logo, index) => (
|
||||
<img
|
||||
key={logo.name}
|
||||
|
|
@ -44,18 +40,25 @@ const CodingAgentLogos: React.FC = () => (
|
|||
</div>
|
||||
);
|
||||
|
||||
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 <key>\`. 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<CreatedKeyDisplayProps> = ({ 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<CreatedKeyDisplayProps> = ({ apiKey }) => {
|
|||
</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="rounded-md border mb-4"
|
||||
style={{ borderColor: "#e5e7eb", background: "#fafafa" }}
|
||||
>
|
||||
<div className="rounded-md border mb-4" style={{ borderColor: "#e5e7eb", background: "#fafafa" }}>
|
||||
<div className="flex items-center justify-between px-3 pt-3 pb-1">
|
||||
<span className="text-sm font-medium text-gray-700">Your API Key</span>
|
||||
<Tooltip title={copiedKey ? "Copied!" : "Copy API key"}>
|
||||
<CopyToClipboard text={apiKey} onCopy={handleCopyKey}>
|
||||
<Button
|
||||
type="text"
|
||||
size="small"
|
||||
aria-label="Copy API key"
|
||||
icon={<CopyOutlined />}
|
||||
/>
|
||||
<Button type="text" size="small" aria-label="Copy API key" icon={<CopyOutlined />} />
|
||||
</CopyToClipboard>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
|
@ -140,25 +132,15 @@ const CreatedKeyDisplay: React.FC<CreatedKeyDisplayProps> = ({ apiKey }) => {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="rounded-md border"
|
||||
style={{ borderColor: "#e5e7eb", background: "#fafafa" }}
|
||||
>
|
||||
<div className="rounded-md border" style={{ borderColor: "#e5e7eb", background: "#fafafa" }}>
|
||||
<div className="flex items-center justify-between px-3 pt-3 pb-1">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm font-medium text-gray-700">
|
||||
Prompt for coding agents
|
||||
</span>
|
||||
<span className="text-sm font-medium text-gray-700">Prompt for coding agents</span>
|
||||
<CodingAgentLogos />
|
||||
</div>
|
||||
<Tooltip title={copiedPrompt ? "Copied!" : "Copy prompt"}>
|
||||
<CopyToClipboard text={codingAgentPrompt} onCopy={handleCopyPrompt}>
|
||||
<Button
|
||||
type="text"
|
||||
size="small"
|
||||
aria-label="Copy prompt for coding agents"
|
||||
icon={<CopyOutlined />}
|
||||
/>
|
||||
<Button type="text" size="small" aria-label="Copy prompt for coding agents" icon={<CopyOutlined />} />
|
||||
</CopyToClipboard>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue