diff --git a/frontend/src/components/shared/modals/settings/settings-form.tsx b/frontend/src/components/shared/modals/settings/settings-form.tsx index e2637bc594d30..3a7d9390aaaa6 100644 --- a/frontend/src/components/shared/modals/settings/settings-form.tsx +++ b/frontend/src/components/shared/modals/settings/settings-form.tsx @@ -23,6 +23,7 @@ import { ModelSelector } from "./model-selector"; import { RuntimeSizeSelector } from "./runtime-size-selector"; import { useConfig } from "#/hooks/query/use-config"; import { useCurrentSettings } from "#/context/settings-context"; +import { MEMORY_CONDENSER } from "#/utils/feature-flags"; interface SettingsFormProps { disabled?: boolean; @@ -64,12 +65,14 @@ export function SettingsForm({ const isUsingConfirmationMode = !!settings.CONFIRMATION_MODE; const isUsingBaseUrl = !!settings.LLM_BASE_URL; const isUsingCustomModel = !!settings.LLM_MODEL && !isKnownModel; + const isUsingDefaultCondenser = !!settings.ENABLE_DEFAULT_CONDENSER; return ( isUsingSecurityAnalyzer || isUsingConfirmationMode || isUsingBaseUrl || - isUsingCustomModel + isUsingCustomModel || + isUsingDefaultCondenser ); } @@ -94,6 +97,9 @@ export function SettingsForm({ const isUsingAdvancedOptions = keys.includes("use-advanced-options"); const newSettings = extractSettings(formData); + // Inject the condenser config from the current feature flag value + newSettings.ENABLE_DEFAULT_CONDENSER = MEMORY_CONDENSER; + saveSettingsView(isUsingAdvancedOptions ? "advanced" : "basic"); await saveUserSettings(newSettings); onClose(); diff --git a/frontend/src/hooks/mutation/use-save-settings.ts b/frontend/src/hooks/mutation/use-save-settings.ts index ef334b0f1db85..50865f6d6414b 100644 --- a/frontend/src/hooks/mutation/use-save-settings.ts +++ b/frontend/src/hooks/mutation/use-save-settings.ts @@ -11,6 +11,7 @@ const saveSettingsMutationFn = async (settings: Partial) => { confirmation_mode: settings.CONFIRMATION_MODE, security_analyzer: settings.SECURITY_ANALYZER, llm_api_key: settings.LLM_API_KEY?.trim() || undefined, + enable_default_condenser: settings.ENABLE_DEFAULT_CONDENSER, }; await OpenHands.saveSettings(apiSettings); diff --git a/frontend/src/hooks/query/use-settings.ts b/frontend/src/hooks/query/use-settings.ts index 3daa8c8780b72..1f56c86b9d9af 100644 --- a/frontend/src/hooks/query/use-settings.ts +++ b/frontend/src/hooks/query/use-settings.ts @@ -20,6 +20,7 @@ const getSettingsQueryFn = async () => { LLM_API_KEY: apiSettings.llm_api_key, REMOTE_RUNTIME_RESOURCE_FACTOR: apiSettings.remote_runtime_resource_factor, + ENABLE_DEFAULT_CONDENSER: apiSettings.enable_default_condenser, }; } diff --git a/frontend/src/i18n/translation.json b/frontend/src/i18n/translation.json index f0d0a87062d8a..615e6f0ef1fc0 100644 --- a/frontend/src/i18n/translation.json +++ b/frontend/src/i18n/translation.json @@ -4506,5 +4506,8 @@ "fr": "Que voulez-vous construire ?", "tr": "Ne inşa etmek istiyorsun?", "de": "Was möchten Sie erstellen?" + }, + "SETTINGS_FORM$ENABLE_DEFAULT_CONDENSER_SWITCH_LABEL": { + "en": "Enable Memory Condenser" } } diff --git a/frontend/src/services/settings.ts b/frontend/src/services/settings.ts index bf2cfa8e97542..1a4cd286f8758 100644 --- a/frontend/src/services/settings.ts +++ b/frontend/src/services/settings.ts @@ -9,6 +9,7 @@ export type Settings = { CONFIRMATION_MODE: boolean; SECURITY_ANALYZER: string; REMOTE_RUNTIME_RESOURCE_FACTOR: number; + ENABLE_DEFAULT_CONDENSER: boolean; }; export type ApiSettings = { @@ -20,6 +21,7 @@ export type ApiSettings = { confirmation_mode: boolean; security_analyzer: string; remote_runtime_resource_factor: number; + enable_default_condenser: boolean; }; export const DEFAULT_SETTINGS: Settings = { @@ -31,6 +33,7 @@ export const DEFAULT_SETTINGS: Settings = { CONFIRMATION_MODE: false, SECURITY_ANALYZER: "", REMOTE_RUNTIME_RESOURCE_FACTOR: 1, + ENABLE_DEFAULT_CONDENSER: false, }; export const getCurrentSettingsVersion = () => { @@ -60,6 +63,8 @@ export const getLocalStorageSettings = (): Settings => { const llmApiKey = localStorage.getItem("LLM_API_KEY"); const confirmationMode = localStorage.getItem("CONFIRMATION_MODE") === "true"; const securityAnalyzer = localStorage.getItem("SECURITY_ANALYZER"); + const enableDefaultCondenser = + localStorage.getItem("ENABLE_DEFAULT_CONDENSER") === "true"; return { LLM_MODEL: llmModel || DEFAULT_SETTINGS.LLM_MODEL, @@ -71,6 +76,8 @@ export const getLocalStorageSettings = (): Settings => { SECURITY_ANALYZER: securityAnalyzer || DEFAULT_SETTINGS.SECURITY_ANALYZER, REMOTE_RUNTIME_RESOURCE_FACTOR: DEFAULT_SETTINGS.REMOTE_RUNTIME_RESOURCE_FACTOR, + ENABLE_DEFAULT_CONDENSER: + enableDefaultCondenser || DEFAULT_SETTINGS.ENABLE_DEFAULT_CONDENSER, }; }; diff --git a/frontend/src/utils/feature-flags.ts b/frontend/src/utils/feature-flags.ts index 8cdf711aadf59..154e88a59924c 100644 --- a/frontend/src/utils/feature-flags.ts +++ b/frontend/src/utils/feature-flags.ts @@ -13,3 +13,4 @@ function loadFeatureFlag( } export const MULTI_CONVERSATION_UI = loadFeatureFlag("MULTI_CONVERSATION_UI"); +export const MEMORY_CONDENSER = loadFeatureFlag("MEMORY_CONDENSER"); diff --git a/openhands/server/session/session.py b/openhands/server/session/session.py index ee960d1fd7cb0..a7a16a4fa6ec7 100644 --- a/openhands/server/session/session.py +++ b/openhands/server/session/session.py @@ -6,6 +6,7 @@ from openhands.controller.agent import Agent from openhands.core.config import AppConfig +from openhands.core.config.condenser_config import AmortizedForgettingCondenserConfig from openhands.core.const.guide_url import TROUBLESHOOTING_URL from openhands.core.logger import openhands_logger as logger from openhands.core.schema import AgentState @@ -105,6 +106,14 @@ async def initialize_agent( llm = LLM(config=self.config.get_llm_config_from_agent(agent_cls)) agent_config = self.config.get_agent_config(agent_cls) + + if settings.enable_default_condenser: + default_condenser_config = AmortizedForgettingCondenserConfig( + keep_first=3, max_size=20 + ) + logger.info(f'Enabling default condenser: {default_condenser_config}') + agent_config.condenser = default_condenser_config + agent = Agent.get_cls(agent_cls)(llm, agent_config) github_token = None diff --git a/openhands/server/settings.py b/openhands/server/settings.py index 19174706e497b..c63e115546148 100644 --- a/openhands/server/settings.py +++ b/openhands/server/settings.py @@ -21,6 +21,7 @@ class Settings(BaseModel): llm_api_key: SecretStr | None = None llm_base_url: str | None = None remote_runtime_resource_factor: int | None = None + enable_default_condenser: bool = False @field_serializer('llm_api_key') def llm_api_key_serializer(self, llm_api_key: SecretStr, info: SerializationInfo):