From a967f9da8648848a6754ec7fc05719df7bdafa6c Mon Sep 17 00:00:00 2001 From: nehaprasad-dev Date: Thu, 21 May 2026 08:30:25 +0530 Subject: [PATCH] fix: enable agent mode switch on new conversation page without websocket --- .../features/chat/change-agent-button.test.tsx | 14 ++++++++++++-- .../chat/components/chat-input-model.test.tsx | 2 +- .../features/chat/change-agent-button.tsx | 18 +++++++++++++++--- .../chat/components/chat-input-actions.tsx | 4 ++-- .../chat/components/chat-input-model.tsx | 2 +- 5 files changed, 31 insertions(+), 9 deletions(-) diff --git a/__tests__/components/features/chat/change-agent-button.test.tsx b/__tests__/components/features/chat/change-agent-button.test.tsx index b7d44d152..766561a58 100644 --- a/__tests__/components/features/chat/change-agent-button.test.tsx +++ b/__tests__/components/features/chat/change-agent-button.test.tsx @@ -5,9 +5,10 @@ import { ChangeAgentButton } from "#/components/features/chat/change-agent-butto import { renderWithProviders } from "../../../../test-utils"; import { useConversationStore } from "#/stores/conversation-store"; -// Mock WebSocket status +const mockWebSocketStatus = vi.hoisted(() => vi.fn(() => "OPEN")); + vi.mock("#/hooks/use-unified-websocket-status", () => ({ - useUnifiedWebSocketStatus: () => "CONNECTED", + useUnifiedWebSocketStatus: () => mockWebSocketStatus(), })); // Mock agent state @@ -68,6 +69,7 @@ vi.mock("#/hooks/use-handle-plan-click", () => ({ describe("ChangeAgentButton - Cache Invalidation", () => { beforeEach(() => { vi.clearAllMocks(); + mockWebSocketStatus.mockReturnValue("OPEN"); // Reset store state useConversationStore.setState({ conversationMode: "code", @@ -151,4 +153,12 @@ describe("ChangeAgentButton - Cache Invalidation", () => { const button = screen.getByRole("button"); expect(button).toBeInTheDocument(); }); + + it("enables mode switch on pre-conversation surfaces without a websocket", () => { + mockWebSocketStatus.mockReturnValue("CLOSED"); + renderWithProviders(, { + navigation: { conversationId: null }, + }); + expect(screen.getByRole("button")).not.toBeDisabled(); + }); }); diff --git a/__tests__/components/features/chat/components/chat-input-model.test.tsx b/__tests__/components/features/chat/components/chat-input-model.test.tsx index 870e326eb..8a990ad13 100644 --- a/__tests__/components/features/chat/components/chat-input-model.test.tsx +++ b/__tests__/components/features/chat/components/chat-input-model.test.tsx @@ -47,7 +47,7 @@ describe("ChatInputModel", () => { const llmSettingsLink = screen.getByRole("link", { name: /LLM Profiles|SETTINGS\$LLM_PROFILES|LLM Settings|SETTINGS\$LLM_SETTINGS/, }); - expect(llmSettingsLink).toHaveAttribute("href", "/settings"); + expect(llmSettingsLink).toHaveAttribute("href", "/settings/llm"); }); it("renders nothing when llm_model is missing", () => { diff --git a/src/components/features/chat/change-agent-button.tsx b/src/components/features/chat/change-agent-button.tsx index c9827b923..fb47b900b 100644 --- a/src/components/features/chat/change-agent-button.tsx +++ b/src/components/features/chat/change-agent-button.tsx @@ -15,6 +15,7 @@ import { useActiveConversation } from "#/hooks/query/use-active-conversation"; import { useUnifiedWebSocketStatus } from "#/hooks/use-unified-websocket-status"; import { useSubConversationTaskPolling } from "#/hooks/query/use-sub-conversation-task-polling"; import { useHandlePlanClick } from "#/hooks/use-handle-plan-click"; +import { useOptionalConversationId } from "#/hooks/use-conversation-id"; export function ChangeAgentButton() { const [contextMenuOpen, setContextMenuOpen] = useState(false); @@ -22,6 +23,9 @@ export function ChangeAgentButton() { const { conversationMode, setConversationMode, subConversationTaskId } = useConversationStore(); + const { conversationId } = useOptionalConversationId(); + const isPreConversation = conversationId == null; + const webSocketStatus = useUnifiedWebSocketStatus(); const isWebSocketConnected = webSocketStatus === "OPEN"; @@ -74,13 +78,21 @@ export function ChangeAgentButton() { // Close context menu when agent starts running useEffect(() => { - if ((isAgentRunning || !isWebSocketConnected) && contextMenuOpen) { + const blockedBySocket = !isPreConversation && !isWebSocketConnected; + if ((isAgentRunning || blockedBySocket) && contextMenuOpen) { setContextMenuOpen(false); } - }, [isAgentRunning, contextMenuOpen, isWebSocketConnected]); + }, [ + isAgentRunning, + contextMenuOpen, + isWebSocketConnected, + isPreConversation, + ]); const isButtonDisabled = - isAgentRunning || isCreatingConversation || !isWebSocketConnected; + isCreatingConversation || + isAgentRunning || + (!isPreConversation && !isWebSocketConnected); // Handle Shift + Tab keyboard shortcut to cycle through modes useEffect(() => { diff --git a/src/components/features/chat/components/chat-input-actions.tsx b/src/components/features/chat/components/chat-input-actions.tsx index 544cb81b6..820b761aa 100644 --- a/src/components/features/chat/components/chat-input-actions.tsx +++ b/src/components/features/chat/components/chat-input-actions.tsx @@ -260,7 +260,7 @@ export function ChatInputActions({ const isAgentSwitcherDisabled = curAgentState === AgentState.RUNNING || isCreatingConversation || - webSocketStatus !== "OPEN"; + (conversationId != null && webSocketStatus !== "OPEN"); const closeOverflowMenus = () => { setActiveSubmenu(null); @@ -449,7 +449,7 @@ export function ChatInputActions({
  • diff --git a/src/components/features/chat/components/chat-input-model.tsx b/src/components/features/chat/components/chat-input-model.tsx index 04b5af5d9..ae40c4c8c 100644 --- a/src/components/features/chat/components/chat-input-model.tsx +++ b/src/components/features/chat/components/chat-input-model.tsx @@ -105,7 +105,7 @@ export function ChatInputModel() {
  • setIsPopoverOpen(false)} className="flex h-[30px] items-center gap-2 rounded p-2 leading-5 text-white hover:bg-[var(--oh-interactive-hover)] transition-colors" >