Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,21 @@
expect(screen.getByText("Hi there")).toBeInTheDocument();
});

it.each([
{ role: "user" as const, bubble: ["bg-info/10", "border-info/20"], avatar: "bg-info/20" },
{ role: "assistant" as const, bubble: ["bg-card", "border-border"], avatar: "bg-muted" },
])("should paint the $role surface from theme tokens, not fixed colours", ({ role, bubble, avatar }) => {
render(<ChatMessageBubble {...defaultProps} message={{ role, content: "Hello" }} />);

const header = screen.getByText(role).closest("div") as HTMLElement;
const surface = header.parentElement as HTMLElement;

expect(surface).toHaveClass(...bubble);
expect(surface).not.toHaveAttribute("style");
expect(header.firstElementChild).toHaveClass(avatar);
expect(header.firstElementChild).not.toHaveAttribute("style");
});

it("should show model badge for assistant messages when model is provided", () => {
render(<ChatMessageBubble {...defaultProps} message={{ role: "assistant", content: "Reply", model: "gpt-4" }} />);

Expand Down Expand Up @@ -143,7 +158,7 @@
{...defaultProps}
isLastMessage={true}
endpointType={EndpointType.RESPONSES}
mcpEvents={mcpEvents as any}

Check warning on line 161 in ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/ChatMessageBubble.test.tsx

View workflow job for this annotation

GitHub Actions / frontend-lint

Unexpected any. Specify a different type
message={{ role: "assistant", content: "response" }}
/>,
);
Expand All @@ -159,7 +174,7 @@
{...defaultProps}
isLastMessage={true}
endpointType={EndpointType.CHAT}
mcpEvents={mcpEvents as any}

Check warning on line 177 in ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/ChatMessageBubble.test.tsx

View workflow job for this annotation

GitHub Actions / frontend-lint

Unexpected any. Specify a different type
message={{ role: "assistant", content: "response" }}
/>,
);
Expand All @@ -175,7 +190,7 @@
{...defaultProps}
isLastMessage={false}
endpointType={EndpointType.RESPONSES}
mcpEvents={mcpEvents as any}

Check warning on line 193 in ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/ChatMessageBubble.test.tsx

View workflow job for this annotation

GitHub Actions / frontend-lint

Unexpected any. Specify a different type
message={{ role: "assistant", content: "response" }}
/>,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
accessToken: string;
}

function ChatMessageBubble({

Check warning on line 35 in ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/ChatMessageBubble.tsx

View workflow job for this annotation

GitHub Actions / frontend-lint

Function 'ChatMessageBubble' has a complexity of 33. Maximum allowed is 20
message,
isLastMessage,
endpointType,
Expand All @@ -46,20 +46,16 @@
return (
<div className={`mb-4 min-w-0 ${isUser ? "text-right" : "text-left"}`}>
<div
className="inline-block min-w-0 max-w-[92%] overflow-hidden rounded-lg p-3 shadow-xs sm:max-w-[85%] sm:px-4"
style={{
backgroundColor: isUser ? "#f0f8ff" : "#ffffff",
border: isUser ? "1px solid #e6f0fa" : "1px solid #f0f0f0",
textAlign: "left",
}}
className={`inline-block min-w-0 max-w-[92%] overflow-hidden rounded-lg border p-3 text-left text-card-foreground shadow-xs sm:max-w-[85%] sm:px-4 ${
isUser ? "border-info/20 bg-info/10" : "border-border bg-card"
}`}
>
{/* Header: role icon + name + model badge */}
<div className="mb-1.5 flex min-w-0 items-center gap-2">
<div
className="flex items-center justify-center w-6 h-6 rounded-full mr-1"
style={{
backgroundColor: isUser ? "#e6f0fa" : "#f5f5f5",
}}
className={`flex items-center justify-center w-6 h-6 rounded-full mr-1 ${
isUser ? "bg-info/20" : "bg-muted"
}`}
>
{isUser ? (
<User className="size-3 text-info" aria-hidden="true" />
Expand All @@ -79,7 +75,7 @@
{message.reasoningContent && <ReasoningContent reasoningContent={message.reasoningContent} />}

{/* MCP events at the start of the last assistant message */}
{message.role === "assistant" &&

Check warning on line 78 in ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/ChatMessageBubble.tsx

View workflow job for this annotation

GitHub Actions / frontend-lint

Boolean expression combines 6 conditions; extract it into a named variable
isLastMessage &&
mcpEvents.length > 0 &&
(endpointType === EndpointType.RESPONSES || endpointType === EndpointType.CHAT) && (
Expand All @@ -94,7 +90,7 @@
)}

{/* Code Interpreter output for the last assistant message */}
{message.role === "assistant" &&

Check warning on line 93 in ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/ChatMessageBubble.tsx

View workflow job for this annotation

GitHub Actions / frontend-lint

Boolean expression combines 5 conditions; extract it into a named variable
isLastMessage &&
codeInterpreterResult &&
endpointType === EndpointType.RESPONSES && (
Expand All @@ -117,7 +113,7 @@
}}
>
{message.isImage ? (
<img

Check warning on line 116 in ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/ChatMessageBubble.tsx

View workflow job for this annotation

GitHub Actions / frontend-lint

Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` or a custom image loader to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element
src={typeof message.content === "string" ? message.content : ""}
alt="Generated image"
className="max-w-full rounded-md border border-border shadow-xs"
Expand Down Expand Up @@ -175,7 +171,7 @@
{/* Generated image from chat completions */}
{message.image && (
<div className="mt-3">
<img

Check warning on line 174 in ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/ChatMessageBubble.tsx

View workflow job for this annotation

GitHub Actions / frontend-lint

Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` or a custom image loader to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element
src={message.image.url}
alt="Generated image"
className="max-w-full rounded-md border border-border shadow-xs"
Expand All @@ -187,7 +183,7 @@
)}

{/* Response metrics */}
{message.role === "assistant" &&

Check warning on line 186 in ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/ChatMessageBubble.tsx

View workflow job for this annotation

GitHub Actions / frontend-lint

Boolean expression combines 6 conditions; extract it into a named variable
(message.timeToFirstToken || message.totalLatency || message.usage) &&
!message.a2aMetadata && (
<ResponseMetrics
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@
proxySettings,
simplified = false,
fixedModel,
}) => {

Check warning on line 127 in ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/ChatUI.tsx

View workflow job for this annotation

GitHub Actions / frontend-lint

Arrow function has a complexity of 110. Maximum allowed is 20
const syntaxTheme = useSyntaxTheme(coy);
const canViewPolicies = useCan("viewPolicies");
const [mcpServers, setMCPServers] = useState<MCPServer[]>([]);
Expand Down Expand Up @@ -1784,19 +1784,9 @@
chatHistory.length > 0 &&
chatHistory[chatHistory.length - 1].role === "user" && (
<div className="mb-4 text-left">
<div
className="inline-block max-w-[80%] rounded-lg p-3.5 px-4 shadow-xs"
style={{
backgroundColor: "#ffffff",
border: "1px solid #f0f0f0",
textAlign: "left",
}}
>
<div className="inline-block max-w-[80%] rounded-lg border border-border bg-card p-3.5 px-4 text-left text-card-foreground shadow-xs">
<div className="mb-1.5 flex items-center gap-2">
<div
className="mr-1 flex h-6 w-6 items-center justify-center rounded-full"
style={{ backgroundColor: "#f5f5f5" }}
>
<div className="mr-1 flex h-6 w-6 items-center justify-center rounded-full bg-muted">
<Bot className="size-3 text-muted-foreground" aria-hidden="true" />
</div>
<strong className="text-sm capitalize">Assistant</strong>
Expand Down
Loading