diff --git a/docs/static/openapi.json b/docs/static/openapi.json index b12ddeb653..3ecf5e25e0 100644 --- a/docs/static/openapi.json +++ b/docs/static/openapi.json @@ -1646,6 +1646,32 @@ } } }, + "/api/reset-settings": { + "post": { + "summary": "Reset settings (Deprecated)", + "description": "This endpoint is deprecated and will return a 410 Gone error. Reset functionality has been removed.", + "operationId": "resetSettings", + "deprecated": true, + "responses": { + "410": { + "description": "Feature removed", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Reset settings functionality has been removed." + } + } + } + } + } + } + } + } + }, "/api/unset-settings-tokens": { "post": { "summary": "Unset settings tokens", @@ -1685,45 +1711,6 @@ } } }, - "/api/reset-settings": { - "post": { - "summary": "Reset settings", - "description": "Reset user settings to defaults", - "operationId": "resetSettings", - "responses": { - "200": { - "description": "Settings reset successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string" - } - } - } - } - } - }, - "500": { - "description": "Error resetting settings", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "error": { - "type": "string" - } - } - } - } - } - } - } - } - }, "/api/options/models": { "get": { "summary": "Get models", @@ -2095,4 +2082,4 @@ "bearerAuth": [] } ] -} \ No newline at end of file +} diff --git a/frontend/__tests__/routes/settings.test.tsx b/frontend/__tests__/routes/settings.test.tsx index 44cb4592e3..27972a7276 100644 --- a/frontend/__tests__/routes/settings.test.tsx +++ b/frontend/__tests__/routes/settings.test.tsx @@ -25,7 +25,6 @@ const mock_provider_tokens_are_set: Record = { describe("Settings Screen", () => { const getSettingsSpy = vi.spyOn(OpenHands, "getSettings"); const saveSettingsSpy = vi.spyOn(OpenHands, "saveSettings"); - const resetSettingsSpy = vi.spyOn(OpenHands, "resetSettings"); const getConfigSpy = vi.spyOn(OpenHands, "getConfig"); const { handleLogoutMock } = vi.hoisted(() => ({ @@ -67,7 +66,6 @@ describe("Settings Screen", () => { // Use queryAllByText to handle multiple elements with the same text expect(screen.queryAllByText("SETTINGS$LLM_SETTINGS")).not.toHaveLength(0); screen.getByText("ACCOUNT_SETTINGS$ADDITIONAL_SETTINGS"); - screen.getByText("BUTTON$RESET_TO_DEFAULTS"); screen.getByText("BUTTON$SAVE"); }); }); @@ -542,54 +540,6 @@ describe("Settings Screen", () => { }); }); - test("resetting settings with no changes but having advanced enabled should hide the advanced items", async () => { - const user = userEvent.setup(); - - getSettingsSpy.mockResolvedValueOnce({ - ...MOCK_DEFAULT_USER_SETTINGS, - }); - - renderSettingsScreen(); - - await toggleAdvancedSettings(user); - - const resetButton = screen.getByText("BUTTON$RESET_TO_DEFAULTS"); - await user.click(resetButton); - - // show modal - const modal = await screen.findByTestId("reset-modal"); - expect(modal).toBeInTheDocument(); - - // Mock the settings that will be returned after reset - // This should be the default settings with no advanced settings enabled - getSettingsSpy.mockResolvedValueOnce({ - ...MOCK_DEFAULT_USER_SETTINGS, - llm_base_url: "", - confirmation_mode: false, - security_analyzer: "", - }); - - // confirm reset - const confirmButton = within(modal).getByText("Reset"); - await user.click(confirmButton); - - await waitFor(() => { - expect( - screen.queryByTestId("llm-custom-model-input"), - ).not.toBeInTheDocument(); - expect( - screen.queryByTestId("base-url-input"), - ).not.toBeInTheDocument(); - expect(screen.queryByTestId("agent-input")).not.toBeInTheDocument(); - expect( - screen.queryByTestId("security-analyzer-input"), - ).not.toBeInTheDocument(); - expect( - screen.queryByTestId("enable-confirmation-mode-switch"), - ).not.toBeInTheDocument(); - }); - }); - it("should save if only confirmation mode is enabled", async () => { const user = userEvent.setup(); renderSettingsScreen(); @@ -762,81 +712,6 @@ describe("Settings Screen", () => { ); }); - it("should reset the settings when the 'Reset to defaults' button is clicked", async () => { - const user = userEvent.setup(); - getSettingsSpy.mockResolvedValue(MOCK_DEFAULT_USER_SETTINGS); - - renderSettingsScreen(); - - const languageInput = await screen.findByTestId("language-input"); - await user.click(languageInput); - - const norskOption = await screen.findByText("Norsk"); - await user.click(norskOption); - - expect(languageInput).toHaveValue("Norsk"); - - const resetButton = screen.getByText("BUTTON$RESET_TO_DEFAULTS"); - await user.click(resetButton); - - expect(saveSettingsSpy).not.toHaveBeenCalled(); - - // show modal - const modal = await screen.findByTestId("reset-modal"); - expect(modal).toBeInTheDocument(); - - // confirm reset - const confirmButton = within(modal).getByText("Reset"); - await user.click(confirmButton); - - await waitFor(() => { - expect(resetSettingsSpy).toHaveBeenCalled(); - }); - - // Mock the settings response after reset - getSettingsSpy.mockResolvedValueOnce({ - ...MOCK_DEFAULT_USER_SETTINGS, - llm_base_url: "", - confirmation_mode: false, - security_analyzer: "", - }); - - // Wait for the mutation to complete and the modal to be removed - await waitFor(() => { - expect(screen.queryByTestId("reset-modal")).not.toBeInTheDocument(); - expect( - screen.queryByTestId("llm-custom-model-input"), - ).not.toBeInTheDocument(); - expect(screen.queryByTestId("base-url-input")).not.toBeInTheDocument(); - expect(screen.queryByTestId("agent-input")).not.toBeInTheDocument(); - expect( - screen.queryByTestId("security-analyzer-input"), - ).not.toBeInTheDocument(); - expect( - screen.queryByTestId("enable-confirmation-mode-switch"), - ).not.toBeInTheDocument(); - }); - }); - - it("should cancel the reset when the 'Cancel' button is clicked", async () => { - const user = userEvent.setup(); - getSettingsSpy.mockResolvedValue(MOCK_DEFAULT_USER_SETTINGS); - - renderSettingsScreen(); - - const resetButton = await screen.findByText("BUTTON$RESET_TO_DEFAULTS"); - await user.click(resetButton); - - const modal = await screen.findByTestId("reset-modal"); - expect(modal).toBeInTheDocument(); - - const cancelButton = within(modal).getByText("Cancel"); - await user.click(cancelButton); - - expect(saveSettingsSpy).not.toHaveBeenCalled(); - expect(screen.queryByTestId("reset-modal")).not.toBeInTheDocument(); - }); - it("should call handleCaptureConsent with true if the save is successful", async () => { const user = userEvent.setup(); const handleCaptureConsentSpy = vi.spyOn( @@ -1044,18 +919,5 @@ describe("Settings Screen", () => { ); }); - it("should not submit the unwanted fields when resetting", async () => { - const user = userEvent.setup(); - renderSettingsScreen(); - - const resetButton = await screen.findByText("BUTTON$RESET_TO_DEFAULTS"); - await user.click(resetButton); - - const modal = await screen.findByTestId("reset-modal"); - const confirmButton = within(modal).getByText("Reset"); - await user.click(confirmButton); - expect(saveSettingsSpy).not.toHaveBeenCalled(); - expect(resetSettingsSpy).toHaveBeenCalled(); - }); }); }); diff --git a/frontend/src/api/open-hands.ts b/frontend/src/api/open-hands.ts index ed5bbbba31..12bd42bcbf 100644 --- a/frontend/src/api/open-hands.ts +++ b/frontend/src/api/open-hands.ts @@ -199,14 +199,6 @@ class OpenHands { return data.status === 200; } - /** - * Reset user settings in server - */ - static async resetSettings(): Promise { - const response = await openHands.post("/api/reset-settings"); - return response.status === 200; - } - static async createCheckoutSession(amount: number): Promise { const { data } = await openHands.post( "/api/billing/create-checkout-session", diff --git a/frontend/src/hooks/mutation/use-save-settings.ts b/frontend/src/hooks/mutation/use-save-settings.ts index 1eb1df7376..436e548afc 100644 --- a/frontend/src/hooks/mutation/use-save-settings.ts +++ b/frontend/src/hooks/mutation/use-save-settings.ts @@ -4,15 +4,7 @@ import OpenHands from "#/api/open-hands"; import { PostSettings, PostApiSettings } from "#/types/settings"; import { useSettings } from "../query/use-settings"; -const saveSettingsMutationFn = async ( - settings: Partial | null, -) => { - // If settings is null, we're resetting - if (settings === null) { - await OpenHands.resetSettings(); - return; - } - +const saveSettingsMutationFn = async (settings: Partial) => { const apiSettings: Partial = { llm_model: settings.LLM_MODEL, llm_base_url: settings.LLM_BASE_URL, @@ -39,12 +31,7 @@ export const useSaveSettings = () => { const { data: currentSettings } = useSettings(); return useMutation({ - mutationFn: async (settings: Partial | null) => { - if (settings === null) { - await saveSettingsMutationFn(null); - return; - } - + mutationFn: async (settings: Partial) => { const newSettings = { ...currentSettings, ...settings }; await saveSettingsMutationFn(newSettings); }, diff --git a/frontend/src/i18n/declaration.ts b/frontend/src/i18n/declaration.ts index f2c8b00511..9421c41e2e 100644 --- a/frontend/src/i18n/declaration.ts +++ b/frontend/src/i18n/declaration.ts @@ -82,7 +82,6 @@ export enum I18nKey { API$DONT_KNOW_KEY = "API$DONT_KNOW_KEY", BUTTON$SAVE = "BUTTON$SAVE", BUTTON$CLOSE = "BUTTON$CLOSE", - BUTTON$RESET_TO_DEFAULTS = "BUTTON$RESET_TO_DEFAULTS", MODAL$CONFIRM_RESET_TITLE = "MODAL$CONFIRM_RESET_TITLE", MODAL$CONFIRM_RESET_MESSAGE = "MODAL$CONFIRM_RESET_MESSAGE", MODAL$END_SESSION_TITLE = "MODAL$END_SESSION_TITLE", @@ -321,7 +320,6 @@ export enum I18nKey { SETTINGS_FORM$ENABLE_CONFIRMATION_MODE_LABEL = "SETTINGS_FORM$ENABLE_CONFIRMATION_MODE_LABEL", SETTINGS_FORM$SAVE_LABEL = "SETTINGS_FORM$SAVE_LABEL", SETTINGS_FORM$CLOSE_LABEL = "SETTINGS_FORM$CLOSE_LABEL", - SETTINGS_FORM$RESET_TO_DEFAULTS_LABEL = "SETTINGS_FORM$RESET_TO_DEFAULTS_LABEL", SETTINGS_FORM$CANCEL_LABEL = "SETTINGS_FORM$CANCEL_LABEL", SETTINGS_FORM$END_SESSION_LABEL = "SETTINGS_FORM$END_SESSION_LABEL", SETTINGS_FORM$CHANGING_WORKSPACE_WARNING_MESSAGE = "SETTINGS_FORM$CHANGING_WORKSPACE_WARNING_MESSAGE", diff --git a/frontend/src/i18n/translation.json b/frontend/src/i18n/translation.json index e33d5e8e79..8490feb095 100644 --- a/frontend/src/i18n/translation.json +++ b/frontend/src/i18n/translation.json @@ -1231,21 +1231,6 @@ "tr": "Kapat", "de": "Schließen" }, - "BUTTON$RESET_TO_DEFAULTS": { - "en": "Reset to defaults", - "ja": "デフォルトにリセット", - "zh-CN": "重置为默认值", - "zh-TW": "還原為預設值", - "ko-KR": "기본값으로 재설정", - "no": "Tilbakestill til standard", - "it": "Ripristina valori predefiniti", - "pt": "Restaurar padrões", - "es": "Restablecer valores predeterminados", - "ar": "إعادة التعيين إلى الإعدادات الافتراضية", - "fr": "Réinitialiser aux valeurs par défaut", - "tr": "Varsayılanlara sıfırla", - "de": "Auf Standardwerte zurücksetzen" - }, "MODAL$CONFIRM_RESET_TITLE": { "en": "Are you sure?", "ja": "本当によろしいですか?", @@ -4541,21 +4526,6 @@ "pt": "Fechar", "tr": "Kapat" }, - "SETTINGS_FORM$RESET_TO_DEFAULTS_LABEL": { - "en": "Reset to defaults", - "es": "Reiniciar valores por defect", - "zh-CN": "重置为默认值", - "zh-TW": "還原為預設值", - "ko-KR": "기본값으로 재설정", - "ja": "デフォルトに戻す", - "no": "Tilbakestill til standardverdier", - "ar": "إعادة التعيين إلى الإعدادات الافتراضية", - "de": "Auf Standardwerte zurücksetzen", - "fr": "Réinitialiser aux valeurs par défaut", - "it": "Ripristina valori predefiniti", - "pt": "Restaurar padrões", - "tr": "Varsayılanlara sıfırla" - }, "SETTINGS_FORM$CANCEL_LABEL": { "en": "Cancel", "es": "Cancelar", diff --git a/frontend/src/routes/account-settings.tsx b/frontend/src/routes/account-settings.tsx index 6a00bbcc7a..6183e4c72a 100644 --- a/frontend/src/routes/account-settings.tsx +++ b/frontend/src/routes/account-settings.tsx @@ -9,7 +9,6 @@ import { SettingsDropdownInput } from "#/components/features/settings/settings-d import { SettingsInput } from "#/components/features/settings/settings-input"; import { SettingsSwitch } from "#/components/features/settings/settings-switch"; import { LoadingSpinner } from "#/components/shared/loading-spinner"; -import { ModalBackdrop } from "#/components/shared/modals/modal-backdrop"; import { ModelSelector } from "#/components/shared/modals/settings/model-selector"; import { useSaveSettings } from "#/hooks/mutation/use-save-settings"; import { useAIConfigOptions } from "#/hooks/query/use-ai-config-options"; @@ -95,8 +94,6 @@ function AccountSettings() { >(isAdvancedSettingsSet ? "advanced" : "basic"); const [confirmationModeIsEnabled, setConfirmationModeIsEnabled] = React.useState(!!settings?.SECURITY_ANALYZER); - const [resetSettingsModalIsOpen, setResetSettingsModalIsOpen] = - React.useState(false); const formRef = React.useRef(null); @@ -180,16 +177,6 @@ function AccountSettings() { }); }; - const handleReset = () => { - saveSettings(null, { - onSuccess: () => { - displaySuccessToast(t(I18nKey.SETTINGS$RESET)); - setResetSettingsModalIsOpen(false); - setLlmConfigMode("basic"); - }, - }); - }; - React.useEffect(() => { // If settings is still loading by the time the state is set, it will always // default to basic settings. This is a workaround to ensure the correct @@ -527,13 +514,6 @@ function AccountSettings() {
- setResetSettingsModalIsOpen(true)} - > - {t(I18nKey.BUTTON$RESET_TO_DEFAULTS)} -
- - {resetSettingsModalIsOpen && ( - -
-

{t(I18nKey.SETTINGS$RESET_CONFIRMATION)}

-
- { - handleReset(); - }} - > - Reset - - - { - setResetSettingsModalIsOpen(false); - }} - > - Cancel - -
-
-
- )} ); } diff --git a/openhands/events/serialization/event.py b/openhands/events/serialization/event.py index 4059055ed6..f18a0d77aa 100644 --- a/openhands/events/serialization/event.py +++ b/openhands/events/serialization/event.py @@ -135,7 +135,6 @@ def event_to_dict(event: 'Event') -> dict: k: (v.value if isinstance(v, Enum) else _convert_pydantic_to_dict(v)) for k, v in props.items() } - logger.debug(f'extras data in event_to_dict: {d["extras"]}') # Include success field for CmdOutputObservation if hasattr(event, 'success'): d['success'] = event.success diff --git a/openhands/llm/llm.py b/openhands/llm/llm.py index 29268c226f..ca4aa079a5 100644 --- a/openhands/llm/llm.py +++ b/openhands/llm/llm.py @@ -713,7 +713,7 @@ class LLM(RetryMixin, DebugMixin): completion_response=response, **extra_kwargs ) except Exception as e: - logger.error(f'Error getting cost from litellm: {e}') + logger.debug(f'Error getting cost from litellm: {e}') if cost is None: _model_name = '/'.join(self.config.model.split('/')[1:]) diff --git a/openhands/server/routes/settings.py b/openhands/server/routes/settings.py index 46579f9e01..c10c682943 100644 --- a/openhands/server/routes/settings.py +++ b/openhands/server/routes/settings.py @@ -207,54 +207,15 @@ async def unset_settings_tokens(request: Request) -> JSONResponse: @app.post('/reset-settings', response_model=dict[str, str]) async def reset_settings(request: Request) -> JSONResponse: """ - Resets user settings. + Resets user settings. (Deprecated) """ - try: - settings_store = await SettingsStoreImpl.get_instance( - config, get_user_id(request) - ) - - existing_settings: Settings = await settings_store.load() - settings = Settings( - language='en', - agent='CodeActAgent', - security_analyzer='', - confirmation_mode=False, - llm_model='anthropic/claude-3-5-sonnet-20241022', - llm_api_key=SecretStr(''), - llm_base_url=None, - remote_runtime_resource_factor=1, - enable_default_condenser=True, - enable_sound_notifications=False, - user_consents_to_analytics=existing_settings.user_consents_to_analytics - if existing_settings - else False, - secrets_store=existing_settings.secrets_store - ) - - server_config_values = server_config.get_config() - is_hide_llm_settings_enabled = server_config_values.get( - 'FEATURE_FLAGS', {} - ).get('HIDE_LLM_SETTINGS', False) - # We don't want the user to be able to modify these settings in SaaS - if server_config.app_mode == AppMode.SAAS and is_hide_llm_settings_enabled: - if existing_settings: - settings.llm_api_key = existing_settings.llm_api_key - settings.llm_base_url = existing_settings.llm_base_url - settings.llm_model = existing_settings.llm_model - - await settings_store.store(settings) - return JSONResponse( - status_code=status.HTTP_200_OK, - content={'message': 'Settings stored'}, - ) - - except Exception as e: - logger.warning(f'Something went wrong resetting settings: {e}') - return JSONResponse( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - content={'error': 'Something went wrong resetting settings'}, - ) + logger.warning( + f"Deprecated endpoint /api/reset-settings called by user" + ) + return JSONResponse( + status_code=status.HTTP_410_GONE, + content={'error': 'Reset settings functionality has been removed.'}, + ) async def check_provider_tokens(request: Request, settings: POSTSettingsModel) -> str: