fix(webui): sync model badge after preset switch

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Xubin Ren
2026-05-12 20:06:22 +08:00
committed by Xubin Ren
co-authored by Cursor
parent b61c6304c3
commit c92345bbb1
9 changed files with 61 additions and 4 deletions
+1
View File
@@ -492,6 +492,7 @@ function Shell({ onModelNameChange, onLogout }: { onModelNameChange: (modelName:
onNewChat={onNewChat}
onCreateChat={onCreateChat}
onTurnEnd={onTurnEnd}
onModelNameChange={onModelNameChange}
theme={theme}
onToggleTheme={toggle}
hideSidebarToggleOnDesktop={desktopSidebarOpen}
+3 -1
View File
@@ -32,6 +32,7 @@ interface ThreadShellProps {
onNewChat?: () => void;
onCreateChat?: () => Promise<string | null>;
onTurnEnd?: () => void;
onModelNameChange?: (modelName: string | null) => void;
theme?: "light" | "dark";
onToggleTheme?: () => void;
hideSidebarToggleOnDesktop?: boolean;
@@ -75,6 +76,7 @@ export function ThreadShell({
onToggleSidebar,
onCreateChat,
onTurnEnd,
onModelNameChange,
theme = "light",
onToggleTheme = () => {},
hideSidebarToggleOnDesktop = false,
@@ -103,7 +105,7 @@ export function ThreadShell({
setMessages,
streamError,
dismissStreamError,
} = useNanobotStream(chatId, initial, hasPendingToolCalls, onTurnEnd);
} = useNanobotStream(chatId, initial, hasPendingToolCalls, onTurnEnd, onModelNameChange);
const showHeroComposer = messages.length === 0 && !loading;
const pendingAsk = useMemo(() => {
for (let index = messages.length - 1; index >= 0; index -= 1) {
+4
View File
@@ -44,6 +44,7 @@ export function useNanobotStream(
initialMessages: UIMessage[] = [],
hasPendingToolCalls = false,
onTurnEnd?: () => void,
onModelNameChange?: (modelName: string | null) => void,
): {
messages: UIMessage[];
isStreaming: boolean;
@@ -181,6 +182,9 @@ export function useNanobotStream(
}
if (ev.event === "message") {
if (ev.model_name !== undefined) {
onModelNameChange?.(ev.model_name || null);
}
if (
suppressStreamUntilTurnEndRef.current &&
(ev.kind === "tool_hint" || ev.kind === "progress")
+2
View File
@@ -147,6 +147,8 @@ export type InboundEvent =
/** Present when the frame is an agent breadcrumb (e.g. tool hint,
* generic progress line) rather than a conversational reply. */
kind?: "tool_hint" | "progress";
/** Runtime model name after commands like `/model fast` update it. */
model_name?: string | null;
}
| {
event: "delta";
+22
View File
@@ -134,6 +134,28 @@ describe("useNanobotStream", () => {
]);
});
it("reports runtime model name updates from message frames", () => {
const fake = fakeClient();
const onModelNameChange = vi.fn();
renderHook(
() => useNanobotStream("chat-model", EMPTY_MESSAGES, false, undefined, onModelNameChange),
{
wrapper: wrap(fake.client),
},
);
act(() => {
fake.emit("chat-model", {
event: "message",
chat_id: "chat-model",
text: "Switched model preset to `fast`.",
model_name: "openai/gpt-4.1",
});
});
expect(onModelNameChange).toHaveBeenCalledWith("openai/gpt-4.1");
});
it("suppresses redundant stream confirmation after assistant media", () => {
const fake = fakeClient();
const { result } = renderHook(() => useNanobotStream("chat-img-result", EMPTY_MESSAGES), {