diff --git a/ui/litellm-dashboard/src/components/shared/CreatedKeyDisplay.test.tsx b/ui/litellm-dashboard/src/components/shared/CreatedKeyDisplay.test.tsx index e35fd788759..4646f075b1d 100644 --- a/ui/litellm-dashboard/src/components/shared/CreatedKeyDisplay.test.tsx +++ b/ui/litellm-dashboard/src/components/shared/CreatedKeyDisplay.test.tsx @@ -2,7 +2,7 @@ import { cloneElement, type MouseEventHandler, type ReactElement, type ReactNode import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; import { render, screen, act } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { toSiTerminology } from "@/lib/terminology"; +import { TerminologyProvider, useTerminology } from "@/contexts/TerminologyContext"; import CreatedKeyDisplay, { buildAgentInstructions } from "./CreatedKeyDisplay"; import { toast } from "@/lib/toast"; @@ -13,6 +13,10 @@ vi.mock("@/components/networking", () => ({ getProxyBaseUrl: vi.fn(() => "http://gw.test:4000/"), })); +vi.mock("@/app/(dashboard)/hooks/uiConfig/useUIConfig", () => ({ + useUIConfig: () => ({ data: { use_si_terminology: true } }), +})); + vi.mock("react-copy-to-clipboard", () => ({ CopyToClipboard: ({ text, @@ -159,6 +163,23 @@ describe("CreatedKeyDisplay", () => { expect(screen.getByRole("button", { name: "Copied!" })).toBeInTheDocument(); expect(toast.success).toHaveBeenCalledWith("Instructions copied"); }); + + it("copies agent instructions in AI wording even when the UI uses SI terminology", async () => { + const user = userEvent.setup({ advanceTimers: vi.advanceTimersByTime }); + const GatewayLabel = () => {useTerminology()("AI Gateway")}; + render( + + + + , + ); + + expect(screen.getByText("SI Gateway")).toBeInTheDocument(); + await user.click(screen.getByRole("button", { name: "Copy instructions" })); + + expect(mockCopy).toHaveBeenLastCalledWith(buildAgentInstructions("http://gw.test:4000", "sk-test-123")); + expect(mockCopy.mock.calls.at(-1)?.[0]).toContain("Use this LiteLLM AI gateway for model inference."); + }); }); describe("buildAgentInstructions", () => { @@ -183,11 +204,4 @@ describe("buildAgentInstructions", () => { ].join("\n"), ); }); - - it("rewrites only its own copy under SI terminology, never the gateway URL or the key", () => { - const lines = buildAgentInstructions("http://AI.example.com/", "sk-AI-1", toSiTerminology).split("\n"); - expect(lines[0]).toBe("Use this LiteLLM SI gateway for model inference."); - expect(lines).toContain("Gateway URL: http://AI.example.com"); - expect(lines).toContain("Virtual key: sk-AI-1"); - }); }); diff --git a/ui/litellm-dashboard/src/components/shared/CreatedKeyDisplay.tsx b/ui/litellm-dashboard/src/components/shared/CreatedKeyDisplay.tsx index e483d2546bb..d58a1864575 100644 --- a/ui/litellm-dashboard/src/components/shared/CreatedKeyDisplay.tsx +++ b/ui/litellm-dashboard/src/components/shared/CreatedKeyDisplay.tsx @@ -1,5 +1,3 @@ -import { useTerminology } from "@/contexts/TerminologyContext"; -import { keepTerminology, type Term } from "@/lib/terminology"; import React, { useState } from "react"; import { CopyToClipboard } from "react-copy-to-clipboard"; import { ChevronDown, ChevronUp } from "lucide-react"; @@ -13,14 +11,14 @@ interface CreatedKeyDisplayProps { apiKey: string; } -export const buildAgentInstructions = (baseUrl: string, apiKey: string, term: Term = keepTerminology): string => { +export const buildAgentInstructions = (baseUrl: string, apiKey: string): string => { const normalizedBaseUrl = baseUrl.replace(/\/+$/, ""); const endpointIntroduction = "LiteLLM is a gateway that exposes OpenAI and Anthropic compatible APIs. " + `Send the virtual key as a Bearer token (Authorization: Bearer ${apiKey}) to:`; return [ - term("Use this LiteLLM AI gateway for model inference."), + "Use this LiteLLM AI gateway for model inference.", "", `Gateway URL: ${normalizedBaseUrl}`, `Virtual key: ${apiKey}`, @@ -43,12 +41,11 @@ export const buildAgentInstructions = (baseUrl: string, apiKey: string, term: Te * Used on the Virtual Keys page and in the Add Agent wizard. */ const CreatedKeyDisplay: React.FC = ({ apiKey }) => { - const term = useTerminology(); const [copied, setCopied] = useState(false); const [instructionsCopied, setInstructionsCopied] = useState(false); const [showInstructions, setShowInstructions] = useState(false); const baseUrl = getProxyBaseUrl().replace(/\/+$/, ""); - const instructions = buildAgentInstructions(baseUrl, apiKey, term); + const instructions = buildAgentInstructions(baseUrl, apiKey); const handleCopy = () => { setCopied(true); diff --git a/ui/litellm-dashboard/src/lib/terminology.test.ts b/ui/litellm-dashboard/src/lib/terminology.test.ts index 9e5d6af036e..7fa24cb4f83 100644 --- a/ui/litellm-dashboard/src/lib/terminology.test.ts +++ b/ui/litellm-dashboard/src/lib/terminology.test.ts @@ -39,6 +39,8 @@ describe("toSiTerminology", () => { ["Cisco AI Defense Inspection API for AI apps", "Cisco AI Defense Inspection API for SI apps"], ["DeepKeep AI Firewall for AI security", "DeepKeep AI Firewall for SI security"], ["Defend AI Agentic Guardrails", "Defend AI Agentic Guardrails"], + ["CyCraft XecGuard AI security gateway for AI apps", "CyCraft XecGuard AI security gateway for SI apps"], + ["Airia AI security platform for responsible AI", "Airia AI security platform for responsible SI"], ])("keeps third-party names inside %j", (input, expected) => { expect(toSiTerminology(input)).toBe(expected); }); diff --git a/ui/litellm-dashboard/src/lib/terminology.ts b/ui/litellm-dashboard/src/lib/terminology.ts index 0f18ae95fa9..e056ae59f55 100644 --- a/ui/litellm-dashboard/src/lib/terminology.ts +++ b/ui/litellm-dashboard/src/lib/terminology.ts @@ -9,6 +9,8 @@ const THIRD_PARTY_NAMES: readonly string[] = [ "DeepKeep AI Firewall", "Defend AI", "Prisma AI Runtime Security", + "XecGuard AI", + "Airia AI", ]; const THIRD_PARTY_NAME_PATTERN = new RegExp(`(${THIRD_PARTY_NAMES.join("|")})`);