mirror of
https://github.com/OpenHands/OpenHands.git
synced 2026-03-22 13:47:19 +08:00
refactor(frontend): remove feature flag (planning agent) (#12880)
This commit is contained in:
@@ -5,11 +5,6 @@ import { ChangeAgentButton } from "#/components/features/chat/change-agent-butto
|
||||
import { renderWithProviders } from "../../../../test-utils";
|
||||
import { useConversationStore } from "#/stores/conversation-store";
|
||||
|
||||
// Mock feature flag to enable planning agent
|
||||
vi.mock("#/utils/feature-flags", () => ({
|
||||
USE_PLANNING_AGENT: () => true,
|
||||
}));
|
||||
|
||||
// Mock WebSocket status
|
||||
vi.mock("#/hooks/use-unified-websocket-status", () => ({
|
||||
useUnifiedWebSocketStatus: () => "CONNECTED",
|
||||
|
||||
@@ -27,11 +27,6 @@ function renderPlanPreview(ui: React.ReactElement) {
|
||||
);
|
||||
}
|
||||
|
||||
// Mock the feature flag to always return true (not testing feature flag behavior)
|
||||
vi.mock("#/utils/feature-flags", () => ({
|
||||
USE_PLANNING_AGENT: vi.fn(() => true),
|
||||
}));
|
||||
|
||||
// Mock i18n - need to preserve initReactI18next and I18nextProvider for test-utils
|
||||
vi.mock("react-i18next", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("react-i18next")>();
|
||||
|
||||
@@ -10,10 +10,6 @@ import { useConversationStore } from "#/stores/conversation-store";
|
||||
const TASK_CONVERSATION_ID = "task-ec03fb2ab8604517b24af632b058c2fd";
|
||||
const REAL_CONVERSATION_ID = "conv-abc123";
|
||||
|
||||
vi.mock("#/utils/feature-flags", () => ({
|
||||
USE_PLANNING_AGENT: () => false,
|
||||
}));
|
||||
|
||||
let mockConversationId = TASK_CONVERSATION_ID;
|
||||
|
||||
vi.mock("#/hooks/use-conversation-id", () => ({
|
||||
@@ -120,9 +116,7 @@ describe("ConversationTabs localStorage behavior", () => {
|
||||
|
||||
// Verify localStorage was updated
|
||||
const storedState = JSON.parse(
|
||||
localStorage.getItem(
|
||||
`conversation-state-${REAL_CONVERSATION_ID}`,
|
||||
)!,
|
||||
localStorage.getItem(`conversation-state-${REAL_CONVERSATION_ID}`)!,
|
||||
);
|
||||
expect(storedState.selectedTab).toBe("terminal");
|
||||
expect(storedState.rightPanelShown).toBe(true);
|
||||
@@ -152,9 +146,7 @@ describe("ConversationTabs localStorage behavior", () => {
|
||||
|
||||
// Verify localStorage was updated
|
||||
const storedState = JSON.parse(
|
||||
localStorage.getItem(
|
||||
`conversation-state-${REAL_CONVERSATION_ID}`,
|
||||
)!,
|
||||
localStorage.getItem(`conversation-state-${REAL_CONVERSATION_ID}`)!,
|
||||
);
|
||||
expect(storedState.rightPanelShown).toBe(false);
|
||||
});
|
||||
@@ -184,9 +176,7 @@ describe("ConversationTabs localStorage behavior", () => {
|
||||
|
||||
// Verify localStorage was updated
|
||||
const storedState = JSON.parse(
|
||||
localStorage.getItem(
|
||||
`conversation-state-${REAL_CONVERSATION_ID}`,
|
||||
)!,
|
||||
localStorage.getItem(`conversation-state-${REAL_CONVERSATION_ID}`)!,
|
||||
);
|
||||
expect(storedState.selectedTab).toBe("browser");
|
||||
});
|
||||
|
||||
@@ -9,11 +9,6 @@ import {
|
||||
createPlanningObservationEvent,
|
||||
} from "test-utils";
|
||||
|
||||
// Mock the feature flag
|
||||
vi.mock("#/utils/feature-flags", () => ({
|
||||
USE_PLANNING_AGENT: vi.fn(() => true),
|
||||
}));
|
||||
|
||||
// Mock useConfig
|
||||
vi.mock("#/hooks/query/use-config", () => ({
|
||||
useConfig: () => ({
|
||||
|
||||
@@ -9,7 +9,6 @@ import LessonPlanIcon from "#/icons/lesson-plan.svg?react";
|
||||
import { useConversationStore } from "#/stores/conversation-store";
|
||||
import { ChangeAgentContextMenu } from "./change-agent-context-menu";
|
||||
import { cn } from "#/utils/utils";
|
||||
import { USE_PLANNING_AGENT } from "#/utils/feature-flags";
|
||||
import { useAgentState } from "#/hooks/use-agent-state";
|
||||
import { AgentState } from "#/types/agent-state";
|
||||
import { useActiveConversation } from "#/hooks/query/use-active-conversation";
|
||||
@@ -27,8 +26,6 @@ export function ChangeAgentButton() {
|
||||
|
||||
const isWebSocketConnected = webSocketStatus === "CONNECTED";
|
||||
|
||||
const shouldUsePlanningAgent = USE_PLANNING_AGENT();
|
||||
|
||||
const { curAgentState } = useAgentState();
|
||||
|
||||
const { t } = useTranslation();
|
||||
@@ -83,10 +80,7 @@ export function ChangeAgentButton() {
|
||||
}, [isAgentRunning, contextMenuOpen, isWebSocketConnected]);
|
||||
|
||||
const isButtonDisabled =
|
||||
isAgentRunning ||
|
||||
isCreatingConversation ||
|
||||
!isWebSocketConnected ||
|
||||
!shouldUsePlanningAgent;
|
||||
isAgentRunning || isCreatingConversation || !isWebSocketConnected;
|
||||
|
||||
// Handle Shift + Tab keyboard shortcut to cycle through modes
|
||||
useEffect(() => {
|
||||
@@ -151,10 +145,6 @@ export function ChangeAgentButton() {
|
||||
return <LessonPlanIcon width={18} height={18} color="#ffffff" />;
|
||||
}, [isExecutionAgent]);
|
||||
|
||||
if (!shouldUsePlanningAgent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<button
|
||||
|
||||
@@ -19,7 +19,6 @@ import { useInitialQueryStore } from "#/stores/initial-query-store";
|
||||
import { useSendMessage } from "#/hooks/use-send-message";
|
||||
import { useAgentState } from "#/hooks/use-agent-state";
|
||||
import { useHandleBuildPlanClick } from "#/hooks/use-handle-build-plan-click";
|
||||
import { USE_PLANNING_AGENT } from "#/utils/feature-flags";
|
||||
|
||||
import { ScrollToBottomButton } from "#/components/shared/buttons/scroll-to-bottom-button";
|
||||
import { LoadingSpinner } from "#/components/shared/loading-spinner";
|
||||
@@ -84,7 +83,6 @@ export function ChatInterface() {
|
||||
|
||||
const { curAgentState } = useAgentState();
|
||||
const { handleBuildPlanClick } = useHandleBuildPlanClick();
|
||||
const shouldUsePlanningAgent = USE_PLANNING_AGENT();
|
||||
|
||||
// Disable Build button while agent is running (streaming)
|
||||
const isAgentRunning =
|
||||
@@ -95,7 +93,7 @@ export function ChatInterface() {
|
||||
// This is placed here instead of PlanPreview to avoid duplicate listeners
|
||||
// when multiple PlanPreview components exist in the chat
|
||||
React.useEffect(() => {
|
||||
if (!shouldUsePlanningAgent || isAgentRunning) {
|
||||
if (isAgentRunning) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -114,12 +112,7 @@ export function ChatInterface() {
|
||||
return () => {
|
||||
document.removeEventListener("keydown", handleKeyDown);
|
||||
};
|
||||
}, [
|
||||
shouldUsePlanningAgent,
|
||||
isAgentRunning,
|
||||
handleBuildPlanClick,
|
||||
scrollDomToBottom,
|
||||
]);
|
||||
}, [isAgentRunning, handleBuildPlanClick, scrollDomToBottom]);
|
||||
|
||||
const [feedbackPolarity, setFeedbackPolarity] = React.useState<
|
||||
"positive" | "negative"
|
||||
|
||||
@@ -2,7 +2,6 @@ import { useMemo, useCallback } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { ArrowUpRight } from "lucide-react";
|
||||
import LessonPlanIcon from "#/icons/lesson-plan.svg?react";
|
||||
import { USE_PLANNING_AGENT } from "#/utils/feature-flags";
|
||||
import { Typography } from "#/ui/typography";
|
||||
import { I18nKey } from "#/i18n/declaration";
|
||||
import { MarkdownRenderer } from "#/components/features/markdown/markdown-renderer";
|
||||
@@ -43,8 +42,6 @@ export function PlanPreview({
|
||||
const { handleBuildPlanClick } = useHandleBuildPlanClick();
|
||||
const { scrollDomToBottom } = useScrollContext();
|
||||
|
||||
const shouldUsePlanningAgent = USE_PLANNING_AGENT();
|
||||
|
||||
const handleViewClick = () => {
|
||||
navigateToTab("planner");
|
||||
};
|
||||
@@ -65,7 +62,7 @@ export function PlanPreview({
|
||||
return `${planContent.slice(0, MAX_CONTENT_LENGTH)}...`;
|
||||
}, [planContent]);
|
||||
|
||||
if (!shouldUsePlanningAgent || !planContent) {
|
||||
if (!planContent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ import GitChanges from "#/icons/git_changes.svg?react";
|
||||
import VSCodeIcon from "#/icons/vscode.svg?react";
|
||||
import PillIcon from "#/icons/pill.svg?react";
|
||||
import PillFillIcon from "#/icons/pill-fill.svg?react";
|
||||
import { USE_PLANNING_AGENT } from "#/utils/feature-flags";
|
||||
import LessonPlanIcon from "#/icons/lesson-plan.svg?react";
|
||||
|
||||
interface ConversationTabsContextMenuProps {
|
||||
@@ -30,9 +29,12 @@ export function ConversationTabsContextMenu({
|
||||
const { state, setUnpinnedTabs } =
|
||||
useConversationLocalStorageState(conversationId);
|
||||
|
||||
const shouldUsePlanningAgent = USE_PLANNING_AGENT();
|
||||
|
||||
const tabConfig = [
|
||||
{
|
||||
tab: "planner",
|
||||
icon: LessonPlanIcon,
|
||||
i18nKey: I18nKey.COMMON$PLANNER,
|
||||
},
|
||||
{ tab: "editor", icon: GitChanges, i18nKey: I18nKey.COMMON$CHANGES },
|
||||
{ tab: "vscode", icon: VSCodeIcon, i18nKey: I18nKey.COMMON$CODE },
|
||||
{ tab: "terminal", icon: TerminalIcon, i18nKey: I18nKey.COMMON$TERMINAL },
|
||||
@@ -40,14 +42,6 @@ export function ConversationTabsContextMenu({
|
||||
{ tab: "browser", icon: GlobeIcon, i18nKey: I18nKey.COMMON$BROWSER },
|
||||
];
|
||||
|
||||
if (shouldUsePlanningAgent) {
|
||||
tabConfig.unshift({
|
||||
tab: "planner",
|
||||
icon: LessonPlanIcon,
|
||||
i18nKey: I18nKey.COMMON$PLANNER,
|
||||
});
|
||||
}
|
||||
|
||||
if (!isOpen) return null;
|
||||
|
||||
const handleTabClick = (tab: string) => {
|
||||
|
||||
@@ -15,7 +15,6 @@ import { I18nKey } from "#/i18n/declaration";
|
||||
import { VSCodeTooltipContent } from "./vscode-tooltip-content";
|
||||
import { useConversationStore } from "#/stores/conversation-store";
|
||||
import { ConversationTabsContextMenu } from "./conversation-tabs-context-menu";
|
||||
import { USE_PLANNING_AGENT } from "#/utils/feature-flags";
|
||||
import { useConversationId } from "#/hooks/use-conversation-id";
|
||||
import { useSelectConversationTab } from "#/hooks/use-select-conversation-tab";
|
||||
|
||||
@@ -28,8 +27,6 @@ export function ConversationTabs() {
|
||||
const { state: persistedState } =
|
||||
useConversationLocalStorageState(conversationId);
|
||||
|
||||
const shouldUsePlanningAgent = USE_PLANNING_AGENT();
|
||||
|
||||
const {
|
||||
selectTab,
|
||||
isTabActive,
|
||||
@@ -66,6 +63,15 @@ export function ConversationTabs() {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const tabs = [
|
||||
{
|
||||
tabValue: "planner",
|
||||
isActive: isTabActive("planner"),
|
||||
icon: LessonPlanIcon,
|
||||
onClick: () => selectTab("planner"),
|
||||
tooltipContent: t(I18nKey.COMMON$PLANNER),
|
||||
tooltipAriaLabel: t(I18nKey.COMMON$PLANNER),
|
||||
label: t(I18nKey.COMMON$PLANNER),
|
||||
},
|
||||
{
|
||||
tabValue: "editor",
|
||||
isActive: isTabActive("editor"),
|
||||
@@ -114,18 +120,6 @@ export function ConversationTabs() {
|
||||
},
|
||||
];
|
||||
|
||||
if (shouldUsePlanningAgent) {
|
||||
tabs.unshift({
|
||||
tabValue: "planner",
|
||||
isActive: isTabActive("planner"),
|
||||
icon: LessonPlanIcon,
|
||||
onClick: () => selectTab("planner"),
|
||||
tooltipContent: t(I18nKey.COMMON$PLANNER),
|
||||
tooltipAriaLabel: t(I18nKey.COMMON$PLANNER),
|
||||
label: t(I18nKey.COMMON$PLANNER),
|
||||
});
|
||||
}
|
||||
|
||||
// Filter out unpinned tabs
|
||||
const visibleTabs = tabs.filter(
|
||||
(tab) => !persistedState.unpinnedTabs.includes(tab.tabValue),
|
||||
|
||||
@@ -17,4 +17,3 @@ export const HIDE_LLM_SETTINGS = () => loadFeatureFlag("HIDE_LLM_SETTINGS");
|
||||
export const VSCODE_IN_NEW_TAB = () => loadFeatureFlag("VSCODE_IN_NEW_TAB");
|
||||
export const ENABLE_TRAJECTORY_REPLAY = () =>
|
||||
loadFeatureFlag("TRAJECTORY_REPLAY");
|
||||
export const USE_PLANNING_AGENT = () => loadFeatureFlag("USE_PLANNING_AGENT");
|
||||
|
||||
Reference in New Issue
Block a user