Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix state dir in docker mode #5840

Merged
merged 7 commits into from
Dec 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ docker run -it --rm --pull=always \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.17-nikolaik \
-e LOG_ALL_EVENTS=true \
-v /var/run/docker.sock:/var/run/docker.sock \
-v ~/.openhands-state:/home/openhands/.openhands-state \
-v ~/.openhands-state:/.openhands-state \
-p 3000:3000 \
--add-host host.docker.internal:host-gateway \
--name openhands-app \
Expand Down
3 changes: 2 additions & 1 deletion containers/app/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ ENV WORKSPACE_BASE=/opt/workspace_base
ENV OPENHANDS_BUILD_VERSION=$OPENHANDS_BUILD_VERSION
ENV SANDBOX_USER_ID=0
ENV FILE_STORE=local
ENV FILE_STORE_PATH=~/.openhands-state
ENV FILE_STORE_PATH=/.openhands-state
RUN mkdir -p $FILE_STORE_PATH
RUN mkdir -p $WORKSPACE_BASE

RUN apt-get update -y \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ export function SecurityAnalyzerInput({
</label>
<Autocomplete
isDisabled={isDisabled}
isRequired
id="security-analyzer"
name="security-analyzer"
aria-label="Security Analyzer"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,7 @@ import { getDefaultSettings, Settings } from "#/services/settings";
import { extractModelAndProvider } from "#/utils/extract-model-and-provider";
import { DangerModal } from "../confirmation-modals/danger-modal";
import { I18nKey } from "#/i18n/declaration";
import {
extractSettings,
saveSettingsView,
updateSettingsVersion,
} from "#/utils/settings-utils";
import { extractSettings, saveSettingsView } from "#/utils/settings-utils";
import { useEndSession } from "#/hooks/use-end-session";
import { useSettings } from "#/context/settings-context";
import { ModalButton } from "../../buttons/modal-button";
Expand All @@ -24,7 +20,6 @@ import { CustomModelInput } from "../../inputs/custom-model-input";
import { SecurityAnalyzerInput } from "../../inputs/security-analyzers-input";
import { ModalBackdrop } from "../modal-backdrop";
import { ModelSelector } from "./model-selector";
import { useAuth } from "#/context/auth-context";

interface SettingsFormProps {
disabled?: boolean;
Expand All @@ -45,7 +40,6 @@ export function SettingsForm({
}: SettingsFormProps) {
const { saveSettings } = useSettings();
const endSession = useEndSession();
const { logout } = useAuth();

const location = useLocation();
const { t } = useTranslation();
Expand Down Expand Up @@ -98,7 +92,6 @@ export function SettingsForm({
const newSettings = extractSettings(formData);

saveSettingsView(isUsingAdvancedOptions ? "advanced" : "basic");
updateSettingsVersion(logout);
saveSettings(newSettings);
resetOngoingSession();

Expand Down
6 changes: 6 additions & 0 deletions frontend/src/routes/_oh/route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useGitHubAuthUrl } from "#/hooks/use-github-auth-url";
import { useIsAuthed } from "#/hooks/query/use-is-authed";
import { useAuth } from "#/context/auth-context";
import { useSettings } from "#/context/settings-context";
import { updateSettingsVersion } from "#/utils/settings-utils";
import { useConfig } from "#/hooks/query/use-config";
import { Sidebar } from "#/components/features/sidebar/sidebar";
import { WaitlistModal } from "#/components/features/waitlist/waitlist-modal";
Expand Down Expand Up @@ -45,6 +46,7 @@ export function ErrorBoundary() {
export default function MainApp() {
const { gitHubToken } = useAuth();
const { settings } = useSettings();
const { logout } = useAuth();

const [consentFormIsOpen, setConsentFormIsOpen] = React.useState(
!localStorage.getItem("analytics-consent"),
Expand All @@ -65,6 +67,10 @@ export default function MainApp() {
}
}, [settings.LANGUAGE]);

React.useEffect(() => {
updateSettingsVersion(logout);
}, []);

const isInWaitlist =
!isFetchingAuth && !isAuthed && config.data?.APP_MODE === "saas";

Expand Down
100 changes: 54 additions & 46 deletions frontend/src/services/settings.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { openHands } from "#/api/open-hands-axios";

export const LATEST_SETTINGS_VERSION = 4;
export const LATEST_SETTINGS_VERSION = 5;

export type Settings = {
LLM_MODEL: string;
Expand Down Expand Up @@ -45,7 +45,53 @@ export const getCurrentSettingsVersion = () => {
export const settingsAreUpToDate = () =>
getCurrentSettingsVersion() === LATEST_SETTINGS_VERSION;

export const maybeMigrateSettings = (logout: () => void) => {
// TODO: localStorage settings are deprecated. Remove this after 1/31/2025
export const getLocalStorageSettings = (): Settings => {
const llmModel = localStorage.getItem("LLM_MODEL");
const baseUrl = localStorage.getItem("LLM_BASE_URL");
const agent = localStorage.getItem("AGENT");
const language = localStorage.getItem("LANGUAGE");
const llmApiKey = localStorage.getItem("LLM_API_KEY");
const confirmationMode = localStorage.getItem("CONFIRMATION_MODE") === "true";
const securityAnalyzer = localStorage.getItem("SECURITY_ANALYZER");

return {
LLM_MODEL: llmModel || DEFAULT_SETTINGS.LLM_MODEL,
LLM_BASE_URL: baseUrl || DEFAULT_SETTINGS.LLM_BASE_URL,
AGENT: agent || DEFAULT_SETTINGS.AGENT,
LANGUAGE: language || DEFAULT_SETTINGS.LANGUAGE,
LLM_API_KEY: llmApiKey || DEFAULT_SETTINGS.LLM_API_KEY,
CONFIRMATION_MODE: confirmationMode || DEFAULT_SETTINGS.CONFIRMATION_MODE,
SECURITY_ANALYZER: securityAnalyzer || DEFAULT_SETTINGS.SECURITY_ANALYZER,
};
};

/**
* Save the settings to the server. Only valid settings are saved.
* @param settings - the settings to save
*/
export const saveSettings = async (
settings: Partial<Settings>,
): Promise<boolean> => {
try {
const apiSettings = {
llm_model: settings.LLM_MODEL || null,
llm_base_url: settings.LLM_BASE_URL || null,
agent: settings.AGENT || null,
language: settings.LANGUAGE || null,
confirmation_mode: settings.CONFIRMATION_MODE || null,
security_analyzer: settings.SECURITY_ANALYZER || null,
llm_api_key: settings.LLM_API_KEY || null,
};

const { data } = await openHands.post("/api/settings", apiSettings);
return data;
} catch (error) {
return false;
}
};

export const maybeMigrateSettings = async (logout: () => void) => {
// Sometimes we ship major changes, like a new default agent.
// In this case, we may want to override a previous choice made by the user.
const currentVersion = getCurrentSettingsVersion();
Expand All @@ -68,6 +114,11 @@ export const maybeMigrateSettings = (logout: () => void) => {
if (currentVersion < 4) {
logout();
}

if (currentVersion < 5) {
const localSettings = getLocalStorageSettings();
await saveSettings(localSettings);
}
};

/**
Expand All @@ -92,48 +143,5 @@ export const getSettings = async (): Promise<Settings> => {
LLM_API_KEY: "",
};
}

const llmModel = localStorage.getItem("LLM_MODEL");
const baseUrl = localStorage.getItem("LLM_BASE_URL");
const agent = localStorage.getItem("AGENT");
const language = localStorage.getItem("LANGUAGE");
const llmApiKey = localStorage.getItem("LLM_API_KEY");
const confirmationMode = localStorage.getItem("CONFIRMATION_MODE") === "true";
const securityAnalyzer = localStorage.getItem("SECURITY_ANALYZER");

return {
LLM_MODEL: llmModel || DEFAULT_SETTINGS.LLM_MODEL,
LLM_BASE_URL: baseUrl || DEFAULT_SETTINGS.LLM_BASE_URL,
AGENT: agent || DEFAULT_SETTINGS.AGENT,
LANGUAGE: language || DEFAULT_SETTINGS.LANGUAGE,
LLM_API_KEY: llmApiKey || DEFAULT_SETTINGS.LLM_API_KEY,
CONFIRMATION_MODE: confirmationMode || DEFAULT_SETTINGS.CONFIRMATION_MODE,
SECURITY_ANALYZER: securityAnalyzer || DEFAULT_SETTINGS.SECURITY_ANALYZER,
};
};

/**
* Save the settings to the server. Only valid settings are saved.
* @param settings - the settings to save
*/
export const saveSettings = async (
settings: Partial<Settings>,
): Promise<boolean> => {
try {
const apiSettings = {
llm_model: settings.LLM_MODEL || null,
llm_base_url: settings.LLM_BASE_URL || null,
agent: settings.AGENT || null,
language: settings.LANGUAGE || null,
confirmation_mode: settings.CONFIRMATION_MODE || null,
security_analyzer: settings.SECURITY_ANALYZER || null,
llm_api_key: settings.LLM_API_KEY || null,
};

const { data } = await openHands.post("/api/settings", apiSettings);
return data;
} catch (error) {
console.error("Error saving settings:", error);
return false;
}
return getLocalStorageSettings();
};
4 changes: 2 additions & 2 deletions frontend/src/utils/settings-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,9 @@ const saveSettingsView = (view: "basic" | "advanced") => {
* Updates the settings version in local storage if the current settings are not up to date.
* If the settings are outdated, it attempts to migrate them before updating the version.
*/
const updateSettingsVersion = (logout: () => void) => {
const updateSettingsVersion = async (logout: () => void) => {
if (!settingsAreUpToDate()) {
maybeMigrateSettings(logout);
await maybeMigrateSettings(logout);
localStorage.setItem(
"SETTINGS_VERSION",
LATEST_SETTINGS_VERSION.toString(),
Expand Down
Loading