diff --git a/ui/litellm-dashboard/src/components/playground/chat_ui/ChatUI.test.tsx b/ui/litellm-dashboard/src/components/playground/chat_ui/ChatUI.test.tsx index 8c85fb3bb2b..d992ff0ecb4 100644 --- a/ui/litellm-dashboard/src/components/playground/chat_ui/ChatUI.test.tsx +++ b/ui/litellm-dashboard/src/components/playground/chat_ui/ChatUI.test.tsx @@ -253,7 +253,7 @@ describe("ChatUI", () => { }; const getMcpSelect = () => - screen.getByText("MCP Tool").closest("div")?.querySelector(".ant-select") as HTMLElement | null; + screen.getByText("MCP Servers").closest("div")?.querySelector(".ant-select") as HTMLElement | null; await selectEndpointOption("/v1/embeddings"); diff --git a/ui/litellm-dashboard/src/components/playground/llm_calls/chat_completion.test.tsx b/ui/litellm-dashboard/src/components/playground/llm_calls/chat_completion.test.tsx index 9e4cd9abebb..f86c051951e 100644 --- a/ui/litellm-dashboard/src/components/playground/llm_calls/chat_completion.test.tsx +++ b/ui/litellm-dashboard/src/components/playground/llm_calls/chat_completion.test.tsx @@ -115,4 +115,58 @@ describe("chat_completion", () => { max_tokens: 100, }); }); + + it("should configure MCP tools per server with restrictions", async () => { + const selectedMCPServers = ["server-1", "server-2"]; + const mcpServers = [ + { server_id: "server-1", alias: "alpha", server_name: "Alpha" }, + { server_id: "server-2", server_name: "Beta" }, + ]; + const mcpServerToolRestrictions = { + "server-1": ["toolA", "toolB"], + "server-2": ["toolC"], + } as Record; + + await makeOpenAIChatCompletionRequest( + mockChatHistory, + mockUpdateUI, + "gpt-4", + "test-token", + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + selectedMCPServers, + undefined, + undefined, + undefined, + undefined, + undefined, + mcpServers, + mcpServerToolRestrictions, + ); + + const callArgs = mockCreate.mock.calls[0][0]; + expect(callArgs.tool_choice).toBe("auto"); + expect(callArgs.tools).toEqual([ + { + type: "mcp", + server_label: "litellm", + server_url: "litellm_proxy/mcp/alpha", + require_approval: "never", + allowed_tools: ["toolA", "toolB"], + }, + { + type: "mcp", + server_label: "litellm", + server_url: "litellm_proxy/mcp/Beta", + require_approval: "never", + allowed_tools: ["toolC"], + }, + ]); + }); }); diff --git a/ui/litellm-dashboard/src/components/playground/llm_calls/responses_api.test.tsx b/ui/litellm-dashboard/src/components/playground/llm_calls/responses_api.test.tsx new file mode 100644 index 00000000000..40c8e41ffb3 --- /dev/null +++ b/ui/litellm-dashboard/src/components/playground/llm_calls/responses_api.test.tsx @@ -0,0 +1,125 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { makeOpenAIResponsesRequest } from "./responses_api"; +import { MessageType } from "../chat_ui/types"; + +vi.mock("@/components/networking", () => ({ + getProxyBaseUrl: vi.fn(() => "https://example.com"), +})); + +const mockResponsesCreate = vi.fn(); +const mockClient = { + responses: { + create: mockResponsesCreate, + }, +}; + +vi.mock("openai", () => ({ + default: { + OpenAI: vi.fn(() => mockClient), + }, +})); + +describe("responses_api", () => { + const mockUpdateTextUI = vi.fn(); + const messages: MessageType[] = [{ role: "user", content: "Hello" }]; + + beforeEach(() => { + const mockEvents = [ + { type: "response.output_text.delta", delta: "Hi" }, + { + type: "response.completed", + response: { + id: "resp_123", + usage: { output_tokens: 2, input_tokens: 5, total_tokens: 7 }, + }, + }, + ]; + + async function* mockStream() { + for (const event of mockEvents) { + yield event; + } + } + + mockResponsesCreate.mockResolvedValue(mockStream()); + }); + + afterEach(() => { + vi.clearAllMocks(); + }); + + it("should send a basic responses request", async () => { + await makeOpenAIResponsesRequest(messages, mockUpdateTextUI, "gpt-4", "test-token"); + + expect(mockResponsesCreate).toHaveBeenCalledTimes(1); + expect(mockResponsesCreate).toHaveBeenCalledWith( + expect.objectContaining({ + model: "gpt-4", + input: [ + { + role: "user", + content: "Hello", + type: "message", + }, + ], + stream: true, + }), + { signal: undefined }, + ); + expect(mockUpdateTextUI).toHaveBeenCalledWith("assistant", "Hi", "gpt-4"); + }); + + it("should configure MCP tools per server with restrictions", async () => { + const selectedMCPServers = ["server-1", "server-2"]; + const mcpServers = [ + { server_id: "server-1", alias: "alpha", server_name: "Alpha" }, + { server_id: "server-2", server_name: "Beta" }, + ]; + const mcpServerToolRestrictions: Record = { + "server-1": ["toolA"], + "server-2": ["toolB", "toolC"], + }; + + await makeOpenAIResponsesRequest( + messages, + mockUpdateTextUI, + "gpt-4", + "test-token", + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + selectedMCPServers, + undefined, + undefined, + undefined, + undefined, + undefined, + mcpServers, + mcpServerToolRestrictions, + ); + + const callArgs = mockResponsesCreate.mock.calls[0][0]; + expect(callArgs.tool_choice).toBe("auto"); + expect(callArgs.tools).toEqual([ + { + type: "mcp", + server_label: "litellm", + server_url: "litellm_proxy/mcp/alpha", + require_approval: "never", + allowed_tools: ["toolA"], + }, + { + type: "mcp", + server_label: "litellm", + server_url: "litellm_proxy/mcp/Beta", + require_approval: "never", + allowed_tools: ["toolB", "toolC"], + }, + ]); + }); +});