From 28679bb9c366a900fb801f6d971116d4665dc3f7 Mon Sep 17 00:00:00 2001 From: moe-berri Date: Sat, 31 Oct 2026 16:39:33 -0700 Subject: [PATCH] fix(chat): describe general chat and deep research on the chat home (#49531) Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../chat/page.background.integration.test.tsx | 41 +++++++++++++++++++ .../src/app/chat/page.integration.test.tsx | 2 +- ui/litellm-dashboard/src/app/chat/page.tsx | 6 ++- .../chat/page.url-state.integration.test.tsx | 6 +-- .../src/components/chat/design.md | 2 +- .../chat/moyai/MoyaiChatComposer.test.tsx | 2 +- .../chat/moyai/MoyaiChatHome.test.tsx | 8 +++- .../components/chat/moyai/MoyaiChatHome.tsx | 14 +++++-- 8 files changed, 68 insertions(+), 13 deletions(-) diff --git a/ui/litellm-dashboard/src/app/chat/page.background.integration.test.tsx b/ui/litellm-dashboard/src/app/chat/page.background.integration.test.tsx index e81d62d1f64..33de17cba9e 100644 --- a/ui/litellm-dashboard/src/app/chat/page.background.integration.test.tsx +++ b/ui/litellm-dashboard/src/app/chat/page.background.integration.test.tsx @@ -134,6 +134,47 @@ beforeEach(() => { }); afterEach(() => vi.unstubAllGlobals()); +it("should switch the composer placeholder with deep research on home and in a conversation", async () => { + const user = userEvent.setup(); + const home = renderChat(); + await screen.findByRole("button", { name: "research-chat" }); + const homeEditor = screen.getByRole("textbox", { name: "Message" }); + expect(homeEditor).toHaveAttribute("placeholder", "Ask a question, attach a file, or paste something to work on…"); + + const enableResearch = async () => { + await user.click(screen.getByRole("button", { name: "Connect tools" })); + await user.click(await screen.findByRole("button", { name: "Deep research", exact: true })); + }; + await enableResearch(); + expect(homeEditor).toHaveAttribute("placeholder", "What should I research on the web?"); + await user.click(screen.getByRole("button", { name: "Turn off deep research" })); + expect(homeEditor).toHaveAttribute("placeholder", "Ask a question, attach a file, or paste something to work on…"); + + home.unmount(); + const conversationId = "saved-chat"; + const history: Conversation[] = [ + { + id: conversationId, + title: "Saved chat", + model: "research-chat", + messages: [{ id: "saved-message", role: "user", content: "Previous question", timestamp: 1 }], + mcpServerNames: [], + createdAt: 1, + updatedAt: 1, + }, + ]; + localStorage.setItem(storageKey, JSON.stringify(history)); + renderChat(conversationId); + await screen.findByRole("button", { name: "research-chat" }); + const conversationEditor = screen.getByRole("textbox", { name: "Message" }); + expect(conversationEditor).toHaveAttribute("placeholder", "Send a message..."); + + await enableResearch(); + expect(conversationEditor).toHaveAttribute("placeholder", "What should I research on the web?"); + await user.click(screen.getByRole("button", { name: "Turn off deep research" })); + expect(conversationEditor).toHaveAttribute("placeholder", "Send a message..."); +}); + async function startResearch(withTools = true) { const user = userEvent.setup(); await screen.findByRole("button", { name: "research-chat" }); diff --git a/ui/litellm-dashboard/src/app/chat/page.integration.test.tsx b/ui/litellm-dashboard/src/app/chat/page.integration.test.tsx index fce05e5cef9..0cdc7a56bea 100644 --- a/ui/litellm-dashboard/src/app/chat/page.integration.test.tsx +++ b/ui/litellm-dashboard/src/app/chat/page.integration.test.tsx @@ -72,7 +72,7 @@ const ON_TOTAL_LATENCY_INDEX = 24; async function sendOneMessage(onUrlUpdate?: OnUrlUpdateFunction): Promise { renderWithProviders(, { onUrlUpdate }); expect(await screen.findByRole("button", { name: /gpt-5\.4-mini/ })).toBeInTheDocument(); - fireEvent.change(screen.getByPlaceholderText("Describe a change, paste an error, or ask a question…"), { + fireEvent.change(screen.getByPlaceholderText("Ask a question, attach a file, or paste something to work on…"), { target: { value: "How much did this cost?" }, }); fireEvent.click(screen.getByRole("button", { name: "Send" })); diff --git a/ui/litellm-dashboard/src/app/chat/page.tsx b/ui/litellm-dashboard/src/app/chat/page.tsx index f2623d1c5aa..b08968cbb8f 100644 --- a/ui/litellm-dashboard/src/app/chat/page.tsx +++ b/ui/litellm-dashboard/src/app/chat/page.tsx @@ -505,9 +505,10 @@ export default function ChatConversationPage() { const inputBar = (inConversation: boolean) => { const hint = mode === "chat" || background.pending ? backgroundHint() : null; - const chatPlaceholder = inConversation + const defaultPlaceholder = inConversation ? "Send a message..." - : "Describe a change, paste an error, or ask a question…"; + : "Ask a question, attach a file, or paste something to work on…"; + const chatPlaceholder = research ? "What should I research on the web?" : defaultPlaceholder; const preparing = isLoadingModels || isReadingAttachments; const researchBlocked = research && !canResearch; const submitDisabled = @@ -718,6 +719,7 @@ export default function ChatConversationPage() { {showBlankState ? ( { expect(await screen.findByRole("button", { name: /gpt-5\.4-mini/ })).toBeInTheDocument(); act(() => { - fireEvent.change(screen.getByPlaceholderText("Describe a change, paste an error, or ask a question…"), { + fireEvent.change(screen.getByPlaceholderText("Ask a question, attach a file, or paste something to work on…"), { target: { value: "How much did this cost?" }, }); }); @@ -87,9 +87,9 @@ describe("chat page URL state with ChatShellProvider", () => { await waitFor(() => expect(window.location.search).toBe("")); expect( - await screen.findByPlaceholderText("Describe a change, paste an error, or ask a question…"), + await screen.findByPlaceholderText("Ask a question, attach a file, or paste something to work on…"), ).toBeInTheDocument(); - expect(screen.getByRole("heading", { level: 1, name: "What are we building?" })).toBeInTheDocument(); + expect(screen.getByRole("heading", { level: 1, name: "What are we working on?" })).toBeInTheDocument(); expect(screen.queryByText("The estimated cost is one cent.")).not.toBeInTheDocument(); expect(screen.getByRole("button", { name: "How much did this cost?" })).toBeInTheDocument(); expect(window.location.pathname).toBe("/chat"); diff --git a/ui/litellm-dashboard/src/components/chat/design.md b/ui/litellm-dashboard/src/components/chat/design.md index b89b223da21..97e0c2ebeea 100644 --- a/ui/litellm-dashboard/src/components/chat/design.md +++ b/ui/litellm-dashboard/src/components/chat/design.md @@ -80,7 +80,7 @@ Show available providers in a single-select dropdown beside model search. “All ```tsx // Page/greeting heading
-

What are we building?

+

What are we working on?

// Moyai: 500 weight, clamp(32px, 3.4vw, 46px), 1.13 line-height // Section heading (panel titles: "Your API Keys", "Your Usage") diff --git a/ui/litellm-dashboard/src/components/chat/moyai/MoyaiChatComposer.test.tsx b/ui/litellm-dashboard/src/components/chat/moyai/MoyaiChatComposer.test.tsx index eefeb2bc025..8613ca37a19 100644 --- a/ui/litellm-dashboard/src/components/chat/moyai/MoyaiChatComposer.test.tsx +++ b/ui/litellm-dashboard/src/components/chat/moyai/MoyaiChatComposer.test.tsx @@ -9,7 +9,7 @@ function composerProps(overrides: Partial> = {} return { children: Chat composer, imageMode: false, + researchMode: false, draft: "", busy: false, conversations: [], @@ -24,12 +25,17 @@ function conversation(id: string, updatedAt: number): Conversation { describe("MoyaiChatHome", () => { it("should render the Moyai welcome and composer", () => { render(); - expect(screen.getByRole("heading", { level: 1, name: "What are we building?" })).toBeInTheDocument(); + expect(screen.getByRole("heading", { level: 1, name: "What are we working on?" })).toBeInTheDocument(); expect(screen.getByText("Chat composer")).toBeInTheDocument(); expect(screen.getByRole("heading", { name: "Recent chats" })).toBeInTheDocument(); expect(screen.getByRole("status")).toHaveTextContent("No recent chats in this browser yet."); }); + it("should render the research welcome when research mode is enabled", () => { + render(); + expect(screen.getByRole("heading", { level: 1, name: "What should we research?" })).toBeInTheDocument(); + }); + it("should show the three most recently updated chats and open the selected one", () => { const conversations = [ conversation("first", 1), diff --git a/ui/litellm-dashboard/src/components/chat/moyai/MoyaiChatHome.tsx b/ui/litellm-dashboard/src/components/chat/moyai/MoyaiChatHome.tsx index e80a3bd92d1..958cb49a72d 100644 --- a/ui/litellm-dashboard/src/components/chat/moyai/MoyaiChatHome.tsx +++ b/ui/litellm-dashboard/src/components/chat/moyai/MoyaiChatHome.tsx @@ -23,6 +23,7 @@ const starters = [ export default function MoyaiChatHome({ children, imageMode, + researchMode, draft, busy, conversations, @@ -31,6 +32,7 @@ export default function MoyaiChatHome({ }: { children: ReactNode; imageMode: boolean; + researchMode: boolean; draft: string; busy: boolean; conversations: Conversation[]; @@ -44,11 +46,15 @@ export default function MoyaiChatHome({

- {imageMode ? ( - "What are we creating?" - ) : ( + {imageMode && "What are we creating?"} + {!imageMode && researchMode && ( <> - What are we building? + What should we research? + + )} + {!imageMode && !researchMode && ( + <> + What are we working on? )}