diff --git a/ui/litellm-dashboard/src/components/playground/chat_ui/ChatImageUtils.test.tsx b/ui/litellm-dashboard/src/components/playground/chat_ui/ChatImageUtils.test.tsx
new file mode 100644
index 00000000000..ecc4914b0ab
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/playground/chat_ui/ChatImageUtils.test.tsx
@@ -0,0 +1,187 @@
+import { describe, expect, it, vi, beforeEach } from "vitest";
+import {
+ convertImageToBase64,
+ createChatMultimodalMessage,
+ createChatDisplayMessage,
+ shouldShowChatAttachedImage,
+} from "./ChatImageUtils";
+import { MessageType } from "./types";
+
+describe("ChatImageUtils", () => {
+ beforeEach(() => {
+ vi.clearAllMocks();
+ });
+
+ describe("convertImageToBase64", () => {
+ it("should convert file to base64 data URI", async () => {
+ const file = new File(["test content"], "test.png", { type: "image/png" });
+ const result = await convertImageToBase64(file);
+ expect(result).toMatch(/^data:image\/png;base64,/);
+ });
+
+ it("should handle different file types", async () => {
+ const jpegFile = new File(["jpeg content"], "test.jpg", { type: "image/jpeg" });
+ const result = await convertImageToBase64(jpegFile);
+ expect(result).toMatch(/^data:image\/jpeg;base64,/);
+ });
+
+ it("should reject on file read error", async () => {
+ const file = new File(["test"], "test.png", { type: "image/png" });
+ const originalReadAsDataURL = FileReader.prototype.readAsDataURL;
+
+ FileReader.prototype.readAsDataURL = vi.fn(function (this: FileReader) {
+ setTimeout(() => {
+ if (this.onerror) {
+ this.onerror(new Error("Read error") as any);
+ }
+ }, 0);
+ });
+
+ await expect(convertImageToBase64(file)).rejects.toThrow();
+
+ FileReader.prototype.readAsDataURL = originalReadAsDataURL;
+ });
+ });
+
+ describe("createChatMultimodalMessage", () => {
+ it("should create multimodal message with text and image", async () => {
+ const file = new File(["test content"], "test.png", { type: "image/png" });
+ const inputMessage = "What is in this image?";
+
+ const result = await createChatMultimodalMessage(inputMessage, file);
+
+ expect(result.role).toBe("user");
+ expect(result.content).toHaveLength(2);
+ expect(result.content[0]).toEqual({ type: "text", text: inputMessage });
+ expect(result.content[1]).toMatchObject({
+ type: "image_url",
+ image_url: {
+ url: expect.stringMatching(/^data:image\/png;base64,/),
+ },
+ });
+ });
+
+ it("should include base64 data URI in image_url", async () => {
+ const file = new File(["test content"], "test.png", { type: "image/png" });
+ const result = await createChatMultimodalMessage("test", file);
+
+ const imageContent = result.content[1];
+ expect(imageContent.type).toBe("image_url");
+ if ("image_url" in imageContent && imageContent.image_url) {
+ expect(imageContent.image_url.url).toMatch(/^data:/);
+ }
+ });
+ });
+
+ describe("createChatDisplayMessage", () => {
+ it("should create display message without file", () => {
+ const result = createChatDisplayMessage("Hello world", false);
+
+ expect(result.role).toBe("user");
+ expect(result.content).toBe("Hello world");
+ expect(result.imagePreviewUrl).toBeUndefined();
+ });
+
+ it("should create display message with PDF file", () => {
+ const filePreviewUrl = "blob:test-url";
+ const result = createChatDisplayMessage("Read this", true, filePreviewUrl, "document.pdf");
+
+ expect(result.content).toBe("Read this [PDF attached]");
+ expect(result.imagePreviewUrl).toBe(filePreviewUrl);
+ });
+
+ it("should create display message with image file", () => {
+ const filePreviewUrl = "blob:test-url";
+ const result = createChatDisplayMessage("Look at this", true, filePreviewUrl, "photo.jpg");
+
+ expect(result.content).toBe("Look at this [Image attached]");
+ expect(result.imagePreviewUrl).toBe(filePreviewUrl);
+ });
+
+ it("should create display message with file but no fileName", () => {
+ const filePreviewUrl = "blob:test-url";
+ const result = createChatDisplayMessage("Check this", true, filePreviewUrl);
+
+ expect(result.content).toBe("Check this ");
+ expect(result.imagePreviewUrl).toBe(filePreviewUrl);
+ });
+
+ it("should create display message with file but no preview URL", () => {
+ const result = createChatDisplayMessage("See this", true, undefined, "image.png");
+
+ expect(result.content).toBe("See this [Image attached]");
+ expect(result.imagePreviewUrl).toBeUndefined();
+ });
+ });
+
+ describe("shouldShowChatAttachedImage", () => {
+ it("should return true for user message with image attachment", () => {
+ const message: MessageType = {
+ role: "user",
+ content: "Check this [Image attached]",
+ imagePreviewUrl: "blob:test-url",
+ };
+
+ expect(shouldShowChatAttachedImage(message)).toBe(true);
+ });
+
+ it("should return true for user message with PDF attachment", () => {
+ const message: MessageType = {
+ role: "user",
+ content: "Read this [PDF attached]",
+ imagePreviewUrl: "blob:test-url",
+ };
+
+ expect(shouldShowChatAttachedImage(message)).toBe(true);
+ });
+
+ it("should return false for assistant message", () => {
+ const message: MessageType = {
+ role: "assistant",
+ content: "Here is the image [Image attached]",
+ imagePreviewUrl: "blob:test-url",
+ };
+
+ expect(shouldShowChatAttachedImage(message)).toBe(false);
+ });
+
+ it("should return false when content is not a string", () => {
+ const message: MessageType = {
+ role: "user",
+ content: [{ type: "input_text", text: "test" }],
+ imagePreviewUrl: "blob:test-url",
+ };
+
+ expect(shouldShowChatAttachedImage(message)).toBe(false);
+ });
+
+ it("should return false when content does not include attachment marker", () => {
+ const message: MessageType = {
+ role: "user",
+ content: "Just regular text",
+ imagePreviewUrl: "blob:test-url",
+ };
+
+ expect(shouldShowChatAttachedImage(message)).toBe(false);
+ });
+
+ it("should return false when imagePreviewUrl is missing", () => {
+ const message: MessageType = {
+ role: "user",
+ content: "Check this [Image attached]",
+ };
+
+ expect(shouldShowChatAttachedImage(message)).toBe(false);
+ });
+
+ it("should return false when imagePreviewUrl is empty string", () => {
+ const message: MessageType = {
+ role: "user",
+ content: "Check this [Image attached]",
+ imagePreviewUrl: "",
+ };
+
+ expect(shouldShowChatAttachedImage(message)).toBe(false);
+ });
+ });
+});
diff --git a/ui/litellm-dashboard/src/components/playground/chat_ui/CodeInterpreterOutput.test.tsx b/ui/litellm-dashboard/src/components/playground/chat_ui/CodeInterpreterOutput.test.tsx
new file mode 100644
index 00000000000..d87a74f4641
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/playground/chat_ui/CodeInterpreterOutput.test.tsx
@@ -0,0 +1,326 @@
+import { render, screen, waitFor } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import { describe, expect, it, vi, beforeEach, afterEach } from "vitest";
+import CodeInterpreterOutput from "./CodeInterpreterOutput";
+
+vi.mock("@/components/networking", () => ({
+ getProxyBaseUrl: vi.fn(() => "https://example.com"),
+}));
+
+global.fetch = vi.fn();
+
+describe("CodeInterpreterOutput", () => {
+ beforeEach(() => {
+ vi.clearAllMocks();
+ URL.createObjectURL = vi.fn((blob) => `blob:${blob}`);
+ URL.revokeObjectURL = vi.fn();
+ });
+
+ afterEach(() => {
+ vi.restoreAllMocks();
+ });
+
+ it("should render", () => {
+ render();
+
+ expect(screen.getByText("Python Code Executed")).toBeInTheDocument();
+ });
+
+ it("should display code in syntax highlighter", async () => {
+ const user = userEvent.setup();
+ const code = "print('hello world')";
+ const { container } = render();
+
+ expect(screen.getByText("Python Code Executed")).toBeInTheDocument();
+
+ const collapseHeader = screen.getByRole("button");
+ await user.click(collapseHeader);
+
+ await waitFor(() => {
+ const codeElement = container.querySelector("code.language-python");
+ expect(codeElement).toBeInTheDocument();
+ expect(codeElement?.textContent).toContain(code);
+ });
+ });
+
+ it("should fetch and display images from annotations", async () => {
+ const mockBlob = new Blob(["image data"], { type: "image/png" });
+ const mockResponse = {
+ ok: true,
+ blob: vi.fn().mockResolvedValue(mockBlob),
+ };
+
+ (global.fetch as any).mockResolvedValue(mockResponse);
+
+ const annotations = [
+ {
+ type: "container_file_citation" as const,
+ container_id: "container-1",
+ file_id: "file-1",
+ filename: "chart.png",
+ start_index: 0,
+ end_index: 10,
+ },
+ ];
+
+ render(
+ ,
+ );
+
+ await waitFor(() => {
+ expect(global.fetch).toHaveBeenCalledWith(
+ "https://example.com/v1/containers/container-1/files/file-1/content",
+ expect.objectContaining({
+ headers: {
+ Authorization: "Bearer test-token",
+ },
+ }),
+ );
+ });
+
+ await waitFor(() => {
+ expect(screen.getByText("chart.png")).toBeInTheDocument();
+ });
+ });
+
+ it("should show loading state while fetching images", async () => {
+ const mockBlob = new Blob(["image data"], { type: "image/png" });
+ let resolveBlob: (value: Blob) => void;
+ const blobPromise = new Promise((resolve) => {
+ resolveBlob = resolve;
+ });
+
+ const mockResponse = {
+ ok: true,
+ blob: vi.fn().mockReturnValue(blobPromise),
+ };
+
+ (global.fetch as any).mockResolvedValue(mockResponse);
+
+ const annotations = [
+ {
+ type: "container_file_citation" as const,
+ container_id: "container-1",
+ file_id: "file-1",
+ filename: "chart.png",
+ start_index: 0,
+ end_index: 10,
+ },
+ ];
+
+ render(
+ ,
+ );
+
+ await waitFor(() => {
+ expect(screen.getByText("Loading image...")).toBeInTheDocument();
+ });
+
+ resolveBlob!(mockBlob);
+ await waitFor(() => {
+ expect(screen.queryByText("Loading image...")).not.toBeInTheDocument();
+ });
+ });
+
+ it("should handle download for image files", async () => {
+ const user = userEvent.setup();
+ const mockBlob = new Blob(["image data"], { type: "image/png" });
+ const mockResponse = {
+ ok: true,
+ blob: vi.fn().mockResolvedValue(mockBlob),
+ };
+
+ (global.fetch as any).mockResolvedValue(mockResponse);
+
+ const annotations = [
+ {
+ type: "container_file_citation" as const,
+ container_id: "container-1",
+ file_id: "file-1",
+ filename: "chart.png",
+ start_index: 0,
+ end_index: 10,
+ },
+ ];
+
+ const createElementSpy = vi.spyOn(document, "createElement");
+ const appendChildSpy = vi.spyOn(document.body, "appendChild");
+ const removeChildSpy = vi.spyOn(document.body, "removeChild");
+
+ render(
+ ,
+ );
+
+ await waitFor(() => {
+ expect(screen.getByText("chart.png")).toBeInTheDocument();
+ });
+
+ const downloadButton = screen.getByText("Download");
+ await user.click(downloadButton);
+
+ await waitFor(() => {
+ expect(global.fetch).toHaveBeenCalledWith(
+ "https://example.com/v1/containers/container-1/files/file-1/content",
+ expect.objectContaining({
+ headers: {
+ Authorization: "Bearer test-token",
+ },
+ }),
+ );
+ });
+
+ createElementSpy.mockRestore();
+ appendChildSpy.mockRestore();
+ removeChildSpy.mockRestore();
+ });
+
+ it("should handle download for non-image files", async () => {
+ const user = userEvent.setup();
+ const mockBlob = new Blob(["file data"], { type: "text/plain" });
+ const mockResponse = {
+ ok: true,
+ blob: vi.fn().mockResolvedValue(mockBlob),
+ };
+
+ (global.fetch as any).mockResolvedValue(mockResponse);
+
+ const annotations = [
+ {
+ type: "container_file_citation" as const,
+ container_id: "container-1",
+ file_id: "file-1",
+ filename: "data.csv",
+ start_index: 0,
+ end_index: 10,
+ },
+ ];
+
+ render();
+
+ await waitFor(() => {
+ expect(screen.getByText("data.csv")).toBeInTheDocument();
+ });
+
+ const downloadButton = screen.getByText("data.csv").closest("button");
+ expect(downloadButton).toBeInTheDocument();
+ if (downloadButton) {
+ await user.click(downloadButton);
+ }
+
+ await waitFor(() => {
+ expect(global.fetch).toHaveBeenCalledWith(
+ "https://example.com/v1/containers/container-1/files/file-1/content",
+ expect.objectContaining({
+ headers: {
+ Authorization: "Bearer test-token",
+ },
+ }),
+ );
+ });
+ });
+
+ it("should return null when no code and no annotations", () => {
+ const { container } = render();
+
+ expect(container.firstChild).toBeNull();
+ });
+
+ it("should handle multiple image formats", async () => {
+ const mockBlob = new Blob(["image data"], { type: "image/png" });
+ const mockResponse = {
+ ok: true,
+ blob: vi.fn().mockResolvedValue(mockBlob),
+ };
+
+ (global.fetch as any).mockResolvedValue(mockResponse);
+
+ const annotations = [
+ {
+ type: "container_file_citation" as const,
+ container_id: "container-1",
+ file_id: "file-1",
+ filename: "image.png",
+ start_index: 0,
+ end_index: 10,
+ },
+ {
+ type: "container_file_citation" as const,
+ container_id: "container-1",
+ file_id: "file-2",
+ filename: "image.jpg",
+ start_index: 0,
+ end_index: 10,
+ },
+ {
+ type: "container_file_citation" as const,
+ container_id: "container-1",
+ file_id: "file-3",
+ filename: "image.jpeg",
+ start_index: 0,
+ end_index: 10,
+ },
+ {
+ type: "container_file_citation" as const,
+ container_id: "container-1",
+ file_id: "file-4",
+ filename: "image.gif",
+ start_index: 0,
+ end_index: 10,
+ },
+ ];
+
+ render(
+ ,
+ );
+
+ await waitFor(() => {
+ expect(global.fetch).toHaveBeenCalledTimes(4);
+ });
+ });
+
+ it("should handle fetch errors gracefully", async () => {
+ const consoleErrorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
+ (global.fetch as any).mockRejectedValue(new Error("Network error"));
+
+ const annotations = [
+ {
+ type: "container_file_citation" as const,
+ container_id: "container-1",
+ file_id: "file-1",
+ filename: "chart.png",
+ start_index: 0,
+ end_index: 10,
+ },
+ ];
+
+ render(
+ ,
+ );
+
+ await waitFor(() => {
+ expect(consoleErrorSpy).toHaveBeenCalled();
+ });
+
+ consoleErrorSpy.mockRestore();
+ });
+});
diff --git a/ui/litellm-dashboard/src/components/playground/compareUI/components/UnifiedSelector.test.tsx b/ui/litellm-dashboard/src/components/playground/compareUI/components/UnifiedSelector.test.tsx
new file mode 100644
index 00000000000..1c6951fc421
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/playground/compareUI/components/UnifiedSelector.test.tsx
@@ -0,0 +1,161 @@
+import { render, screen, waitFor } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import { describe, expect, it, vi } from "vitest";
+import { UnifiedSelector } from "./UnifiedSelector";
+import { EndpointId, ENDPOINT_CONFIGS } from "../endpoint_config";
+
+describe("UnifiedSelector", () => {
+ it("should render", () => {
+ const onChange = vi.fn();
+ const options = [
+ { value: "option1", label: "Option 1" },
+ { value: "option2", label: "Option 2" },
+ ];
+ const config = ENDPOINT_CONFIGS[EndpointId.CHAT_COMPLETIONS];
+
+ render();
+
+ const select = screen.getByRole("combobox");
+ expect(select).toBeInTheDocument();
+ });
+
+ it("should display placeholder when not loading", () => {
+ const onChange = vi.fn();
+ const options = [{ value: "option1", label: "Option 1" }];
+ const config = ENDPOINT_CONFIGS[EndpointId.CHAT_COMPLETIONS];
+
+ const { container } = render(
+ ,
+ );
+
+ const placeholder = container.querySelector(".ant-select-selection-placeholder");
+ expect(placeholder).toHaveTextContent(config.selectorPlaceholder);
+ });
+
+ it("should display loading placeholder when loading", () => {
+ const onChange = vi.fn();
+ const options = [{ value: "option1", label: "Option 1" }];
+ const config = ENDPOINT_CONFIGS[EndpointId.CHAT_COMPLETIONS];
+
+ const { container } = render(
+ ,
+ );
+
+ const placeholder = container.querySelector(".ant-select-selection-placeholder");
+ expect(placeholder).toHaveTextContent(`Loading ${config.selectorLabel.toLowerCase()}s...`);
+ });
+
+ it("should call onChange when option is selected", async () => {
+ const user = userEvent.setup();
+ const onChange = vi.fn();
+ const options = [
+ { value: "option1", label: "Option 1" },
+ { value: "option2", label: "Option 2" },
+ ];
+ const config = ENDPOINT_CONFIGS[EndpointId.CHAT_COMPLETIONS];
+
+ render();
+
+ const select = screen.getByRole("combobox");
+ await user.click(select);
+
+ await waitFor(() => {
+ const option = screen.getByText("Option 1");
+ expect(option).toBeInTheDocument();
+ });
+
+ const option = screen.getByText("Option 1");
+ await user.click(option);
+
+ await waitFor(() => {
+ expect(onChange).toHaveBeenCalled();
+ });
+ const callArgs = onChange.mock.calls[0];
+ expect(callArgs[0]).toBe("option1");
+ });
+
+ it("should display selected value", () => {
+ const onChange = vi.fn();
+ const options = [
+ { value: "option1", label: "Option 1" },
+ { value: "option2", label: "Option 2" },
+ ];
+ const config = ENDPOINT_CONFIGS[EndpointId.CHAT_COMPLETIONS];
+
+ const { container } = render(
+ ,
+ );
+
+ const selectedValue = container.querySelector(".ant-select-selection-item");
+ expect(selectedValue).toHaveTextContent("Option 1");
+ });
+
+ it("should filter options by search input", async () => {
+ const user = userEvent.setup();
+ const onChange = vi.fn();
+ const options = [
+ { value: "option1", label: "Option One" },
+ { value: "option2", label: "Option Two" },
+ { value: "option3", label: "Different" },
+ ];
+ const config = ENDPOINT_CONFIGS[EndpointId.CHAT_COMPLETIONS];
+
+ render();
+
+ const select = screen.getByRole("combobox");
+ await user.click(select);
+ await user.type(select, "One");
+
+ await waitFor(() => {
+ expect(screen.getByText("Option One")).toBeInTheDocument();
+ expect(screen.queryByText("Option Two")).not.toBeInTheDocument();
+ expect(screen.queryByText("Different")).not.toBeInTheDocument();
+ });
+ });
+
+ it("should show loading spinner in notFoundContent when loading", async () => {
+ const user = userEvent.setup();
+ const onChange = vi.fn();
+ const options: { value: string; label: string }[] = [];
+ const config = ENDPOINT_CONFIGS[EndpointId.CHAT_COMPLETIONS];
+
+ render();
+
+ const select = screen.getByRole("combobox");
+ await user.click(select);
+
+ await waitFor(() => {
+ const spin = document.querySelector(".ant-spin");
+ expect(spin).toBeInTheDocument();
+ });
+ });
+
+ it("should show no options message when not loading and no options", async () => {
+ const user = userEvent.setup();
+ const onChange = vi.fn();
+ const options: { value: string; label: string }[] = [];
+ const config = ENDPOINT_CONFIGS[EndpointId.CHAT_COMPLETIONS];
+
+ render();
+
+ const select = screen.getByRole("combobox");
+ await user.click(select);
+
+ await waitFor(() => {
+ expect(screen.getByText(`No ${config.selectorLabel.toLowerCase()}s available`)).toBeInTheDocument();
+ });
+ });
+
+ it("should work with agent endpoint config", () => {
+ const onChange = vi.fn();
+ const options = [{ value: "agent1", label: "Agent One" }];
+ const config = ENDPOINT_CONFIGS[EndpointId.A2A_AGENTS];
+
+ const { container } = render(
+ ,
+ );
+
+ const placeholder = container.querySelector(".ant-select-selection-placeholder");
+ expect(placeholder).toHaveTextContent(config.selectorPlaceholder);
+ });
+});
diff --git a/ui/litellm-dashboard/src/components/playground/compareUI/endpoint_config.test.ts b/ui/litellm-dashboard/src/components/playground/compareUI/endpoint_config.test.ts
new file mode 100644
index 00000000000..67ecf32fc2a
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/playground/compareUI/endpoint_config.test.ts
@@ -0,0 +1,104 @@
+import { describe, expect, it } from "vitest";
+import {
+ EndpointId,
+ ENDPOINT_CONFIGS,
+ getAvailableEndpoints,
+ getEndpointConfig,
+ isAgentEndpoint,
+ isModelEndpoint,
+ modelOptionsToSelectorOptions,
+ agentOptionsToSelectorOptions,
+ getSelectionFieldName,
+ getComparisonSelection,
+ hasValidSelection,
+} from "./endpoint_config";
+import { Agent } from "../llm_calls/fetch_agents";
+
+describe("endpoint_config", () => {
+ it("should export EndpointId constants", () => {
+ expect(EndpointId.CHAT_COMPLETIONS).toBe("/v1/chat/completions");
+ expect(EndpointId.A2A_AGENTS).toBe("/a2a");
+ });
+
+ it("should have endpoint configs for all endpoint IDs", () => {
+ expect(ENDPOINT_CONFIGS[EndpointId.CHAT_COMPLETIONS]).toBeDefined();
+ expect(ENDPOINT_CONFIGS[EndpointId.A2A_AGENTS]).toBeDefined();
+ expect(ENDPOINT_CONFIGS[EndpointId.CHAT_COMPLETIONS].selectorType).toBe("model");
+ expect(ENDPOINT_CONFIGS[EndpointId.A2A_AGENTS].selectorType).toBe("agent");
+ });
+
+ it("should get available endpoints", () => {
+ const endpoints = getAvailableEndpoints();
+ expect(endpoints).toHaveLength(2);
+ expect(endpoints).toContainEqual({
+ value: EndpointId.CHAT_COMPLETIONS,
+ label: "/v1/chat/completions",
+ });
+ expect(endpoints).toContainEqual({
+ value: EndpointId.A2A_AGENTS,
+ label: "/a2a (Agents)",
+ });
+ });
+
+ it("should get endpoint config by ID", () => {
+ const config = getEndpointConfig(EndpointId.CHAT_COMPLETIONS);
+ expect(config.id).toBe(EndpointId.CHAT_COMPLETIONS);
+ expect(config.selectorType).toBe("model");
+ expect(config.selectorLabel).toBe("Model");
+ });
+
+ it("should check if endpoint is agent endpoint", () => {
+ expect(isAgentEndpoint(EndpointId.A2A_AGENTS)).toBe(true);
+ expect(isAgentEndpoint(EndpointId.CHAT_COMPLETIONS)).toBe(false);
+ });
+
+ it("should check if endpoint is model endpoint", () => {
+ expect(isModelEndpoint(EndpointId.CHAT_COMPLETIONS)).toBe(true);
+ expect(isModelEndpoint(EndpointId.A2A_AGENTS)).toBe(false);
+ });
+
+ it("should convert model options to selector options", () => {
+ const models = ["gpt-4", "gpt-3.5-turbo", "claude-3"];
+ const options = modelOptionsToSelectorOptions(models);
+ expect(options).toHaveLength(3);
+ expect(options[0]).toEqual({ value: "gpt-4", label: "gpt-4" });
+ expect(options[1]).toEqual({ value: "gpt-3.5-turbo", label: "gpt-3.5-turbo" });
+ expect(options[2]).toEqual({ value: "claude-3", label: "claude-3" });
+ });
+
+ it("should convert agent options to selector options", () => {
+ const agents: Agent[] = [
+ { agent_id: "agent-1", agent_name: "Agent One" },
+ { agent_id: "agent-2", agent_name: "Agent Two" },
+ { agent_id: "agent-3", agent_name: undefined as any },
+ ];
+ const options = agentOptionsToSelectorOptions(agents);
+ expect(options).toHaveLength(3);
+ expect(options[0]).toEqual({ value: "Agent One", label: "Agent One" });
+ expect(options[1]).toEqual({ value: "Agent Two", label: "Agent Two" });
+ expect(options[2]).toEqual({ value: undefined, label: "agent-3" });
+ });
+
+ it("should get selection field name based on endpoint", () => {
+ expect(getSelectionFieldName(EndpointId.CHAT_COMPLETIONS)).toBe("model");
+ expect(getSelectionFieldName(EndpointId.A2A_AGENTS)).toBe("agent");
+ });
+
+ it("should get comparison selection based on endpoint", () => {
+ const comparison = { model: "gpt-4", agent: "agent-1" };
+ expect(getComparisonSelection(comparison, EndpointId.CHAT_COMPLETIONS)).toBe("gpt-4");
+ expect(getComparisonSelection(comparison, EndpointId.A2A_AGENTS)).toBe("agent-1");
+ });
+
+ it("should check if comparison has valid selection", () => {
+ const comparisonWithModel = { model: "gpt-4", agent: "" };
+ const comparisonWithAgent = { model: "", agent: "agent-1" };
+ const comparisonEmpty = { model: "", agent: "" };
+ const comparisonWhitespace = { model: " ", agent: "" };
+
+ expect(hasValidSelection(comparisonWithModel, EndpointId.CHAT_COMPLETIONS)).toBe(true);
+ expect(hasValidSelection(comparisonWithAgent, EndpointId.A2A_AGENTS)).toBe(true);
+ expect(hasValidSelection(comparisonEmpty, EndpointId.CHAT_COMPLETIONS)).toBe(false);
+ expect(hasValidSelection(comparisonWhitespace, EndpointId.CHAT_COMPLETIONS)).toBe(false);
+ });
+});