diff --git a/evaluation/benchmarks/EDA/run_infer.py b/evaluation/benchmarks/EDA/run_infer.py index f216a86ff8..a80b745ce7 100644 --- a/evaluation/benchmarks/EDA/run_infer.py +++ b/evaluation/benchmarks/EDA/run_infer.py @@ -17,7 +17,7 @@ from evaluation.utils.shared import ( ) from openhands.controller.state.state import State from openhands.core.config import ( - AppConfig, + OpenHandsConfig, get_llm_config_arg, get_parser, ) @@ -59,10 +59,10 @@ AGENT_CLS_TO_INST_SUFFIX = { def get_config( metadata: EvalMetadata, -) -> AppConfig: +) -> OpenHandsConfig: sandbox_config = get_default_sandbox_config_for_eval() sandbox_config.base_container_image = 'python:3.12-bookworm' - config = AppConfig( + config = OpenHandsConfig( default_agent=metadata.agent_class, run_as_openhands=False, runtime='docker', diff --git a/evaluation/benchmarks/agent_bench/run_infer.py b/evaluation/benchmarks/agent_bench/run_infer.py index 55fe36fafd..0452cbe2be 100644 --- a/evaluation/benchmarks/agent_bench/run_infer.py +++ b/evaluation/benchmarks/agent_bench/run_infer.py @@ -25,7 +25,7 @@ from evaluation.utils.shared import ( ) from openhands.controller.state.state import State from openhands.core.config import ( - AppConfig, + OpenHandsConfig, get_llm_config_arg, parse_arguments, ) @@ -39,11 +39,11 @@ from openhands.utils.async_utils import call_async_from_sync def get_config( metadata: EvalMetadata, -) -> AppConfig: +) -> OpenHandsConfig: sandbox_config = get_default_sandbox_config_for_eval() sandbox_config.base_container_image = 'python:3.12-slim' - config = AppConfig( + config = OpenHandsConfig( default_agent=metadata.agent_class, run_as_openhands=False, runtime=os.environ.get('RUNTIME', 'docker'), diff --git a/evaluation/benchmarks/aider_bench/run_infer.py b/evaluation/benchmarks/aider_bench/run_infer.py index 61cfa8061a..20f4cb99a4 100644 --- a/evaluation/benchmarks/aider_bench/run_infer.py +++ b/evaluation/benchmarks/aider_bench/run_infer.py @@ -24,7 +24,7 @@ from evaluation.utils.shared import ( ) from openhands.controller.state.state import State from openhands.core.config import ( - AppConfig, + OpenHandsConfig, get_llm_config_arg, load_from_toml, parse_arguments, @@ -46,10 +46,10 @@ SKIP_NUM = ( def get_config( metadata: EvalMetadata, -) -> AppConfig: +) -> OpenHandsConfig: sandbox_config = get_default_sandbox_config_for_eval() sandbox_config.base_container_image = 'python:3.11-bookworm' - config = AppConfig( + config = OpenHandsConfig( default_agent=metadata.agent_class, run_as_openhands=False, runtime=os.environ.get('RUNTIME', 'docker'), diff --git a/evaluation/benchmarks/biocoder/run_infer.py b/evaluation/benchmarks/biocoder/run_infer.py index 36657a47ee..4172e7d873 100644 --- a/evaluation/benchmarks/biocoder/run_infer.py +++ b/evaluation/benchmarks/biocoder/run_infer.py @@ -22,7 +22,7 @@ from evaluation.utils.shared import ( ) from openhands.controller.state.state import State from openhands.core.config import ( - AppConfig, + OpenHandsConfig, get_llm_config_arg, parse_arguments, ) @@ -55,12 +55,12 @@ FILE_EXT_MAP = { def get_config( metadata: EvalMetadata, -) -> AppConfig: +) -> OpenHandsConfig: BIOCODER_BENCH_CONTAINER_IMAGE = 'public.ecr.aws/i5g0m1f6/eval_biocoder:v1.0' sandbox_config = get_default_sandbox_config_for_eval() sandbox_config.base_container_image = BIOCODER_BENCH_CONTAINER_IMAGE - config = AppConfig( + config = OpenHandsConfig( default_agent=metadata.agent_class, run_as_openhands=False, runtime='docker', diff --git a/evaluation/benchmarks/bird/run_infer.py b/evaluation/benchmarks/bird/run_infer.py index e2cd70d818..82b8ae848e 100644 --- a/evaluation/benchmarks/bird/run_infer.py +++ b/evaluation/benchmarks/bird/run_infer.py @@ -25,7 +25,7 @@ from evaluation.utils.shared import ( ) from openhands.controller.state.state import State from openhands.core.config import ( - AppConfig, + OpenHandsConfig, get_llm_config_arg, parse_arguments, ) @@ -70,11 +70,11 @@ AGENT_CLS_TO_INST_SUFFIX = { def get_config( metadata: EvalMetadata, -) -> AppConfig: +) -> OpenHandsConfig: sandbox_config = get_default_sandbox_config_for_eval() sandbox_config.base_container_image = 'python:3.12-bookworm' - config = AppConfig( + config = OpenHandsConfig( default_agent=metadata.agent_class, run_as_openhands=False, runtime='docker', diff --git a/evaluation/benchmarks/browsing_delegation/run_infer.py b/evaluation/benchmarks/browsing_delegation/run_infer.py index 9d239367c2..2f0e883ef5 100644 --- a/evaluation/benchmarks/browsing_delegation/run_infer.py +++ b/evaluation/benchmarks/browsing_delegation/run_infer.py @@ -18,7 +18,7 @@ from evaluation.utils.shared import ( ) from openhands.controller.state.state import State from openhands.core.config import ( - AppConfig, + OpenHandsConfig, get_llm_config_arg, parse_arguments, ) @@ -33,13 +33,13 @@ SUPPORTED_AGENT_CLS = {'CodeActAgent'} def get_config( metadata: EvalMetadata, -) -> AppConfig: +) -> OpenHandsConfig: assert metadata.max_iterations == 1, ( 'max_iterations must be 1 for browsing delegation evaluation.' ) sandbox_config = get_default_sandbox_config_for_eval() sandbox_config.base_container_image = 'python:3.12-bookworm' - config = AppConfig( + config = OpenHandsConfig( default_agent=metadata.agent_class, run_as_openhands=False, runtime='docker', diff --git a/evaluation/benchmarks/commit0/run_infer.py b/evaluation/benchmarks/commit0/run_infer.py index c40cb953f3..1f6160d0ea 100644 --- a/evaluation/benchmarks/commit0/run_infer.py +++ b/evaluation/benchmarks/commit0/run_infer.py @@ -25,7 +25,7 @@ from evaluation.utils.shared import ( from openhands.controller.state.state import State from openhands.core.config import ( AgentConfig, - AppConfig, + OpenHandsConfig, get_llm_config_arg, get_parser, ) @@ -101,7 +101,7 @@ def get_instance_docker_image(repo_name: str) -> str: def get_config( instance: pd.Series, metadata: EvalMetadata, -) -> AppConfig: +) -> OpenHandsConfig: repo_name = instance['repo'].split('/')[1] base_container_image = get_instance_docker_image(repo_name) logger.info( @@ -113,7 +113,7 @@ def get_config( sandbox_config = get_default_sandbox_config_for_eval() sandbox_config.base_container_image = base_container_image - config = AppConfig( + config = OpenHandsConfig( default_agent=metadata.agent_class, run_as_openhands=False, max_iterations=metadata.max_iterations, diff --git a/evaluation/benchmarks/discoverybench/run_infer.py b/evaluation/benchmarks/discoverybench/run_infer.py index 1ab8eb7f65..b1a6b1a842 100644 --- a/evaluation/benchmarks/discoverybench/run_infer.py +++ b/evaluation/benchmarks/discoverybench/run_infer.py @@ -25,7 +25,7 @@ from evaluation.utils.shared import ( from openhands.controller.state.state import State from openhands.core.config import ( AgentConfig, - AppConfig, + OpenHandsConfig, get_llm_config_arg, parse_arguments, ) @@ -61,10 +61,10 @@ AGENT_CLS_TO_INST_SUFFIX = { def get_config( metadata: EvalMetadata, -) -> AppConfig: +) -> OpenHandsConfig: sandbox_config = get_default_sandbox_config_for_eval() sandbox_config.base_container_image = 'python:3.12-bookworm' - config = AppConfig( + config = OpenHandsConfig( default_agent=metadata.agent_class, run_as_openhands=False, runtime='docker', diff --git a/evaluation/benchmarks/gaia/run_infer.py b/evaluation/benchmarks/gaia/run_infer.py index e31db4bb3c..15f09f4e9b 100644 --- a/evaluation/benchmarks/gaia/run_infer.py +++ b/evaluation/benchmarks/gaia/run_infer.py @@ -21,7 +21,7 @@ from evaluation.utils.shared import ( ) from openhands.controller.state.state import State from openhands.core.config import ( - AppConfig, + OpenHandsConfig, get_llm_config_arg, get_parser, ) @@ -47,10 +47,10 @@ AGENT_CLS_TO_INST_SUFFIX = { def get_config( metadata: EvalMetadata, -) -> AppConfig: +) -> OpenHandsConfig: sandbox_config = get_default_sandbox_config_for_eval() sandbox_config.base_container_image = 'python:3.12-bookworm' - config = AppConfig( + config = OpenHandsConfig( default_agent=metadata.agent_class, run_as_openhands=False, runtime='docker', diff --git a/evaluation/benchmarks/gorilla/run_infer.py b/evaluation/benchmarks/gorilla/run_infer.py index 10844e113e..652e774503 100644 --- a/evaluation/benchmarks/gorilla/run_infer.py +++ b/evaluation/benchmarks/gorilla/run_infer.py @@ -19,7 +19,7 @@ from evaluation.utils.shared import ( ) from openhands.controller.state.state import State from openhands.core.config import ( - AppConfig, + OpenHandsConfig, get_llm_config_arg, get_parser, ) @@ -39,10 +39,10 @@ AGENT_CLS_TO_INST_SUFFIX = { def get_config( metadata: EvalMetadata, -) -> AppConfig: +) -> OpenHandsConfig: sandbox_config = get_default_sandbox_config_for_eval() sandbox_config.base_container_image = 'python:3.12-bookworm' - config = AppConfig( + config = OpenHandsConfig( default_agent=metadata.agent_class, run_as_openhands=False, runtime='docker', diff --git a/evaluation/benchmarks/gpqa/run_infer.py b/evaluation/benchmarks/gpqa/run_infer.py index e297e3fb9e..3bc981378b 100644 --- a/evaluation/benchmarks/gpqa/run_infer.py +++ b/evaluation/benchmarks/gpqa/run_infer.py @@ -37,7 +37,7 @@ from evaluation.utils.shared import ( ) from openhands.controller.state.state import State from openhands.core.config import ( - AppConfig, + OpenHandsConfig, get_llm_config_arg, get_parser, ) @@ -60,10 +60,10 @@ ACTION_FORMAT = """ def get_config( metadata: EvalMetadata, -) -> AppConfig: +) -> OpenHandsConfig: sandbox_config = get_default_sandbox_config_for_eval() sandbox_config.base_container_image = 'python:3.12-bookworm' - config = AppConfig( + config = OpenHandsConfig( default_agent=metadata.agent_class, run_as_openhands=False, runtime='docker', diff --git a/evaluation/benchmarks/humanevalfix/run_infer.py b/evaluation/benchmarks/humanevalfix/run_infer.py index 67577347aa..9d881fb29e 100644 --- a/evaluation/benchmarks/humanevalfix/run_infer.py +++ b/evaluation/benchmarks/humanevalfix/run_infer.py @@ -30,7 +30,7 @@ from evaluation.utils.shared import ( ) from openhands.controller.state.state import State from openhands.core.config import ( - AppConfig, + OpenHandsConfig, get_llm_config_arg, parse_arguments, ) @@ -81,10 +81,10 @@ AGENT_CLS_TO_INST_SUFFIX = { def get_config( metadata: EvalMetadata, -) -> AppConfig: +) -> OpenHandsConfig: sandbox_config = get_default_sandbox_config_for_eval() sandbox_config.base_container_image = 'python:3.12-bookworm' - config = AppConfig( + config = OpenHandsConfig( default_agent=metadata.agent_class, run_as_openhands=False, runtime='docker', diff --git a/evaluation/benchmarks/lca_ci_build_repair/eval_infer.py b/evaluation/benchmarks/lca_ci_build_repair/eval_infer.py index e4c736f5f0..40846e1e61 100644 --- a/evaluation/benchmarks/lca_ci_build_repair/eval_infer.py +++ b/evaluation/benchmarks/lca_ci_build_repair/eval_infer.py @@ -19,10 +19,10 @@ from evaluation.utils.shared import ( make_metadata, ) from openhands.core.config import ( - AppConfig, LLMConfig, + OpenHandsConfig, get_parser, - load_app_config, + load_openhands_config, ) from openhands.core.logger import openhands_logger as logger from openhands.core.main import create_runtime @@ -34,10 +34,10 @@ from openhands.utils.async_utils import call_async_from_sync def get_config( metadata: EvalMetadata, -) -> AppConfig: +) -> OpenHandsConfig: sandbox_config = get_default_sandbox_config_for_eval() sandbox_config.base_container_image = 'python:3.12-bookworm' - config = AppConfig( + config = OpenHandsConfig( default_agent=metadata.agent_class, run_as_openhands=False, runtime='docker', @@ -53,7 +53,7 @@ def get_config( return config -config = load_app_config() +config = load_openhands_config() def load_bench_config(): diff --git a/evaluation/benchmarks/lca_ci_build_repair/run_infer.py b/evaluation/benchmarks/lca_ci_build_repair/run_infer.py index f6c93bb0dc..0fe5e79e3b 100644 --- a/evaluation/benchmarks/lca_ci_build_repair/run_infer.py +++ b/evaluation/benchmarks/lca_ci_build_repair/run_infer.py @@ -29,10 +29,10 @@ from evaluation.utils.shared import ( ) from openhands.controller.state.state import State from openhands.core.config import ( - AppConfig, + OpenHandsConfig, get_llm_config_arg, get_parser, - load_app_config, + load_openhands_config, ) from openhands.core.logger import openhands_logger as logger from openhands.core.main import create_runtime, run_controller @@ -44,10 +44,10 @@ from openhands.utils.async_utils import call_async_from_sync def get_config( metadata: EvalMetadata, -) -> AppConfig: +) -> OpenHandsConfig: sandbox_config = get_default_sandbox_config_for_eval() sandbox_config.base_container_image = 'python:3.12-bookworm' - config = AppConfig( + config = OpenHandsConfig( default_agent=metadata.agent_class, run_as_openhands=False, runtime='docker', @@ -63,7 +63,7 @@ def get_config( return config -config = load_app_config() +config = load_openhands_config() def load_bench_config(): diff --git a/evaluation/benchmarks/logic_reasoning/run_infer.py b/evaluation/benchmarks/logic_reasoning/run_infer.py index bba9bc6691..39743cd674 100644 --- a/evaluation/benchmarks/logic_reasoning/run_infer.py +++ b/evaluation/benchmarks/logic_reasoning/run_infer.py @@ -17,7 +17,7 @@ from evaluation.utils.shared import ( ) from openhands.controller.state.state import State from openhands.core.config import ( - AppConfig, + OpenHandsConfig, get_llm_config_arg, get_parser, ) @@ -44,14 +44,14 @@ AGENT_CLS_TO_INST_SUFFIX = { def get_config( metadata: EvalMetadata, -) -> AppConfig: +) -> OpenHandsConfig: sandbox_config = get_default_sandbox_config_for_eval() sandbox_config.base_container_image = 'xingyaoww/od-eval-logic-reasoning:v1.0' sandbox_config.runtime_extra_deps = ( '$OH_INTERPRETER_PATH -m pip install scitools-pyke' ) - config = AppConfig( + config = OpenHandsConfig( default_agent=metadata.agent_class, run_as_openhands=False, runtime='docker', diff --git a/evaluation/benchmarks/miniwob/run_infer.py b/evaluation/benchmarks/miniwob/run_infer.py index 5790f6fd6f..df0438c516 100644 --- a/evaluation/benchmarks/miniwob/run_infer.py +++ b/evaluation/benchmarks/miniwob/run_infer.py @@ -21,7 +21,7 @@ from evaluation.utils.shared import ( ) from openhands.controller.state.state import State from openhands.core.config import ( - AppConfig, + OpenHandsConfig, get_llm_config_arg, parse_arguments, ) @@ -54,10 +54,10 @@ AGENT_CLS_TO_FAKE_USER_RESPONSE_FN = { def get_config( metadata: EvalMetadata, env_id: str, -) -> AppConfig: +) -> OpenHandsConfig: sandbox_config = get_default_sandbox_config_for_eval() sandbox_config.base_container_image = 'xingyaoww/od-eval-miniwob:v1.0' - config = AppConfig( + config = OpenHandsConfig( default_agent=metadata.agent_class, run_as_openhands=False, runtime=os.environ.get('RUNTIME', 'docker'), diff --git a/evaluation/benchmarks/mint/run_infer.py b/evaluation/benchmarks/mint/run_infer.py index 5a2dd237d2..d0cec13a2f 100644 --- a/evaluation/benchmarks/mint/run_infer.py +++ b/evaluation/benchmarks/mint/run_infer.py @@ -22,7 +22,7 @@ from evaluation.utils.shared import ( ) from openhands.controller.state.state import State from openhands.core.config import ( - AppConfig, + OpenHandsConfig, get_llm_config_arg, get_parser, ) @@ -102,14 +102,14 @@ def load_incontext_example(task_name: str, with_tool: bool = True): def get_config( metadata: EvalMetadata, -) -> AppConfig: +) -> OpenHandsConfig: sandbox_config = get_default_sandbox_config_for_eval() sandbox_config.base_container_image = 'xingyaoww/od-eval-mint:v1.0' sandbox_config.runtime_extra_deps = ( f'$OH_INTERPRETER_PATH -m pip install {" ".join(MINT_DEPENDENCIES)}' ) - config = AppConfig( + config = OpenHandsConfig( default_agent=metadata.agent_class, run_as_openhands=False, runtime='docker', diff --git a/evaluation/benchmarks/ml_bench/run_analysis.py b/evaluation/benchmarks/ml_bench/run_analysis.py index 1079073826..9c0958060f 100644 --- a/evaluation/benchmarks/ml_bench/run_analysis.py +++ b/evaluation/benchmarks/ml_bench/run_analysis.py @@ -4,11 +4,11 @@ import pprint import tqdm -from openhands.core.config import get_llm_config_arg, get_parser, load_app_config +from openhands.core.config import get_llm_config_arg, get_parser, load_openhands_config from openhands.core.logger import openhands_logger as logger from openhands.llm.llm import LLM -config = load_app_config() +config = load_openhands_config() def extract_test_results(res_file_path: str) -> tuple[list[str], list[str]]: diff --git a/evaluation/benchmarks/ml_bench/run_infer.py b/evaluation/benchmarks/ml_bench/run_infer.py index 09230ff0ce..40874cf9a4 100644 --- a/evaluation/benchmarks/ml_bench/run_infer.py +++ b/evaluation/benchmarks/ml_bench/run_infer.py @@ -33,10 +33,10 @@ from evaluation.utils.shared import ( ) from openhands.controller.state.state import State from openhands.core.config import ( - AppConfig, + OpenHandsConfig, get_llm_config_arg, get_parser, - load_app_config, + load_openhands_config, ) from openhands.core.logger import openhands_logger as logger from openhands.core.main import create_runtime, run_controller @@ -45,7 +45,7 @@ from openhands.events.observation import CmdOutputObservation from openhands.runtime.base import Runtime from openhands.utils.async_utils import call_async_from_sync -config = load_app_config() +config = load_openhands_config() AGENT_CLS_TO_FAKE_USER_RESPONSE_FN = { 'CodeActAgent': codeact_user_response, @@ -76,10 +76,10 @@ ID2CONDA = { def get_config( metadata: EvalMetadata, -) -> AppConfig: +) -> OpenHandsConfig: sandbox_config = get_default_sandbox_config_for_eval() sandbox_config.base_container_image = 'public.ecr.aws/i5g0m1f6/ml-bench' - config = AppConfig( + config = OpenHandsConfig( default_agent=metadata.agent_class, run_as_openhands=False, runtime='docker', diff --git a/evaluation/benchmarks/multi_swe_bench/eval_infer.py b/evaluation/benchmarks/multi_swe_bench/eval_infer.py index 4b1af51088..c895bb0b62 100644 --- a/evaluation/benchmarks/multi_swe_bench/eval_infer.py +++ b/evaluation/benchmarks/multi_swe_bench/eval_infer.py @@ -28,8 +28,8 @@ from evaluation.utils.shared import ( run_evaluation, ) from openhands.core.config import ( - AppConfig, LLMConfig, + OpenHandsConfig, get_parser, ) from openhands.core.logger import openhands_logger as logger @@ -73,7 +73,7 @@ def process_git_patch(patch): return patch -def get_config(metadata: EvalMetadata, instance: pd.Series) -> AppConfig: +def get_config(metadata: EvalMetadata, instance: pd.Series) -> OpenHandsConfig: # We use a different instance image for the each instance of swe-bench eval base_container_image = get_instance_docker_image(instance['instance_id']) logger.info( @@ -87,7 +87,7 @@ def get_config(metadata: EvalMetadata, instance: pd.Series) -> AppConfig: dataset_name=metadata.dataset, instance_id=instance['instance_id'], ) - config = AppConfig( + config = OpenHandsConfig( run_as_openhands=False, runtime=os.environ.get('RUNTIME', 'docker'), sandbox=sandbox_config, diff --git a/evaluation/benchmarks/multi_swe_bench/run_infer.py b/evaluation/benchmarks/multi_swe_bench/run_infer.py index d62a3ea5b1..df0efd339d 100644 --- a/evaluation/benchmarks/multi_swe_bench/run_infer.py +++ b/evaluation/benchmarks/multi_swe_bench/run_infer.py @@ -30,7 +30,7 @@ from evaluation.utils.shared import ( from openhands.controller.state.state import State from openhands.core.config import ( AgentConfig, - AppConfig, + OpenHandsConfig, get_llm_config_arg, get_parser, ) @@ -314,7 +314,7 @@ def get_instance_docker_image(instance: pd.Series): def get_config( instance: pd.Series, metadata: EvalMetadata, -) -> AppConfig: +) -> OpenHandsConfig: SWE_BENCH_CONTAINER_IMAGE = 'ghcr.io/opendevin/eval-swe-bench:full-v1.2.1' if USE_INSTANCE_IMAGE: # We use a different instance image for the each instance of swe-bench eval @@ -340,7 +340,7 @@ def get_config( instance_id=instance['instance_id'], ) - config = AppConfig( + config = OpenHandsConfig( default_agent=metadata.agent_class, run_as_openhands=False, max_iterations=metadata.max_iterations, diff --git a/evaluation/benchmarks/scienceagentbench/run_infer.py b/evaluation/benchmarks/scienceagentbench/run_infer.py index 6e4a6fe12a..8a83a7e200 100644 --- a/evaluation/benchmarks/scienceagentbench/run_infer.py +++ b/evaluation/benchmarks/scienceagentbench/run_infer.py @@ -20,7 +20,7 @@ from evaluation.utils.shared import ( ) from openhands.controller.state.state import State from openhands.core.config import ( - AppConfig, + OpenHandsConfig, get_llm_config_arg, get_parser, ) @@ -58,12 +58,12 @@ def format_task_dict(example, use_knowledge): def get_config( metadata: EvalMetadata, instance_id: str, -) -> AppConfig: +) -> OpenHandsConfig: sandbox_config = get_default_sandbox_config_for_eval() sandbox_config.base_container_image = ( 'docker.io/xingyaoww/openhands-eval-scienceagentbench' ) - config = AppConfig( + config = OpenHandsConfig( default_agent=metadata.agent_class, run_as_openhands=False, runtime=os.environ.get('RUNTIME', 'docker'), diff --git a/evaluation/benchmarks/swe_bench/eval_infer.py b/evaluation/benchmarks/swe_bench/eval_infer.py index c8d68fe6e5..48170be8b5 100644 --- a/evaluation/benchmarks/swe_bench/eval_infer.py +++ b/evaluation/benchmarks/swe_bench/eval_infer.py @@ -24,8 +24,8 @@ from evaluation.utils.shared import ( run_evaluation, ) from openhands.core.config import ( - AppConfig, LLMConfig, + OpenHandsConfig, get_parser, ) from openhands.core.logger import openhands_logger as logger @@ -69,7 +69,7 @@ def process_git_patch(patch): return patch -def get_config(metadata: EvalMetadata, instance: pd.Series) -> AppConfig: +def get_config(metadata: EvalMetadata, instance: pd.Series) -> OpenHandsConfig: # We use a different instance image for the each instance of swe-bench eval base_container_image = get_instance_docker_image(instance['instance_id']) logger.info( @@ -83,7 +83,7 @@ def get_config(metadata: EvalMetadata, instance: pd.Series) -> AppConfig: dataset_name=metadata.dataset, instance_id=instance['instance_id'], ) - config = AppConfig( + config = OpenHandsConfig( run_as_openhands=False, runtime=os.environ.get('RUNTIME', 'docker'), sandbox=sandbox_config, diff --git a/evaluation/benchmarks/swe_bench/run_infer.py b/evaluation/benchmarks/swe_bench/run_infer.py index c7846055f9..ea242736c3 100644 --- a/evaluation/benchmarks/swe_bench/run_infer.py +++ b/evaluation/benchmarks/swe_bench/run_infer.py @@ -40,12 +40,12 @@ from evaluation.utils.shared import ( from openhands.controller.state.state import State from openhands.core.config import ( AgentConfig, - AppConfig, + OpenHandsConfig, get_llm_config_arg, get_parser, ) -from openhands.core.config.utils import get_condenser_config_arg from openhands.core.config.condenser_config import NoOpCondenserConfig +from openhands.core.config.utils import get_condenser_config_arg from openhands.core.logger import openhands_logger as logger from openhands.core.main import create_runtime, run_controller from openhands.critic import AgentFinishedCritic @@ -220,7 +220,7 @@ def get_instance_docker_image( def get_config( instance: pd.Series, metadata: EvalMetadata, -) -> AppConfig: +) -> OpenHandsConfig: # We use a different instance image for the each instance of swe-bench eval use_swebench_official_image = 'swe-gym' not in metadata.dataset.lower() base_container_image = get_instance_docker_image( @@ -244,7 +244,7 @@ def get_config( instance_id=instance['instance_id'], ) - config = AppConfig( + config = OpenHandsConfig( default_agent=metadata.agent_class, run_as_openhands=False, max_iterations=metadata.max_iterations, @@ -721,15 +721,16 @@ def filter_dataset(dataset: pd.DataFrame, filter_column: str) -> pd.DataFrame: # repos for the swe-bench instances: # ['astropy/astropy', 'django/django', 'matplotlib/matplotlib', 'mwaskom/seaborn', 'pallets/flask', 'psf/requests', 'pydata/xarray', 'pylint-dev/pylint', 'pytest-dev/pytest', 'scikit-learn/scikit-learn', 'sphinx-doc/sphinx', 'sympy/sympy'] selected_repos = data['selected_repos'] - if isinstance(selected_repos, str): selected_repos = [selected_repos] + if isinstance(selected_repos, str): + selected_repos = [selected_repos] assert isinstance(selected_repos, list) logger.info( f'Filtering {selected_repos} tasks from "selected_repos"...' ) - subset = dataset[dataset["repo"].isin(selected_repos)] + subset = dataset[dataset['repo'].isin(selected_repos)] logger.info(f'Retained {subset.shape[0]} tasks after filtering') return subset - + skip_ids = os.environ.get('SKIP_IDS', '').split(',') if len(skip_ids) > 0: logger.info(f'Filtering {len(skip_ids)} tasks from "SKIP_IDS"...') @@ -806,7 +807,9 @@ if __name__ == '__main__': else: # If no specific condenser config is provided via env var, default to NoOpCondenser condenser_config = NoOpCondenserConfig() - logger.debug('No Condenser config provided via EVAL_CONDENSER, using NoOpCondenser.') + logger.debug( + 'No Condenser config provided via EVAL_CONDENSER, using NoOpCondenser.' + ) details = {'mode': args.mode} _agent_cls = openhands.agenthub.Agent.get_cls(args.agent_cls) diff --git a/evaluation/benchmarks/swe_bench/run_localize.py b/evaluation/benchmarks/swe_bench/run_localize.py index 0b9d5b8dde..2a1dcfe220 100644 --- a/evaluation/benchmarks/swe_bench/run_localize.py +++ b/evaluation/benchmarks/swe_bench/run_localize.py @@ -30,7 +30,7 @@ from evaluation.utils.shared import ( from openhands.controller.state.state import State from openhands.core.config import ( AgentConfig, - AppConfig, + OpenHandsConfig, get_llm_config_arg, get_parser, ) @@ -58,7 +58,7 @@ def _get_swebench_workspace_dir_name(instance: pd.Series) -> str: def get_instruction(instance: pd.Series, metadata: EvalMetadata): - workspace_dir_name = _get_swebench_workspace_dir_name(instance) + _get_swebench_workspace_dir_name(instance) instruction = f""" Consider the following issue description: @@ -168,7 +168,7 @@ def get_instance_docker_image(instance_id: str, official_image: bool = False) -> def get_config( instance: pd.Series, metadata: EvalMetadata, -) -> AppConfig: +) -> OpenHandsConfig: # We use a different instance image for the each instance of swe-bench eval use_official_image = bool( 'verified' in metadata.dataset.lower() or 'lite' in metadata.dataset.lower() @@ -197,7 +197,7 @@ def get_config( 'REPO_PATH': f'/workspace/{workspace_dir_name}/', } - config = AppConfig( + config = OpenHandsConfig( default_agent=metadata.agent_class, run_as_openhands=False, max_iterations=metadata.max_iterations, @@ -348,13 +348,13 @@ def initialize_runtime( # Check if an existing graph index file is available graph_index_file_path = os.path.join( - INDEX_BASE_DIR, 'graph_index_v2.3', f"{instance['instance_id']}.pkl" + INDEX_BASE_DIR, 'graph_index_v2.3', f'{instance["instance_id"]}.pkl' ) if INDEX_BASE_DIR and os.path.exists(graph_index_file_path): logger.info( - f"Copying graph index from {graph_index_file_path} to /workspace/{workspace_dir_name}/_index_data/graph_index_v2.3" + f'Copying graph index from {graph_index_file_path} to /workspace/{workspace_dir_name}/_index_data/graph_index_v2.3' ) - + runtime.copy_to( graph_index_file_path, f'/workspace/{workspace_dir_name}/_index_data/graph_index_v2.3', @@ -364,9 +364,13 @@ def initialize_runtime( ) obs = runtime.run_action(action) - bm25_index_dir = os.path.join(INDEX_BASE_DIR, 'BM25_index', instance['instance_id']) + bm25_index_dir = os.path.join( + INDEX_BASE_DIR, 'BM25_index', instance['instance_id'] + ) runtime.copy_to( - bm25_index_dir, f'/workspace/{workspace_dir_name}/_index_data', recursive=True + bm25_index_dir, + f'/workspace/{workspace_dir_name}/_index_data', + recursive=True, ) action = CmdRunAction( command=f'mv _index_data/{instance["instance_id"]} _index_data/bm25_index' diff --git a/evaluation/benchmarks/testgeneval/eval_infer.py b/evaluation/benchmarks/testgeneval/eval_infer.py index 95875b9f8e..6312ff66e5 100644 --- a/evaluation/benchmarks/testgeneval/eval_infer.py +++ b/evaluation/benchmarks/testgeneval/eval_infer.py @@ -41,7 +41,7 @@ from evaluation.utils.shared import ( reset_logger_for_multiprocessing, run_evaluation, ) -from openhands.core.config import AppConfig, SandboxConfig, get_parser +from openhands.core.config import OpenHandsConfig, SandboxConfig, get_parser from openhands.core.logger import openhands_logger as logger from openhands.core.main import create_runtime from openhands.events.action import CmdRunAction @@ -52,13 +52,13 @@ DOCKER_IMAGE_PREFIX = os.environ.get('EVAL_DOCKER_IMAGE_PREFIX', 'docker.io/kdja logger.info(f'Using docker image prefix: {DOCKER_IMAGE_PREFIX}') -def get_config(instance: pd.Series) -> AppConfig: +def get_config(instance: pd.Series) -> OpenHandsConfig: base_container_image = get_instance_docker_image(instance['instance_id_swebench']) assert base_container_image, ( f'Invalid container image for instance {instance["instance_id_swebench"]}.' ) logger.info(f'Using instance container image: {base_container_image}.') - return AppConfig( + return OpenHandsConfig( run_as_openhands=False, runtime=os.environ.get('RUNTIME', 'eventstream'), sandbox=SandboxConfig( diff --git a/evaluation/benchmarks/testgeneval/run_infer.py b/evaluation/benchmarks/testgeneval/run_infer.py index 0378bf0ee9..7277f57d8c 100644 --- a/evaluation/benchmarks/testgeneval/run_infer.py +++ b/evaluation/benchmarks/testgeneval/run_infer.py @@ -35,7 +35,7 @@ from evaluation.utils.shared import ( from openhands.controller.state.state import State from openhands.core.config import ( AgentConfig, - AppConfig, + OpenHandsConfig, SandboxConfig, get_llm_config_arg, get_parser, @@ -117,7 +117,7 @@ def get_instance_docker_image(instance_id: str) -> str: def get_config( instance: pd.Series, metadata: EvalMetadata, -) -> AppConfig: +) -> OpenHandsConfig: # We use a different instance image for the each instance of TestGenEval base_container_image = get_instance_docker_image(instance['instance_id_swebench']) logger.info( @@ -126,7 +126,7 @@ def get_config( f'Submit an issue on https://github.com/All-Hands-AI/OpenHands if you run into any issues.' ) - config = AppConfig( + config = OpenHandsConfig( default_agent=metadata.agent_class, run_as_openhands=False, max_iterations=metadata.max_iterations, diff --git a/evaluation/benchmarks/the_agent_company/run_infer.py b/evaluation/benchmarks/the_agent_company/run_infer.py index 50e92e19c9..e71550d0d9 100644 --- a/evaluation/benchmarks/the_agent_company/run_infer.py +++ b/evaluation/benchmarks/the_agent_company/run_infer.py @@ -15,8 +15,8 @@ from browsing import pre_login from evaluation.utils.shared import get_default_sandbox_config_for_eval from openhands.controller.state.state import State from openhands.core.config import ( - AppConfig, LLMConfig, + OpenHandsConfig, get_agent_config_arg, get_llm_config_arg, get_parser, @@ -36,13 +36,13 @@ def get_config( mount_path_on_host: str, llm_config: LLMConfig, agent_config: AgentConfig | None, -) -> AppConfig: +) -> OpenHandsConfig: sandbox_config = get_default_sandbox_config_for_eval() sandbox_config.base_container_image = base_container_image sandbox_config.enable_auto_lint = True # If the web services are running on the host machine, this must be set to True sandbox_config.use_host_network = True - config = AppConfig( + config = OpenHandsConfig( run_as_openhands=False, max_budget_per_task=4, max_iterations=100, @@ -126,7 +126,7 @@ def codeact_user_response(state: State) -> str: def run_solver( runtime: Runtime, task_name: str, - config: AppConfig, + config: OpenHandsConfig, dependencies: list[str], save_final_state: bool, state_dir: str, @@ -274,7 +274,7 @@ if __name__ == '__main__': temp_dir = os.path.abspath(os.getenv('TMPDIR')) else: temp_dir = tempfile.mkdtemp() - config: AppConfig = get_config( + config: OpenHandsConfig = get_config( args.task_image_name, task_short_name, temp_dir, agent_llm_config, agent_config ) runtime: Runtime = create_runtime(config) diff --git a/evaluation/benchmarks/toolqa/run_infer.py b/evaluation/benchmarks/toolqa/run_infer.py index bde3399e20..29e65d944f 100644 --- a/evaluation/benchmarks/toolqa/run_infer.py +++ b/evaluation/benchmarks/toolqa/run_infer.py @@ -18,7 +18,7 @@ from evaluation.utils.shared import ( ) from openhands.controller.state.state import State from openhands.core.config import ( - AppConfig, + OpenHandsConfig, get_llm_config_arg, get_parser, ) @@ -40,10 +40,10 @@ AGENT_CLS_TO_INST_SUFFIX = { def get_config( metadata: EvalMetadata, -) -> AppConfig: +) -> OpenHandsConfig: sandbox_config = get_default_sandbox_config_for_eval() sandbox_config.base_container_image = 'python:3.12-bookworm' - config = AppConfig( + config = OpenHandsConfig( default_agent=metadata.agent_class, run_as_openhands=False, runtime='docker', diff --git a/evaluation/benchmarks/visual_swe_bench/run_infer.py b/evaluation/benchmarks/visual_swe_bench/run_infer.py index 8d272bfc0a..1bdd5349f1 100644 --- a/evaluation/benchmarks/visual_swe_bench/run_infer.py +++ b/evaluation/benchmarks/visual_swe_bench/run_infer.py @@ -30,7 +30,7 @@ from evaluation.utils.shared import ( from openhands.controller.state.state import State from openhands.core.config import ( AgentConfig, - AppConfig, + OpenHandsConfig, get_llm_config_arg, get_parser, ) @@ -135,7 +135,7 @@ def get_instance_docker_image(instance_id: str, official_image: bool = False) -> def get_config( instance: pd.Series, metadata: EvalMetadata, -) -> AppConfig: +) -> OpenHandsConfig: # We use a different instance image for the each instance of swe-bench eval use_official_image = bool( 'verified' in metadata.dataset.lower() or 'lite' in metadata.dataset.lower() @@ -160,7 +160,7 @@ def get_config( instance_id=instance['instance_id'], ) - config = AppConfig( + config = OpenHandsConfig( default_agent=metadata.agent_class, run_as_openhands=False, max_iterations=metadata.max_iterations, diff --git a/evaluation/benchmarks/visualwebarena/run_infer.py b/evaluation/benchmarks/visualwebarena/run_infer.py index bbd5515cb4..e88f76c1bd 100644 --- a/evaluation/benchmarks/visualwebarena/run_infer.py +++ b/evaluation/benchmarks/visualwebarena/run_infer.py @@ -20,7 +20,7 @@ from evaluation.utils.shared import ( ) from openhands.controller.state.state import State from openhands.core.config import ( - AppConfig, + OpenHandsConfig, get_llm_config_arg, parse_arguments, ) @@ -48,7 +48,7 @@ AGENT_CLS_TO_FAKE_USER_RESPONSE_FN = { def get_config( metadata: EvalMetadata, env_id: str, -) -> AppConfig: +) -> OpenHandsConfig: base_url = os.environ.get('VISUALWEBARENA_BASE_URL', None) openai_api_key = os.environ.get('OPENAI_API_KEY', None) openai_base_url = os.environ.get('OPENAI_BASE_URL', None) @@ -72,7 +72,7 @@ def get_config( 'VWA_WIKIPEDIA': f'{base_url}:8888', 'VWA_HOMEPAGE': f'{base_url}:4399', } - config = AppConfig( + config = OpenHandsConfig( default_agent=metadata.agent_class, run_as_openhands=False, runtime='docker', diff --git a/evaluation/benchmarks/webarena/run_infer.py b/evaluation/benchmarks/webarena/run_infer.py index d93a423343..f3df268fab 100644 --- a/evaluation/benchmarks/webarena/run_infer.py +++ b/evaluation/benchmarks/webarena/run_infer.py @@ -19,7 +19,7 @@ from evaluation.utils.shared import ( ) from openhands.controller.state.state import State from openhands.core.config import ( - AppConfig, + OpenHandsConfig, get_llm_config_arg, parse_arguments, ) @@ -44,7 +44,7 @@ SUPPORTED_AGENT_CLS = {'BrowsingAgent'} def get_config( metadata: EvalMetadata, env_id: str, -) -> AppConfig: +) -> OpenHandsConfig: base_url = os.environ.get('WEBARENA_BASE_URL', None) openai_api_key = os.environ.get('OPENAI_API_KEY', None) assert base_url is not None, 'WEBARENA_BASE_URL must be set' @@ -64,7 +64,7 @@ def get_config( 'MAP': f'{base_url}:3000', 'HOMEPAGE': f'{base_url}:4399', } - config = AppConfig( + config = OpenHandsConfig( default_agent=metadata.agent_class, run_as_openhands=False, runtime='docker', diff --git a/evaluation/integration_tests/run_infer.py b/evaluation/integration_tests/run_infer.py index 748b7d0489..845ef1c728 100644 --- a/evaluation/integration_tests/run_infer.py +++ b/evaluation/integration_tests/run_infer.py @@ -21,7 +21,7 @@ from evaluation.utils.shared import ( from openhands.controller.state.state import State from openhands.core.config import ( AgentConfig, - AppConfig, + OpenHandsConfig, get_llm_config_arg, parse_arguments, ) @@ -41,10 +41,10 @@ FAKE_RESPONSES = { def get_config( metadata: EvalMetadata, instance_id: str, -) -> AppConfig: +) -> OpenHandsConfig: sandbox_config = get_default_sandbox_config_for_eval() sandbox_config.platform = 'linux/amd64' - config = AppConfig( + config = OpenHandsConfig( default_agent=metadata.agent_class, run_as_openhands=False, runtime=os.environ.get('RUNTIME', 'docker'), diff --git a/evaluation/regression/run_tests.py b/evaluation/regression/run_tests.py index 1c0af98ffd..cf06c79fca 100644 --- a/evaluation/regression/run_tests.py +++ b/evaluation/regression/run_tests.py @@ -2,9 +2,9 @@ import argparse import pytest -from openhands.config import load_app_config +from openhands.config import load_openhands_config -config = load_app_config() +config = load_openhands_config() if __name__ == '__main__': """Main entry point of the script. diff --git a/openhands/cli/commands.py b/openhands/cli/commands.py index e9f6a4de25..8de3d5c750 100644 --- a/openhands/cli/commands.py +++ b/openhands/cli/commands.py @@ -25,7 +25,7 @@ from openhands.cli.utils import ( write_to_file, ) from openhands.core.config import ( - AppConfig, + OpenHandsConfig, ) from openhands.core.schema import AgentState from openhands.events import EventSource @@ -42,7 +42,7 @@ async def handle_commands( event_stream: EventStream, usage_metrics: UsageMetrics, sid: str, - config: AppConfig, + config: OpenHandsConfig, current_dir: str, settings_store: FileSettingsStore, ) -> tuple[bool, bool, bool]: @@ -105,7 +105,7 @@ def handle_help_command() -> None: async def handle_init_command( - config: AppConfig, event_stream: EventStream, current_dir: str + config: OpenHandsConfig, event_stream: EventStream, current_dir: str ) -> tuple[bool, bool]: REPO_MD_CREATE_PROMPT = """ Please explore this repository. Create the file .openhands/microagents/repo.md with: @@ -166,7 +166,7 @@ def handle_new_command( async def handle_settings_command( - config: AppConfig, + config: OpenHandsConfig, settings_store: FileSettingsStore, ) -> None: display_settings(config) @@ -264,7 +264,7 @@ async def init_repository(current_dir: str) -> bool: return init_repo -def check_folder_security_agreement(config: AppConfig, current_dir: str) -> bool: +def check_folder_security_agreement(config: OpenHandsConfig, current_dir: str) -> bool: # Directories trusted by user for the CLI to use as workspace # Config from ~/.openhands/config.toml overrides the app config diff --git a/openhands/cli/main.py b/openhands/cli/main.py index fea0e0ea2a..798c0ee0df 100644 --- a/openhands/cli/main.py +++ b/openhands/cli/main.py @@ -30,7 +30,7 @@ from openhands.cli.utils import ( from openhands.controller import AgentController from openhands.controller.agent import Agent from openhands.core.config import ( - AppConfig, + OpenHandsConfig, parse_arguments, setup_config_from_args, ) @@ -103,7 +103,7 @@ async def cleanup_session( async def run_session( loop: asyncio.AbstractEventLoop, - config: AppConfig, + config: OpenHandsConfig, settings_store: FileSettingsStore, current_dir: str, task_content: str | None = None, @@ -334,7 +334,7 @@ async def main(loop: asyncio.AbstractEventLoop) -> None: logger.setLevel(logging.WARNING) # Load config from toml and override with command line arguments - config: AppConfig = setup_config_from_args(args) + config: OpenHandsConfig = setup_config_from_args(args) # Load settings from Settings Store # TODO: Make this generic? diff --git a/openhands/cli/settings.py b/openhands/cli/settings.py index 4c067deec9..773460e8a7 100644 --- a/openhands/cli/settings.py +++ b/openhands/cli/settings.py @@ -18,7 +18,7 @@ from openhands.cli.utils import ( organize_models_and_providers, ) from openhands.controller.agent import Agent -from openhands.core.config import AppConfig +from openhands.core.config import OpenHandsConfig from openhands.core.config.condenser_config import NoOpCondenserConfig from openhands.core.config.utils import OH_DEFAULT_AGENT from openhands.memory.condenser.impl.llm_summarizing_condenser import ( @@ -29,7 +29,7 @@ from openhands.storage.settings.file_settings_store import FileSettingsStore from openhands.utils.llm import get_supported_llm_models -def display_settings(config: AppConfig) -> None: +def display_settings(config: OpenHandsConfig) -> None: llm_config = config.get_llm_config() advanced_llm_settings = True if llm_config.base_url else False @@ -145,7 +145,7 @@ def save_settings_confirmation() -> bool: async def modify_llm_settings_basic( - config: AppConfig, settings_store: FileSettingsStore + config: OpenHandsConfig, settings_store: FileSettingsStore ) -> None: model_list = get_supported_llm_models(config) organized_models = organize_models_and_providers(model_list) @@ -243,7 +243,7 @@ async def modify_llm_settings_basic( async def modify_llm_settings_advanced( - config: AppConfig, settings_store: FileSettingsStore + config: OpenHandsConfig, settings_store: FileSettingsStore ) -> None: session = PromptSession(key_bindings=kb_cancel()) diff --git a/openhands/cli/tui.py b/openhands/cli/tui.py index 33cb397b20..86c9ae2c08 100644 --- a/openhands/cli/tui.py +++ b/openhands/cli/tui.py @@ -27,7 +27,7 @@ from prompt_toolkit.styles import Style from prompt_toolkit.widgets import Frame, TextArea from openhands import __version__ -from openhands.core.config import AppConfig +from openhands.core.config import OpenHandsConfig from openhands.core.schema import AgentState from openhands.events import EventSource, EventStream from openhands.events.action import ( @@ -180,7 +180,7 @@ def display_initial_user_prompt(prompt: str) -> None: # Prompt output display functions -def display_event(event: Event, config: AppConfig) -> None: +def display_event(event: Event, config: OpenHandsConfig) -> None: global streaming_output_text_area with print_lock: if isinstance(event, Action): diff --git a/openhands/core/config/__init__.py b/openhands/core/config/__init__.py index c43bca2408..7af35781eb 100644 --- a/openhands/core/config/__init__.py +++ b/openhands/core/config/__init__.py @@ -1,5 +1,4 @@ from openhands.core.config.agent_config import AgentConfig -from openhands.core.config.app_config import AppConfig from openhands.core.config.config_utils import ( OH_DEFAULT_AGENT, OH_MAX_ITERATIONS, @@ -8,6 +7,7 @@ from openhands.core.config.config_utils import ( from openhands.core.config.extended_config import ExtendedConfig from openhands.core.config.llm_config import LLMConfig from openhands.core.config.mcp_config import MCPConfig +from openhands.core.config.openhands_config import OpenHandsConfig from openhands.core.config.sandbox_config import SandboxConfig from openhands.core.config.security_config import SecurityConfig from openhands.core.config.utils import ( @@ -15,9 +15,9 @@ from openhands.core.config.utils import ( get_agent_config_arg, get_llm_config_arg, get_parser, - load_app_config, load_from_env, load_from_toml, + load_openhands_config, parse_arguments, setup_config_from_args, ) @@ -26,13 +26,13 @@ __all__ = [ 'OH_DEFAULT_AGENT', 'OH_MAX_ITERATIONS', 'AgentConfig', - 'AppConfig', + 'OpenHandsConfig', 'MCPConfig', 'LLMConfig', 'SandboxConfig', 'SecurityConfig', 'ExtendedConfig', - 'load_app_config', + 'load_openhands_config', 'load_from_env', 'load_from_toml', 'finalize_config', diff --git a/openhands/core/config/mcp_config.py b/openhands/core/config/mcp_config.py index 9e286e5cac..e8f52800b2 100644 --- a/openhands/core/config/mcp_config.py +++ b/openhands/core/config/mcp_config.py @@ -1,10 +1,11 @@ import os -from urllib.parse import urlparse from typing import TYPE_CHECKING +from urllib.parse import urlparse + from pydantic import BaseModel, Field, ValidationError, model_validator if TYPE_CHECKING: - from openhands.core.config.app_config import AppConfig + from openhands.core.config.openhands_config import OpenHandsConfig from openhands.core.logger import openhands_logger as logger from openhands.utils.import_utils import get_impl @@ -147,7 +148,7 @@ class MCPConfig(BaseModel): class OpenHandsMCPConfig: @staticmethod - def add_search_engine(app_config: "AppConfig") -> MCPStdioServerConfig | None: + def add_search_engine(app_config: 'OpenHandsConfig') -> MCPStdioServerConfig | None: """Add search engine to the MCP config""" if ( app_config.search_api_key @@ -165,17 +166,16 @@ class OpenHandsMCPConfig: # Do not add search engine to MCP config in SaaS mode since it will be added by the OpenHands server return None - @staticmethod def create_default_mcp_server_config( - host: str, config: "AppConfig", user_id: str | None = None + host: str, config: 'OpenHandsConfig', user_id: str | None = None ) -> tuple[MCPSSEServerConfig, list[MCPStdioServerConfig]]: """ Create a default MCP server configuration. Args: host: Host string - config: AppConfig + config: OpenHandsConfig Returns: tuple[MCPSSEServerConfig, list[MCPStdioServerConfig]]: A tuple containing the default SSE server configuration and a list of MCP stdio server configurations """ diff --git a/openhands/core/config/app_config.py b/openhands/core/config/openhands_config.py similarity index 95% rename from openhands/core/config/app_config.py rename to openhands/core/config/openhands_config.py index 3cd8246572..d809135690 100644 --- a/openhands/core/config/app_config.py +++ b/openhands/core/config/openhands_config.py @@ -16,7 +16,7 @@ from openhands.core.config.sandbox_config import SandboxConfig from openhands.core.config.security_config import SecurityConfig -class AppConfig(BaseModel): +class OpenHandsConfig(BaseModel): """Configuration for the app. Attributes: @@ -65,7 +65,10 @@ class AppConfig(BaseModel): save_trajectory_path: str | None = Field(default=None) save_screenshots_in_trajectory: bool = Field(default=False) replay_trajectory_path: str | None = Field(default=None) - search_api_key: SecretStr | None = Field(default=None, description="API key for Tavily search engine (https://tavily.com/). Required for search functionality.") + search_api_key: SecretStr | None = Field( + default=None, + description='API key for Tavily search engine (https://tavily.com/). Required for search functionality.', + ) # Deprecated parameters - will be removed in a future version workspace_base: str | None = Field(default=None, deprecated=True) @@ -73,7 +76,7 @@ class AppConfig(BaseModel): workspace_mount_path_in_sandbox: str = Field(default='/workspace', deprecated=True) workspace_mount_rewrite: str | None = Field(default=None, deprecated=True) # End of deprecated parameters - + cache_dir: str = Field(default='/tmp/cache') run_as_openhands: bool = Field(default=True) max_iterations: int = Field(default=OH_MAX_ITERATIONS) @@ -148,5 +151,5 @@ class AppConfig(BaseModel): """Post-initialization hook, called when the instance is created with only default values.""" super().model_post_init(__context) - if not AppConfig.defaults_dict: # Only set defaults_dict if it's empty - AppConfig.defaults_dict = model_defaults_to_dict(self) + if not OpenHandsConfig.defaults_dict: # Only set defaults_dict if it's empty + OpenHandsConfig.defaults_dict = model_defaults_to_dict(self) diff --git a/openhands/core/config/utils.py b/openhands/core/config/utils.py index 49d317f6c0..b63f9063a6 100644 --- a/openhands/core/config/utils.py +++ b/openhands/core/config/utils.py @@ -15,7 +15,6 @@ from pydantic import BaseModel, SecretStr, ValidationError from openhands import __version__ from openhands.core import logger from openhands.core.config.agent_config import AgentConfig -from openhands.core.config.app_config import AppConfig from openhands.core.config.condenser_config import ( CondenserConfig, condenser_config_from_toml_section, @@ -28,6 +27,7 @@ from openhands.core.config.config_utils import ( from openhands.core.config.extended_config import ExtendedConfig from openhands.core.config.llm_config import LLMConfig from openhands.core.config.mcp_config import MCPConfig +from openhands.core.config.openhands_config import OpenHandsConfig from openhands.core.config.sandbox_config import SandboxConfig from openhands.core.config.security_config import SecurityConfig from openhands.storage import get_file_store @@ -39,7 +39,7 @@ load_dotenv() def load_from_env( - cfg: AppConfig, env_or_toml_dict: dict | MutableMapping[str, str] + cfg: OpenHandsConfig, env_or_toml_dict: dict | MutableMapping[str, str] ) -> None: """Sets config attributes from environment variables or TOML dictionary. @@ -48,7 +48,7 @@ def load_from_env( (e.g., AGENT_MEMORY_ENABLED), sandbox settings (e.g., SANDBOX_TIMEOUT), and more. Args: - cfg: The AppConfig object to set attributes on. + cfg: The OpenHandsConfig object to set attributes on. env_or_toml_dict: The environment variables or a config.toml dict. """ @@ -121,11 +121,11 @@ def load_from_env( set_attr_from_env(default_agent_config, 'AGENT_') -def load_from_toml(cfg: AppConfig, toml_file: str = 'config.toml') -> None: +def load_from_toml(cfg: OpenHandsConfig, toml_file: str = 'config.toml') -> None: """Load the config from the toml file. Supports both styles of config vars. Args: - cfg: The AppConfig object to update attributes of. + cfg: The OpenHandsConfig object to update attributes of. toml_file: The path to the toml file. Defaults to 'config.toml'. See Also: @@ -302,7 +302,7 @@ def get_or_create_jwt_secret(file_store: FileStore) -> str: return new_secret -def finalize_config(cfg: AppConfig) -> None: +def finalize_config(cfg: OpenHandsConfig) -> None: """More tweaks to the config after it's been loaded.""" # Handle the sandbox.volumes parameter if cfg.workspace_base is not None or cfg.workspace_mount_path is not None: @@ -759,7 +759,7 @@ def parse_arguments() -> argparse.Namespace: return args -def register_custom_agents(config: AppConfig) -> None: +def register_custom_agents(config: OpenHandsConfig) -> None: """Register custom agents from configuration. This function is called after configuration is loaded to ensure all custom agents @@ -782,16 +782,16 @@ def register_custom_agents(config: AppConfig) -> None: ) -def load_app_config( +def load_openhands_config( set_logging_levels: bool = True, config_file: str = 'config.toml' -) -> AppConfig: +) -> OpenHandsConfig: """Load the configuration from the specified config file and environment variables. Args: set_logging_levels: Whether to set the global variables for logging levels. config_file: Path to the config file. Defaults to 'config.toml' in the current directory. """ - config = AppConfig() + config = OpenHandsConfig() load_from_toml(config, config_file) load_from_env(config, os.environ) finalize_config(config) @@ -802,13 +802,13 @@ def load_app_config( return config -def setup_config_from_args(args: argparse.Namespace) -> AppConfig: +def setup_config_from_args(args: argparse.Namespace) -> OpenHandsConfig: """Load config from toml and override with command line arguments. Common setup used by both CLI and main.py entry points. """ # Load base config from toml and env vars - config = load_app_config(config_file=args.config_file) + config = load_openhands_config(config_file=args.config_file) # Override with command line arguments if provided if args.llm_config: diff --git a/openhands/core/main.py b/openhands/core/main.py index 9703867cbd..8303cfebc3 100644 --- a/openhands/core/main.py +++ b/openhands/core/main.py @@ -9,7 +9,7 @@ from openhands.controller.agent import Agent from openhands.controller.replay import ReplayManager from openhands.controller.state.state import State from openhands.core.config import ( - AppConfig, + OpenHandsConfig, parse_arguments, setup_config_from_args, ) @@ -47,7 +47,7 @@ class FakeUserResponseFunc(Protocol): async def run_controller( - config: AppConfig, + config: OpenHandsConfig, initial_user_action: Action, sid: str | None = None, runtime: Runtime | None = None, @@ -90,7 +90,7 @@ async def run_controller( config.max_budget_per_task. Example: - >>> config = load_app_config() + >>> config = load_openhands_config() >>> action = MessageAction(content="Write a hello world program") >>> state = await run_controller(config=config, initial_user_action=action) """ @@ -279,7 +279,7 @@ def load_replay_log(trajectory_path: str) -> tuple[list[Event] | None, Action]: if __name__ == '__main__': args = parse_arguments() - config: AppConfig = setup_config_from_args(args) + config: OpenHandsConfig = setup_config_from_args(args) # Read task from file, CLI args, or stdin task_str = read_task(args, config.cli_multiline_input) diff --git a/openhands/core/setup.py b/openhands/core/setup.py index be54a9b093..8a7793a7d7 100644 --- a/openhands/core/setup.py +++ b/openhands/core/setup.py @@ -10,7 +10,7 @@ from openhands.controller import AgentController from openhands.controller.agent import Agent from openhands.controller.state.state import State from openhands.core.config import ( - AppConfig, + OpenHandsConfig, ) from openhands.core.logger import openhands_logger as logger from openhands.events import EventStream @@ -28,7 +28,7 @@ from openhands.utils.async_utils import GENERAL_TIMEOUT, call_async_from_sync def create_runtime( - config: AppConfig, + config: OpenHandsConfig, sid: str | None = None, headless_mode: bool = True, agent: Agent | None = None, @@ -172,7 +172,7 @@ def create_memory( return memory -def create_agent(config: AppConfig) -> Agent: +def create_agent(config: OpenHandsConfig) -> Agent: agent_cls: type[Agent] = Agent.get_cls(config.default_agent) agent_config = config.get_agent_config(config.default_agent) llm_config = config.get_llm_config_from_agent(config.default_agent) @@ -188,7 +188,7 @@ def create_agent(config: AppConfig) -> Agent: def create_controller( agent: Agent, runtime: Runtime, - config: AppConfig, + config: OpenHandsConfig, headless_mode: bool = True, replay_events: list[Event] | None = None, ) -> tuple[AgentController, State | None]: @@ -218,7 +218,7 @@ def create_controller( return (controller, initial_state) -def generate_sid(config: AppConfig, session_name: str | None = None) -> str: +def generate_sid(config: OpenHandsConfig, session_name: str | None = None) -> str: """Generate a session id based on the session name and the jwt secret.""" session_name = session_name or str(uuid.uuid4()) jwt_secret = config.jwt_secret diff --git a/openhands/mcp/utils.py b/openhands/mcp/utils.py index 212ccaef8e..9beb19bc49 100644 --- a/openhands/mcp/utils.py +++ b/openhands/mcp/utils.py @@ -4,11 +4,11 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: from openhands.controller.agent import Agent -from openhands.core.config.app_config import AppConfig from openhands.core.config.mcp_config import ( MCPConfig, MCPSSEServerConfig, ) +from openhands.core.config.openhands_config import OpenHandsConfig from openhands.core.logger import openhands_logger as logger from openhands.events.action.mcp import MCPAction from openhands.events.observation.mcp import MCPObservation @@ -162,7 +162,7 @@ async def call_tool_mcp(mcp_clients: list[MCPClient], action: MCPAction) -> Obse async def add_mcp_tools_to_agent( - agent: 'Agent', runtime: Runtime, memory: 'Memory', app_config: AppConfig + agent: 'Agent', runtime: Runtime, memory: 'Memory', app_config: OpenHandsConfig ): """ Add MCP tools to an agent. diff --git a/openhands/resolver/issue_resolver.py b/openhands/resolver/issue_resolver.py index 9c6d085f18..1f79d50759 100644 --- a/openhands/resolver/issue_resolver.py +++ b/openhands/resolver/issue_resolver.py @@ -16,7 +16,7 @@ from termcolor import colored import openhands from openhands.controller.state.state import State -from openhands.core.config import AgentConfig, AppConfig, LLMConfig, SandboxConfig +from openhands.core.config import AgentConfig, LLMConfig, OpenHandsConfig, SandboxConfig from openhands.core.logger import openhands_logger as logger from openhands.core.main import create_runtime, run_controller from openhands.events.action import CmdRunAction, MessageAction @@ -377,7 +377,7 @@ class IssueResolver: shutil.rmtree(workspace_base) shutil.copytree(os.path.join(self.output_dir, 'repo'), workspace_base) - config = AppConfig( + config = OpenHandsConfig( default_agent='CodeActAgent', runtime='docker', max_budget_per_task=4, diff --git a/openhands/runtime/base.py b/openhands/runtime/base.py index 92a3a707a8..70135cacd3 100644 --- a/openhands/runtime/base.py +++ b/openhands/runtime/base.py @@ -15,7 +15,7 @@ from zipfile import ZipFile import httpx -from openhands.core.config import AppConfig, SandboxConfig +from openhands.core.config import OpenHandsConfig, SandboxConfig from openhands.core.config.mcp_config import MCPConfig, MCPStdioServerConfig from openhands.core.exceptions import AgentRuntimeDisconnectedError from openhands.core.logger import openhands_logger as logger @@ -97,7 +97,7 @@ class Runtime(FileEditRuntimeMixin): """ sid: str - config: AppConfig + config: OpenHandsConfig initial_env_vars: dict[str, str] attach_to_existing: bool status_callback: Callable[[str, str, str], None] | None @@ -105,7 +105,7 @@ class Runtime(FileEditRuntimeMixin): def __init__( self, - config: AppConfig, + config: OpenHandsConfig, event_stream: EventStream, sid: str = 'default', plugins: list[PluginRequirement] | None = None, diff --git a/openhands/runtime/impl/action_execution/action_execution_client.py b/openhands/runtime/impl/action_execution/action_execution_client.py index abb2382158..159d02e985 100644 --- a/openhands/runtime/impl/action_execution/action_execution_client.py +++ b/openhands/runtime/impl/action_execution/action_execution_client.py @@ -9,7 +9,7 @@ import httpcore import httpx from tenacity import retry, retry_if_exception, stop_after_attempt, wait_exponential -from openhands.core.config import AppConfig +from openhands.core.config import OpenHandsConfig from openhands.core.config.mcp_config import ( MCPConfig, MCPSSEServerConfig, @@ -65,7 +65,7 @@ class ActionExecutionClient(Runtime): def __init__( self, - config: AppConfig, + config: OpenHandsConfig, event_stream: EventStream, sid: str = 'default', plugins: list[PluginRequirement] | None = None, @@ -409,7 +409,7 @@ class ActionExecutionClient(Runtime): 'warning', f'Some MCP servers failed to be added: {result["router_error_log"]}', ) - + # Update our cached list with combined servers after successful update self._last_updated_mcp_stdio_servers = combined_servers.copy() self.log( diff --git a/openhands/runtime/impl/cli/cli_runtime.py b/openhands/runtime/impl/cli/cli_runtime.py index 3f6ed4e36e..c2d45028f6 100644 --- a/openhands/runtime/impl/cli/cli_runtime.py +++ b/openhands/runtime/impl/cli/cli_runtime.py @@ -22,7 +22,7 @@ from openhands_aci.editor.results import ToolResult from openhands_aci.utils.diff import get_diff from pydantic import SecretStr -from openhands.core.config import AppConfig +from openhands.core.config import OpenHandsConfig from openhands.core.config.mcp_config import MCPConfig, MCPStdioServerConfig from openhands.core.exceptions import LLMMalformedActionError from openhands.core.logger import openhands_logger as logger @@ -57,7 +57,7 @@ class CLIRuntime(Runtime): file operations using Python's standard library. It does not implement browser functionality. Args: - config (AppConfig): The application configuration. + config (OpenHandsConfig): The application configuration. event_stream (EventStream): The event stream to subscribe to. sid (str, optional): The session ID. Defaults to 'default'. plugins (list[PluginRequirement] | None, optional): List of plugin requirements. Defaults to None. @@ -71,7 +71,7 @@ class CLIRuntime(Runtime): def __init__( self, - config: AppConfig, + config: OpenHandsConfig, event_stream: EventStream, sid: str = 'default', plugins: list[PluginRequirement] | None = None, diff --git a/openhands/runtime/impl/daytona/daytona_runtime.py b/openhands/runtime/impl/daytona/daytona_runtime.py index 95730c82b4..6507a89098 100644 --- a/openhands/runtime/impl/daytona/daytona_runtime.py +++ b/openhands/runtime/impl/daytona/daytona_runtime.py @@ -11,7 +11,7 @@ from daytona_sdk import ( Workspace, ) -from openhands.core.config.app_config import AppConfig +from openhands.core.config.openhands_config import OpenHandsConfig from openhands.events.stream import EventStream from openhands.runtime.impl.action_execution.action_execution_client import ( ActionExecutionClient, @@ -33,7 +33,7 @@ class DaytonaRuntime(ActionExecutionClient): def __init__( self, - config: AppConfig, + config: OpenHandsConfig, event_stream: EventStream, sid: str = 'default', plugins: list[PluginRequirement] | None = None, diff --git a/openhands/runtime/impl/docker/docker_runtime.py b/openhands/runtime/impl/docker/docker_runtime.py index e783004e4b..233809d5a4 100644 --- a/openhands/runtime/impl/docker/docker_runtime.py +++ b/openhands/runtime/impl/docker/docker_runtime.py @@ -8,7 +8,7 @@ import httpx import tenacity from docker.models.containers import Container -from openhands.core.config import AppConfig +from openhands.core.config import OpenHandsConfig from openhands.core.exceptions import ( AgentRuntimeDisconnectedError, AgentRuntimeNotFoundError, @@ -23,7 +23,10 @@ from openhands.runtime.impl.action_execution.action_execution_client import ( from openhands.runtime.impl.docker.containers import stop_all_containers from openhands.runtime.plugins import PluginRequirement from openhands.runtime.utils import find_available_tcp_port -from openhands.runtime.utils.command import DEFAULT_MAIN_MODULE, get_action_execution_server_startup_command +from openhands.runtime.utils.command import ( + DEFAULT_MAIN_MODULE, + get_action_execution_server_startup_command, +) from openhands.runtime.utils.log_streamer import LogStreamer from openhands.runtime.utils.runtime_build import build_runtime_image from openhands.utils.async_utils import call_sync_from_async @@ -62,7 +65,7 @@ class DockerRuntime(ActionExecutionClient): When receive an event, it will send the event to runtime-client which run inside the docker environment. Args: - config (AppConfig): The application configuration. + config (OpenHandsConfig): The application configuration. event_stream (EventStream): The event stream to subscribe to. sid (str, optional): The session ID. Defaults to 'default'. plugins (list[PluginRequirement] | None, optional): List of plugin requirements. Defaults to None. @@ -73,7 +76,7 @@ class DockerRuntime(ActionExecutionClient): def __init__( self, - config: AppConfig, + config: OpenHandsConfig, event_stream: EventStream, sid: str = 'default', plugins: list[PluginRequirement] | None = None, diff --git a/openhands/runtime/impl/e2b/e2b_runtime.py b/openhands/runtime/impl/e2b/e2b_runtime.py index b54f833e36..2cf20f3ff9 100644 --- a/openhands/runtime/impl/e2b/e2b_runtime.py +++ b/openhands/runtime/impl/e2b/e2b_runtime.py @@ -1,6 +1,6 @@ from typing import Callable -from openhands.core.config import AppConfig +from openhands.core.config import OpenHandsConfig from openhands.events.action import ( FileReadAction, FileWriteAction, @@ -22,7 +22,7 @@ from openhands.runtime.utils.files import insert_lines, read_lines class E2BRuntime(Runtime): def __init__( self, - config: AppConfig, + config: OpenHandsConfig, event_stream: EventStream, sid: str = 'default', plugins: list[PluginRequirement] | None = None, diff --git a/openhands/runtime/impl/local/local_runtime.py b/openhands/runtime/impl/local/local_runtime.py index 97174869d3..a03ef6da07 100644 --- a/openhands/runtime/impl/local/local_runtime.py +++ b/openhands/runtime/impl/local/local_runtime.py @@ -12,7 +12,7 @@ import httpx import tenacity import openhands -from openhands.core.config import AppConfig +from openhands.core.config import OpenHandsConfig from openhands.core.exceptions import AgentRuntimeDisconnectedError from openhands.core.logger import openhands_logger as logger from openhands.events import EventStream @@ -107,7 +107,7 @@ class LocalRuntime(ActionExecutionClient): When receiving an event, it will send the event to the server via HTTP. Args: - config (AppConfig): The application configuration. + config (OpenHandsConfig): The application configuration. event_stream (EventStream): The event stream to subscribe to. sid (str, optional): The session ID. Defaults to 'default'. plugins (list[PluginRequirement] | None, optional): list of plugin requirements. Defaults to None. @@ -116,7 +116,7 @@ class LocalRuntime(ActionExecutionClient): def __init__( self, - config: AppConfig, + config: OpenHandsConfig, event_stream: EventStream, sid: str = 'default', plugins: list[PluginRequirement] | None = None, diff --git a/openhands/runtime/impl/modal/modal_runtime.py b/openhands/runtime/impl/modal/modal_runtime.py index 9bbff143df..c37e28dd30 100644 --- a/openhands/runtime/impl/modal/modal_runtime.py +++ b/openhands/runtime/impl/modal/modal_runtime.py @@ -7,7 +7,7 @@ import httpx import modal import tenacity -from openhands.core.config import AppConfig +from openhands.core.config import OpenHandsConfig from openhands.events import EventStream from openhands.runtime.impl.action_execution.action_execution_client import ( ActionExecutionClient, @@ -31,7 +31,7 @@ class ModalRuntime(ActionExecutionClient): When receive an event, it will send the event to runtime-client which run inside the Modal sandbox environment. Args: - config (AppConfig): The application configuration. + config (OpenHandsConfig): The application configuration. event_stream (EventStream): The event stream to subscribe to. sid (str, optional): The session ID. Defaults to 'default'. plugins (list[PluginRequirement] | None, optional): List of plugin requirements. Defaults to None. @@ -44,7 +44,7 @@ class ModalRuntime(ActionExecutionClient): def __init__( self, - config: AppConfig, + config: OpenHandsConfig, event_stream: EventStream, sid: str = 'default', plugins: list[PluginRequirement] | None = None, diff --git a/openhands/runtime/impl/remote/remote_runtime.py b/openhands/runtime/impl/remote/remote_runtime.py index bd0d252505..dc269124c2 100644 --- a/openhands/runtime/impl/remote/remote_runtime.py +++ b/openhands/runtime/impl/remote/remote_runtime.py @@ -8,7 +8,7 @@ import httpx import tenacity from tenacity import RetryCallState -from openhands.core.config import AppConfig +from openhands.core.config import OpenHandsConfig from openhands.core.exceptions import ( AgentRuntimeDisconnectedError, AgentRuntimeError, @@ -24,7 +24,10 @@ from openhands.runtime.impl.action_execution.action_execution_client import ( ActionExecutionClient, ) from openhands.runtime.plugins import PluginRequirement -from openhands.runtime.utils.command import DEFAULT_MAIN_MODULE, get_action_execution_server_startup_command +from openhands.runtime.utils.command import ( + DEFAULT_MAIN_MODULE, + get_action_execution_server_startup_command, +) from openhands.runtime.utils.request import send_request from openhands.runtime.utils.runtime_build import build_runtime_image from openhands.utils.async_utils import call_sync_from_async @@ -45,7 +48,7 @@ class RemoteRuntime(ActionExecutionClient): def __init__( self, - config: AppConfig, + config: OpenHandsConfig, event_stream: EventStream, sid: str = 'default', plugins: list[PluginRequirement] | None = None, diff --git a/openhands/runtime/impl/runloop/runloop_runtime.py b/openhands/runtime/impl/runloop/runloop_runtime.py index 104d747668..5d057caf4a 100644 --- a/openhands/runtime/impl/runloop/runloop_runtime.py +++ b/openhands/runtime/impl/runloop/runloop_runtime.py @@ -6,7 +6,7 @@ from runloop_api_client import Runloop from runloop_api_client.types import DevboxView from runloop_api_client.types.shared_params import LaunchParameters -from openhands.core.config import AppConfig +from openhands.core.config import OpenHandsConfig from openhands.core.logger import openhands_logger as logger from openhands.events import EventStream from openhands.runtime.impl.action_execution.action_execution_client import ( @@ -27,7 +27,7 @@ class RunloopRuntime(ActionExecutionClient): def __init__( self, - config: AppConfig, + config: OpenHandsConfig, event_stream: EventStream, sid: str = 'default', plugins: list[PluginRequirement] | None = None, diff --git a/openhands/runtime/utils/command.py b/openhands/runtime/utils/command.py index 66787b2e28..150ace2248 100644 --- a/openhands/runtime/utils/command.py +++ b/openhands/runtime/utils/command.py @@ -1,4 +1,4 @@ -from openhands.core.config import AppConfig +from openhands.core.config import OpenHandsConfig from openhands.runtime.plugins import PluginRequirement DEFAULT_PYTHON_PREFIX = [ @@ -15,7 +15,7 @@ DEFAULT_MAIN_MODULE = 'openhands.runtime.action_execution_server' def get_action_execution_server_startup_command( server_port: int, plugins: list[PluginRequirement], - app_config: AppConfig, + app_config: OpenHandsConfig, python_prefix: list[str] = DEFAULT_PYTHON_PREFIX, override_user_id: int | None = None, override_username: str | None = None, diff --git a/openhands/runtime/utils/edit.py b/openhands/runtime/utils/edit.py index bdd11bc5fa..47d5a6f5ef 100644 --- a/openhands/runtime/utils/edit.py +++ b/openhands/runtime/utils/edit.py @@ -6,7 +6,7 @@ from typing import Any from openhands_aci.utils.diff import get_diff -from openhands.core.config import AppConfig +from openhands.core.config import OpenHandsConfig from openhands.core.logger import openhands_logger as logger from openhands.events.action import ( FileEditAction, @@ -83,7 +83,7 @@ def get_new_file_contents( class FileEditRuntimeInterface(ABC): - config: AppConfig + config: OpenHandsConfig @abstractmethod def read(self, action: FileReadAction) -> Observation: diff --git a/openhands/server/conversation_manager/conversation_manager.py b/openhands/server/conversation_manager/conversation_manager.py index e039e72bb1..8766f06767 100644 --- a/openhands/server/conversation_manager/conversation_manager.py +++ b/openhands/server/conversation_manager/conversation_manager.py @@ -4,14 +4,12 @@ from abc import ABC, abstractmethod import socketio -from openhands.core.config import AppConfig +from openhands.core.config import OpenHandsConfig from openhands.events.action import MessageAction -from openhands.events.event_store import EventStore from openhands.server.config.server_config import ServerConfig from openhands.server.data_models.agent_loop_info import AgentLoopInfo -from openhands.server.data_models.conversation_info import ConversationInfo from openhands.server.monitoring import MonitoringListener -from openhands.server.session.conversation import Conversation +from openhands.server.session.conversation import ServerConversation from openhands.storage.conversation.conversation_store import ConversationStore from openhands.storage.data_models.settings import Settings from openhands.storage.files import FileStore @@ -26,7 +24,7 @@ class ConversationManager(ABC): """ sio: socketio.AsyncServer - config: AppConfig + config: OpenHandsConfig file_store: FileStore conversation_store: ConversationStore @@ -41,11 +39,11 @@ class ConversationManager(ABC): @abstractmethod async def attach_to_conversation( self, sid: str, user_id: str | None = None - ) -> Conversation | None: + ) -> ServerConversation | None: """Attach to an existing conversation or create a new one.""" @abstractmethod - async def detach_from_conversation(self, conversation: Conversation): + async def detach_from_conversation(self, conversation: ServerConversation): """Detach from a conversation.""" @abstractmethod @@ -109,7 +107,7 @@ class ConversationManager(ABC): def get_instance( cls, sio: socketio.AsyncServer, - config: AppConfig, + config: OpenHandsConfig, file_store: FileStore, server_config: ServerConfig, monitoring_listener: MonitoringListener, diff --git a/openhands/server/conversation_manager/docker_nested_conversation_manager.py b/openhands/server/conversation_manager/docker_nested_conversation_manager.py index f60dc7310a..5156c6209a 100644 --- a/openhands/server/conversation_manager/docker_nested_conversation_manager.py +++ b/openhands/server/conversation_manager/docker_nested_conversation_manager.py @@ -15,7 +15,7 @@ from docker.models.containers import Container from fastapi import status from openhands.controller.agent import Agent -from openhands.core.config import AppConfig +from openhands.core.config import OpenHandsConfig from openhands.core.logger import openhands_logger as logger from openhands.events.action import MessageAction from openhands.events.nested_event_store import NestedEventStore @@ -30,7 +30,7 @@ from openhands.server.conversation_manager.conversation_manager import ( ) from openhands.server.data_models.agent_loop_info import AgentLoopInfo from openhands.server.monitoring import MonitoringListener -from openhands.server.session.conversation import Conversation +from openhands.server.session.conversation import ServerConversation from openhands.server.session.conversation_init_data import ConversationInitData from openhands.server.session.session import ROOM_KEY, Session from openhands.storage.conversation.conversation_store import ConversationStore @@ -45,10 +45,10 @@ from openhands.utils.import_utils import get_impl @dataclass class DockerNestedConversationManager(ConversationManager): - """Conversation manager where the agent loops exist inside the docker containers.""" + """ServerConversation manager where the agent loops exist inside the docker containers.""" sio: socketio.AsyncServer - config: AppConfig + config: OpenHandsConfig server_config: ServerConfig file_store: FileStore docker_client: docker.DockerClient = field(default_factory=docker.from_env) @@ -65,11 +65,11 @@ class DockerNestedConversationManager(ConversationManager): async def attach_to_conversation( self, sid: str, user_id: str | None = None - ) -> Conversation | None: + ) -> ServerConversation | None: # Not supported - clients should connect directly to the nested server! raise ValueError('unsupported_operation') - async def detach_from_conversation(self, conversation: Conversation): + async def detach_from_conversation(self, conversation: ServerConversation): # Not supported - clients should connect directly to the nested server! raise ValueError('unsupported_operation') @@ -309,7 +309,7 @@ class DockerNestedConversationManager(ConversationManager): def get_instance( cls, sio: socketio.AsyncServer, - config: AppConfig, + config: OpenHandsConfig, file_store: FileStore, server_config: ServerConfig, monitoring_listener: MonitoringListener, @@ -433,7 +433,7 @@ class DockerNestedConversationManager(ConversationManager): volumes = [v.strip() for v in config.sandbox.volumes.split(',')] conversation_dir = get_conversation_dir(sid, user_id) volumes.append( - f'{config.file_store_path}/{conversation_dir}:{AppConfig.model_fields["file_store_path"].default}/{conversation_dir}:rw' + f'{config.file_store_path}/{conversation_dir}:{OpenHandsConfig.model_fields["file_store_path"].default}/{conversation_dir}:rw' ) config.sandbox.volumes = ','.join(volumes) diff --git a/openhands/server/conversation_manager/standalone_conversation_manager.py b/openhands/server/conversation_manager/standalone_conversation_manager.py index 176ac1c71c..838ce7a2cc 100644 --- a/openhands/server/conversation_manager/standalone_conversation_manager.py +++ b/openhands/server/conversation_manager/standalone_conversation_manager.py @@ -6,7 +6,7 @@ from typing import Callable, Iterable import socketio -from openhands.core.config.app_config import AppConfig +from openhands.core.config.openhands_config import OpenHandsConfig from openhands.core.exceptions import AgentRuntimeUnavailableError from openhands.core.logger import openhands_logger as logger from openhands.core.schema.agent import AgentState @@ -16,7 +16,7 @@ from openhands.server.config.server_config import ServerConfig from openhands.server.data_models.agent_loop_info import AgentLoopInfo from openhands.server.monitoring import MonitoringListener from openhands.server.session.agent_session import WAIT_TIME_BEFORE_CLOSE -from openhands.server.session.conversation import Conversation +from openhands.server.session.conversation import ServerConversation from openhands.server.session.session import ROOM_KEY, Session from openhands.storage.conversation.conversation_store import ConversationStore from openhands.storage.data_models.conversation_metadata import ConversationMetadata @@ -41,17 +41,17 @@ class StandaloneConversationManager(ConversationManager): """Manages conversations in standalone mode (single server instance).""" sio: socketio.AsyncServer - config: AppConfig + config: OpenHandsConfig file_store: FileStore server_config: ServerConfig # Defaulting monitoring_listener for temp backward compatibility. monitoring_listener: MonitoringListener = MonitoringListener() _local_agent_loops_by_sid: dict[str, Session] = field(default_factory=dict) _local_connection_id_to_session_id: dict[str, str] = field(default_factory=dict) - _active_conversations: dict[str, tuple[Conversation, int]] = field( + _active_conversations: dict[str, tuple[ServerConversation, int]] = field( default_factory=dict ) - _detached_conversations: dict[str, tuple[Conversation, float]] = field( + _detached_conversations: dict[str, tuple[ServerConversation, float]] = field( default_factory=dict ) _conversations_lock: asyncio.Lock = field(default_factory=asyncio.Lock) @@ -69,7 +69,7 @@ class StandaloneConversationManager(ConversationManager): async def attach_to_conversation( self, sid: str, user_id: str | None = None - ) -> Conversation | None: + ) -> ServerConversation | None: start_time = time.time() if not await session_exists(sid, self.file_store, user_id=user_id): return None @@ -94,7 +94,7 @@ class StandaloneConversationManager(ConversationManager): return conversation # Create new conversation if none exists - c = Conversation( + c = ServerConversation( sid, file_store=self.file_store, config=self.config, user_id=user_id ) try: @@ -108,7 +108,7 @@ class StandaloneConversationManager(ConversationManager): return None end_time = time.time() logger.info( - f'Conversation {c.sid} connected in {end_time - start_time} seconds' + f'ServerConversation {c.sid} connected in {end_time - start_time} seconds' ) self._active_conversations[sid] = (c, 1) return c @@ -129,7 +129,7 @@ class StandaloneConversationManager(ConversationManager): agent_loop_info = await self.maybe_start_agent_loop(sid, settings, user_id) return agent_loop_info - async def detach_from_conversation(self, conversation: Conversation): + async def detach_from_conversation(self, conversation: ServerConversation): sid = conversation.sid async with self._conversations_lock: if sid in self._active_conversations: @@ -377,7 +377,7 @@ class StandaloneConversationManager(ConversationManager): def get_instance( cls, sio: socketio.AsyncServer, - config: AppConfig, + config: OpenHandsConfig, file_store: FileStore, server_config: ServerConfig, monitoring_listener: MonitoringListener | None, @@ -475,7 +475,7 @@ class StandaloneConversationManager(ConversationManager): continue results.append(self._agent_loop_info_from_session(session)) return results - + def _agent_loop_info_from_session(self, session: Session): return AgentLoopInfo( conversation_id=session.sid, @@ -485,7 +485,7 @@ class StandaloneConversationManager(ConversationManager): ) def _get_conversation_url(self, conversation_id: str): - return f"/api/conversations/{conversation_id}" + return f'/api/conversations/{conversation_id}' def _last_updated_at_key(conversation: ConversationMetadata) -> float: diff --git a/openhands/server/file_config.py b/openhands/server/file_config.py index 4c59e7f366..ab1eec5104 100644 --- a/openhands/server/file_config.py +++ b/openhands/server/file_config.py @@ -1,7 +1,7 @@ import os import re -from openhands.core.config import AppConfig +from openhands.core.config import OpenHandsConfig from openhands.core.logger import openhands_logger as logger from openhands.server.shared import config as shared_config @@ -30,7 +30,7 @@ def sanitize_filename(filename: str) -> str: def load_file_upload_config( - config: AppConfig = shared_config, + config: OpenHandsConfig = shared_config, ) -> tuple[int, bool, list[str]]: """Load file upload configuration from the config object. diff --git a/openhands/server/monitoring.py b/openhands/server/monitoring.py index e5c4462880..872eb9ae8d 100644 --- a/openhands/server/monitoring.py +++ b/openhands/server/monitoring.py @@ -1,4 +1,4 @@ -from openhands.core.config.app_config import AppConfig +from openhands.core.config.openhands_config import OpenHandsConfig from openhands.events.event import Event @@ -33,6 +33,6 @@ class MonitoringListener: @classmethod def get_instance( cls, - config: AppConfig, + config: OpenHandsConfig, ) -> 'MonitoringListener': return cls() diff --git a/openhands/server/routes/conversation.py b/openhands/server/routes/conversation.py index 94831d6eac..a3ffb12be9 100644 --- a/openhands/server/routes/conversation.py +++ b/openhands/server/routes/conversation.py @@ -103,7 +103,7 @@ async def search_events( end_id: int | None = None, reverse: bool = False, filter: EventFilter | None = None, - limit: int = 20 + limit: int = 20, ): """Search through the event stream with filtering and pagination. Args: @@ -123,22 +123,24 @@ async def search_events( """ if not request.state.conversation: raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, detail='Conversation not found' + status_code=status.HTTP_404_NOT_FOUND, detail='ServerConversation not found' ) if limit < 0 or limit > 100: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail='Invalid limit' ) - + # Get matching events from the stream event_stream = request.state.conversation.event_stream - events = list(event_stream.search_events( - start_id=start_id, - end_id=end_id, - reverse=reverse, - filter=filter, - limit=limit + 1, - )) + events = list( + event_stream.search_events( + start_id=start_id, + end_id=end_id, + reverse=reverse, + filter=filter, + limit=limit + 1, + ) + ) # Check if there are more events has_more = len(events) > limit @@ -156,4 +158,4 @@ async def search_events( async def add_event(request: Request): data = request.json() conversation_manager.send_to_event_stream(request.state.sid, data) - return JSONResponse({"success": True}) + return JSONResponse({'success': True}) diff --git a/openhands/server/routes/mcp.py b/openhands/server/routes/mcp.py index 4e3c81791e..5454b6bd2b 100644 --- a/openhands/server/routes/mcp.py +++ b/openhands/server/routes/mcp.py @@ -1,27 +1,36 @@ import re from typing import Annotated -from pydantic import Field + from fastmcp import FastMCP from fastmcp.server.dependencies import get_http_request +from pydantic import Field + +from openhands.core.logger import openhands_logger as logger from openhands.integrations.github.github_service import GithubServiceImpl from openhands.integrations.gitlab.gitlab_service import GitLabServiceImpl from openhands.integrations.provider import ProviderToken from openhands.integrations.service_types import ProviderType from openhands.server.shared import ConversationStoreImpl, config -from openhands.server.user_auth import get_access_token, get_provider_tokens, get_user_id -from openhands.core.logger import openhands_logger as logger +from openhands.server.user_auth import ( + get_access_token, + get_provider_tokens, + get_user_id, +) from openhands.storage.data_models.conversation_metadata import ConversationMetadata mcp_server = FastMCP('mcp') -async def save_pr_metadata(user_id: str, conversation_id: str, tool_result: str) -> None: +async def save_pr_metadata( + user_id: str, conversation_id: str, tool_result: str +) -> None: conversation_store = await ConversationStoreImpl.get_instance(config, user_id) - conversation: ConversationMetadata = await conversation_store.get_metadata(conversation_id) + conversation: ConversationMetadata = await conversation_store.get_metadata( + conversation_id + ) - - pull_pattern = r"pull/(\d+)" - merge_request_pattern = r"merge_requests/(\d+)" + pull_pattern = r'pull/(\d+)' + merge_request_pattern = r'merge_requests/(\d+)' # Check if the tool_result contains the PR number pr_number = None @@ -33,11 +42,11 @@ async def save_pr_metadata(user_id: str, conversation_id: str, tool_result: str) elif match_merge_request: pr_number = int(match_merge_request.group(1)) - if pr_number: conversation.pr_number.append(pr_number) await conversation_store.save_metadata(conversation) + @mcp_server.tool() async def create_pr( repo_name: Annotated[ @@ -46,7 +55,7 @@ async def create_pr( source_branch: Annotated[str, Field(description='Source branch on repo')], target_branch: Annotated[str, Field(description='Target branch on repo')], title: Annotated[str, Field(description='PR Title')], - body: Annotated[str | None, Field(description='PR body')] + body: Annotated[str | None, Field(description='PR body')], ) -> str: """Open a draft PR in GitHub""" @@ -54,20 +63,24 @@ async def create_pr( request = get_http_request() headers = request.headers - conversation_id = headers.get('X-OpenHands-Conversation-ID', None) + conversation_id = headers.get('X-OpenHands-ServerConversation-ID', None) provider_tokens = await get_provider_tokens(request) access_token = await get_access_token(request) user_id = await get_user_id(request) - github_token = provider_tokens.get(ProviderType.GITHUB, ProviderToken()) if provider_tokens else ProviderToken() + github_token = ( + provider_tokens.get(ProviderType.GITHUB, ProviderToken()) + if provider_tokens + else ProviderToken() + ) github_service = GithubServiceImpl( user_id=github_token.user_id, external_auth_id=user_id, external_auth_token=access_token, token=github_token.token, - base_domain=github_token.host + base_domain=github_token.host, ) try: @@ -76,7 +89,7 @@ async def create_pr( source_branch=source_branch, target_branch=target_branch, title=title, - body=body + body=body, ) if conversation_id and user_id: @@ -88,37 +101,41 @@ async def create_pr( return response - @mcp_server.tool() async def create_mr( id: Annotated[ - int | str, Field(description='GitLab repository (ID or URL-encoded path of the project)') + int | str, + Field(description='GitLab repository (ID or URL-encoded path of the project)'), ], source_branch: Annotated[str, Field(description='Source branch on repo')], target_branch: Annotated[str, Field(description='Target branch on repo')], title: Annotated[str, Field(description='MR Title')], - description: Annotated[str | None, Field(description='MR description')] + description: Annotated[str | None, Field(description='MR description')], ) -> str: """Open a draft MR in GitLab""" - + logger.info('Calling OpenHands MCP create_mr') request = get_http_request() headers = request.headers - conversation_id = headers.get('X-OpenHands-Conversation-ID', None) + conversation_id = headers.get('X-OpenHands-ServerConversation-ID', None) provider_tokens = await get_provider_tokens(request) access_token = await get_access_token(request) user_id = await get_user_id(request) - github_token = provider_tokens.get(ProviderType.GITLAB, ProviderToken()) if provider_tokens else ProviderToken() + github_token = ( + provider_tokens.get(ProviderType.GITLAB, ProviderToken()) + if provider_tokens + else ProviderToken() + ) github_service = GitLabServiceImpl( user_id=github_token.user_id, external_auth_id=user_id, external_auth_token=access_token, token=github_token.token, - base_domain=github_token.host + base_domain=github_token.host, ) try: @@ -137,5 +154,3 @@ async def create_mr( response = str(e) return response - - diff --git a/openhands/server/services/conversation.py b/openhands/server/services/conversation.py index db3a555516..7c079dbe7a 100644 --- a/openhands/server/services/conversation.py +++ b/openhands/server/services/conversation.py @@ -1,16 +1,26 @@ - - -from typing import Any import uuid +from typing import Any + from openhands.core.logger import openhands_logger as logger from openhands.events.action.message import MessageAction -from openhands.integrations.provider import CUSTOM_SECRETS_TYPE_WITH_JSON_SCHEMA, PROVIDER_TOKEN_TYPE +from openhands.integrations.provider import ( + CUSTOM_SECRETS_TYPE_WITH_JSON_SCHEMA, + PROVIDER_TOKEN_TYPE, +) from openhands.integrations.service_types import ProviderType from openhands.server.data_models.agent_loop_info import AgentLoopInfo from openhands.server.session.conversation_init_data import ConversationInitData -from openhands.server.shared import ConversationStoreImpl, SettingsStoreImpl, config, conversation_manager +from openhands.server.shared import ( + ConversationStoreImpl, + SettingsStoreImpl, + config, + conversation_manager, +) from openhands.server.types import LLMAuthenticationError, MissingSettingsError -from openhands.storage.data_models.conversation_metadata import ConversationMetadata, ConversationTrigger +from openhands.storage.data_models.conversation_metadata import ( + ConversationMetadata, + ConversationTrigger, +) from openhands.utils.conversation_summary import get_default_conversation_title @@ -69,7 +79,7 @@ async def create_new_conversation( conversation_init_data = ConversationInitData(**session_init_args) logger.info('Loading conversation store') conversation_store = await ConversationStoreImpl.get_instance(config, user_id) - logger.info('Conversation store loaded') + logger.info('ServerConversation store loaded') # For nested runtimes, we allow a single conversation id, passed in on container creation if conversation_id is None: @@ -101,7 +111,7 @@ async def create_new_conversation( extra={'user_id': user_id, 'session_id': conversation_id}, ) initial_message_action = None - if initial_user_msg or image_urls: + if initial_user_msg or image_urls: initial_message_action = MessageAction( content=initial_user_msg or '', image_urls=image_urls or [], @@ -109,7 +119,7 @@ async def create_new_conversation( if attach_convo_id and conversation_instructions: conversation_instructions = conversation_instructions.format(conversation_id) - + agent_loop_info = await conversation_manager.maybe_start_agent_loop( conversation_id, conversation_init_data, diff --git a/openhands/server/session/agent_session.py b/openhands/server/session/agent_session.py index 4f84fd3e16..cc80cfcf91 100644 --- a/openhands/server/session/agent_session.py +++ b/openhands/server/session/agent_session.py @@ -9,15 +9,18 @@ from openhands.controller import AgentController from openhands.controller.agent import Agent from openhands.controller.replay import ReplayManager from openhands.controller.state.state import State -from openhands.core.config import AgentConfig, AppConfig, LLMConfig +from openhands.core.config import AgentConfig, LLMConfig, OpenHandsConfig from openhands.core.exceptions import AgentRuntimeUnavailableError from openhands.core.logger import OpenHandsLoggerAdapter from openhands.core.schema.agent import AgentState from openhands.events.action import ChangeAgentStateAction, MessageAction from openhands.events.event import Event, EventSource from openhands.events.stream import EventStream -from openhands.integrations.provider import CUSTOM_SECRETS_TYPE, PROVIDER_TOKEN_TYPE, ProviderHandler -from openhands.integrations.service_types import ProviderType +from openhands.integrations.provider import ( + CUSTOM_SECRETS_TYPE, + PROVIDER_TOKEN_TYPE, + ProviderHandler, +) from openhands.mcp import add_mcp_tools_to_agent from openhands.memory.memory import Memory from openhands.microagent.microagent import BaseMicroagent @@ -80,7 +83,7 @@ class AgentSession: async def start( self, runtime_name: str, - config: AppConfig, + config: OpenHandsConfig, agent: Agent, max_iterations: int, git_provider_tokens: PROVIDER_TOKEN_TYPE | None = None, @@ -118,7 +121,9 @@ class AgentSession: finished = False # For monitoring runtime_connected = False - custom_secrets_handler = UserSecrets(custom_secrets=custom_secrets if custom_secrets else {}) + custom_secrets_handler = UserSecrets( + custom_secrets=custom_secrets if custom_secrets else {} + ) try: self._create_security_analyzer(config.security.security_analyzer) @@ -147,7 +152,7 @@ class AgentSession: selected_repository=selected_repository, repo_directory=repo_directory, conversation_instructions=conversation_instructions, - custom_secrets_descriptions=custom_secrets_handler.get_custom_secrets_descriptions() + custom_secrets_descriptions=custom_secrets_handler.get_custom_secrets_descriptions(), ) # NOTE: this needs to happen before controller is created @@ -232,7 +237,7 @@ class AgentSession: initial_message: MessageAction | None, replay_json: str, agent: Agent, - config: AppConfig, + config: OpenHandsConfig, max_iterations: int, max_budget_per_task: float | None, agent_to_llm_config: dict[str, LLMConfig] | None, @@ -271,11 +276,10 @@ class AgentSession: security_analyzer, SecurityAnalyzer )(self.event_stream) - def override_provider_tokens_with_custom_secret( self, git_provider_tokens: PROVIDER_TOKEN_TYPE | None, - custom_secrets: CUSTOM_SECRETS_TYPE | None + custom_secrets: CUSTOM_SECRETS_TYPE | None, ): if git_provider_tokens and custom_secrets: tokens = dict(git_provider_tokens) @@ -283,15 +287,14 @@ class AgentSession: token_name = ProviderHandler.get_provider_env_key(provider) if token_name in custom_secrets or token_name.upper() in custom_secrets: del tokens[provider] - + return MappingProxyType(tokens) return git_provider_tokens - async def _create_runtime( self, runtime_name: str, - config: AppConfig, + config: OpenHandsConfig, agent: Agent, git_provider_tokens: PROVIDER_TOKEN_TYPE | None = None, custom_secrets: CUSTOM_SECRETS_TYPE | None = None, @@ -317,10 +320,14 @@ class AgentSession: self.logger.debug(f'Initializing runtime `{runtime_name}` now...') runtime_cls = get_runtime_cls(runtime_name) - if runtime_cls == RemoteRuntime: + if runtime_cls == RemoteRuntime: # If provider tokens is passed in custom secrets, then remove provider from provider tokens # We prioritize provider tokens set in custom secrets - provider_tokens_without_gitlab = self.override_provider_tokens_with_custom_secret(git_provider_tokens, custom_secrets) + provider_tokens_without_gitlab = ( + self.override_provider_tokens_with_custom_secret( + git_provider_tokens, custom_secrets + ) + ) self.runtime = runtime_cls( config=config, @@ -339,7 +346,7 @@ class AgentSession: provider_tokens=git_provider_tokens or cast(PROVIDER_TOKEN_TYPE, MappingProxyType({})) ) - + # Merge git provider tokens with custom secrets before passing over to runtime env_vars.update(await provider_handler.get_env_vars(expose_secrets=True)) self.runtime = runtime_cls( @@ -436,11 +443,11 @@ class AgentSession: return controller async def _create_memory( - self, - selected_repository: str | None, - repo_directory: str | None, + self, + selected_repository: str | None, + repo_directory: str | None, conversation_instructions: str | None, - custom_secrets_descriptions: dict[str, str] + custom_secrets_descriptions: dict[str, str], ) -> Memory: memory = Memory( event_stream=self.event_stream, @@ -461,10 +468,7 @@ class AgentSession: memory.load_user_workspace_microagents(microagents) if selected_repository and repo_directory: - memory.set_repository_info( - selected_repository, - repo_directory - ) + memory.set_repository_info(selected_repository, repo_directory) return memory def _maybe_restore_state(self) -> State | None: diff --git a/openhands/server/session/conversation.py b/openhands/server/session/conversation.py index 32915ecb10..85fa693121 100644 --- a/openhands/server/session/conversation.py +++ b/openhands/server/session/conversation.py @@ -1,6 +1,6 @@ import asyncio -from openhands.core.config import AppConfig +from openhands.core.config import OpenHandsConfig from openhands.events.stream import EventStream from openhands.runtime import get_runtime_cls from openhands.runtime.base import Runtime @@ -9,7 +9,7 @@ from openhands.storage.files import FileStore from openhands.utils.async_utils import call_sync_from_async -class Conversation: +class ServerConversation: sid: str file_store: FileStore event_stream: EventStream @@ -17,7 +17,11 @@ class Conversation: user_id: str | None def __init__( - self, sid: str, file_store: FileStore, config: AppConfig, user_id: str | None + self, + sid: str, + file_store: FileStore, + config: OpenHandsConfig, + user_id: str | None, ): self.sid = sid self.config = config diff --git a/openhands/server/session/session.py b/openhands/server/session/session.py index 78366cd522..4d2c760f94 100644 --- a/openhands/server/session/session.py +++ b/openhands/server/session/session.py @@ -6,7 +6,7 @@ from logging import LoggerAdapter import socketio from openhands.controller.agent import Agent -from openhands.core.config import AppConfig +from openhands.core.config import OpenHandsConfig from openhands.core.config.condenser_config import ( BrowserOutputCondenserConfig, CondenserPipelineConfig, @@ -43,7 +43,7 @@ class Session: is_alive: bool = True agent_session: AgentSession loop: asyncio.AbstractEventLoop - config: AppConfig + config: OpenHandsConfig file_store: FileStore user_id: str | None logger: LoggerAdapter @@ -51,7 +51,7 @@ class Session: def __init__( self, sid: str, - config: AppConfig, + config: OpenHandsConfig, file_store: FileStore, sio: socketio.AsyncServer | None, user_id: str | None = None, @@ -128,9 +128,15 @@ class Session: self.config.search_api_key = settings.search_api_key # NOTE: this need to happen AFTER the config is updated with the search_api_key - self.config.mcp = settings.mcp_config or MCPConfig(sse_servers=[], stdio_servers=[]) + self.config.mcp = settings.mcp_config or MCPConfig( + sse_servers=[], stdio_servers=[] + ) # Add OpenHands' MCP server by default - openhands_mcp_server, openhands_mcp_stdio_servers = OpenHandsMCPConfigImpl.create_default_mcp_server_config(self.config.mcp_host, self.config, self.user_id) + openhands_mcp_server, openhands_mcp_stdio_servers = ( + OpenHandsMCPConfigImpl.create_default_mcp_server_config( + self.config.mcp_host, self.config, self.user_id + ) + ) if openhands_mcp_server: self.config.mcp.sse_servers.append(openhands_mcp_server) self.config.mcp.stdio_servers.extend(openhands_mcp_stdio_servers) @@ -154,7 +160,7 @@ class Session: ), ] ) - + self.logger.info( f'Enabling pipeline condenser with:' f' browser_output_masking(attention_window=2), ' diff --git a/openhands/server/shared.py b/openhands/server/shared.py index b91170c27f..cc6167dfef 100644 --- a/openhands/server/shared.py +++ b/openhands/server/shared.py @@ -3,8 +3,8 @@ import os import socketio from dotenv import load_dotenv -from openhands.core.config import load_app_config -from openhands.core.config.app_config import AppConfig +from openhands.core.config import load_openhands_config +from openhands.core.config.openhands_config import OpenHandsConfig from openhands.server.config.server_config import ServerConfig, load_server_config from openhands.server.conversation_manager.conversation_manager import ( ConversationManager, @@ -20,7 +20,7 @@ from openhands.utils.import_utils import get_impl load_dotenv() -config: AppConfig = load_app_config() +config: OpenHandsConfig = load_openhands_config() server_config_interface: ServerConfigInterface = load_server_config() assert isinstance(server_config_interface, ServerConfig), ( 'Loaded server config interface is not a ServerConfig, despite this being assumed' diff --git a/openhands/storage/conversation/conversation_store.py b/openhands/storage/conversation/conversation_store.py index 859084ee66..b28b2fc5be 100644 --- a/openhands/storage/conversation/conversation_store.py +++ b/openhands/storage/conversation/conversation_store.py @@ -3,7 +3,7 @@ from __future__ import annotations from abc import ABC, abstractmethod from typing import Iterable -from openhands.core.config.app_config import AppConfig +from openhands.core.config.openhands_config import OpenHandsConfig from openhands.storage.data_models.conversation_metadata import ConversationMetadata from openhands.storage.data_models.conversation_metadata_result_set import ( ConversationMetadataResultSet, @@ -22,9 +22,7 @@ class ConversationStore(ABC): async def get_metadata(self, conversation_id: str) -> ConversationMetadata: """Load conversation metadata.""" - async def validate_metadata( - self, conversation_id: str, user_id: str - ) -> bool: + async def validate_metadata(self, conversation_id: str, user_id: str) -> bool: """Validate that conversation belongs to the current user.""" metadata = await self.get_metadata(conversation_id) if not metadata.user_id or metadata.user_id != user_id: @@ -57,6 +55,6 @@ class ConversationStore(ABC): @classmethod @abstractmethod async def get_instance( - cls, config: AppConfig, user_id: str | None + cls, config: OpenHandsConfig, user_id: str | None ) -> ConversationStore: """Get a store for the user represented by the token given.""" diff --git a/openhands/storage/conversation/file_conversation_store.py b/openhands/storage/conversation/file_conversation_store.py index c8ac1c6578..78a5a664ea 100644 --- a/openhands/storage/conversation/file_conversation_store.py +++ b/openhands/storage/conversation/file_conversation_store.py @@ -6,7 +6,7 @@ from pathlib import Path from pydantic import TypeAdapter -from openhands.core.config.app_config import AppConfig +from openhands.core.config.openhands_config import OpenHandsConfig from openhands.core.logger import openhands_logger as logger from openhands.storage import get_file_store from openhands.storage.conversation.conversation_store import ConversationStore @@ -42,7 +42,7 @@ class FileConversationStore(ConversationStore): json_obj = json.loads(json_str) if 'created_at' not in json_obj: raise FileNotFoundError(path) - + # Remove github_user_id if it exists if 'github_user_id' in json_obj: json_obj.pop('github_user_id') @@ -103,7 +103,7 @@ class FileConversationStore(ConversationStore): @classmethod async def get_instance( - cls, config: AppConfig, user_id: str | None + cls, config: OpenHandsConfig, user_id: str | None ) -> FileConversationStore: file_store = get_file_store(config.file_store, config.file_store_path) return FileConversationStore(file_store) diff --git a/openhands/storage/data_models/settings.py b/openhands/storage/data_models/settings.py index 1f3b872b8a..32c123a3a8 100644 --- a/openhands/storage/data_models/settings.py +++ b/openhands/storage/data_models/settings.py @@ -12,7 +12,7 @@ from pydantic.json import pydantic_encoder from openhands.core.config.llm_config import LLMConfig from openhands.core.config.mcp_config import MCPConfig -from openhands.core.config.utils import load_app_config +from openhands.core.config.utils import load_openhands_config from openhands.storage.data_models.user_secrets import UserSecrets @@ -41,7 +41,6 @@ class Settings(BaseModel): mcp_config: MCPConfig | None = None search_api_key: SecretStr | None = None - model_config = { 'validate_assignment': True, } @@ -54,7 +53,7 @@ class Settings(BaseModel): """ if api_key is None: return None - + context = info.context if context and context.get('expose_secrets', False): return api_key.get_secret_value() @@ -106,7 +105,7 @@ class Settings(BaseModel): @staticmethod def from_config() -> Settings | None: - app_config = load_app_config() + app_config = load_openhands_config() llm_config: LLMConfig = app_config.get_llm_config() if llm_config.api_key is None: # If no api key has been set, we take this to mean that there is no reasonable default diff --git a/openhands/storage/secrets/file_secrets_store.py b/openhands/storage/secrets/file_secrets_store.py index 769d085d0d..8b4368b432 100644 --- a/openhands/storage/secrets/file_secrets_store.py +++ b/openhands/storage/secrets/file_secrets_store.py @@ -3,7 +3,7 @@ from __future__ import annotations import json from dataclasses import dataclass -from openhands.core.config.app_config import AppConfig +from openhands.core.config.openhands_config import OpenHandsConfig from openhands.storage import get_file_store from openhands.storage.data_models.user_secrets import UserSecrets from openhands.storage.files import FileStore @@ -37,7 +37,7 @@ class FileSecretsStore(SecretsStore): @classmethod async def get_instance( - cls, config: AppConfig, user_id: str | None + cls, config: OpenHandsConfig, user_id: str | None ) -> FileSecretsStore: file_store = get_file_store(config.file_store, config.file_store_path) return FileSecretsStore(file_store) diff --git a/openhands/storage/secrets/secrets_store.py b/openhands/storage/secrets/secrets_store.py index dcd53aec46..6a1f55185b 100644 --- a/openhands/storage/secrets/secrets_store.py +++ b/openhands/storage/secrets/secrets_store.py @@ -2,7 +2,7 @@ from __future__ import annotations from abc import ABC, abstractmethod -from openhands.core.config.app_config import AppConfig +from openhands.core.config.openhands_config import OpenHandsConfig from openhands.storage.data_models.user_secrets import UserSecrets @@ -19,5 +19,7 @@ class SecretsStore(ABC): @classmethod @abstractmethod - async def get_instance(cls, config: AppConfig, user_id: str | None) -> SecretsStore: + async def get_instance( + cls, config: OpenHandsConfig, user_id: str | None + ) -> SecretsStore: """Get a store for the user represented by the token given.""" diff --git a/openhands/storage/settings/file_settings_store.py b/openhands/storage/settings/file_settings_store.py index 88447d41bb..8095d25e7d 100644 --- a/openhands/storage/settings/file_settings_store.py +++ b/openhands/storage/settings/file_settings_store.py @@ -3,7 +3,7 @@ from __future__ import annotations import json from dataclasses import dataclass -from openhands.core.config.app_config import AppConfig +from openhands.core.config.openhands_config import OpenHandsConfig from openhands.storage import get_file_store from openhands.storage.data_models.settings import Settings from openhands.storage.files import FileStore @@ -31,7 +31,7 @@ class FileSettingsStore(SettingsStore): @classmethod async def get_instance( - cls, config: AppConfig, user_id: str | None + cls, config: OpenHandsConfig, user_id: str | None ) -> FileSettingsStore: file_store = get_file_store(config.file_store, config.file_store_path) return FileSettingsStore(file_store) diff --git a/openhands/storage/settings/settings_store.py b/openhands/storage/settings/settings_store.py index 721bee3381..380871f025 100644 --- a/openhands/storage/settings/settings_store.py +++ b/openhands/storage/settings/settings_store.py @@ -2,7 +2,7 @@ from __future__ import annotations from abc import ABC, abstractmethod -from openhands.core.config.app_config import AppConfig +from openhands.core.config.openhands_config import OpenHandsConfig from openhands.storage.data_models.settings import Settings @@ -20,6 +20,6 @@ class SettingsStore(ABC): @classmethod @abstractmethod async def get_instance( - cls, config: AppConfig, user_id: str | None + cls, config: OpenHandsConfig, user_id: str | None ) -> SettingsStore: """Get a store for the user represented by the token given.""" diff --git a/openhands/utils/llm.py b/openhands/utils/llm.py index fcffdf1b97..998ae4c969 100644 --- a/openhands/utils/llm.py +++ b/openhands/utils/llm.py @@ -6,12 +6,12 @@ with warnings.catch_warnings(): warnings.simplefilter('ignore') import litellm -from openhands.core.config import AppConfig, LLMConfig +from openhands.core.config import LLMConfig, OpenHandsConfig from openhands.core.logger import openhands_logger as logger from openhands.llm import bedrock -def get_supported_llm_models(config: AppConfig) -> list[str]: +def get_supported_llm_models(config: OpenHandsConfig) -> list[str]: """Get all models supported by LiteLLM. This function combines models from litellm and Bedrock, removing any diff --git a/tests/runtime/conftest.py b/tests/runtime/conftest.py index 4c5b3a03ff..40637b6406 100644 --- a/tests/runtime/conftest.py +++ b/tests/runtime/conftest.py @@ -7,7 +7,7 @@ import time import pytest from pytest import TempPathFactory -from openhands.core.config import AppConfig, MCPConfig, load_app_config +from openhands.core.config import MCPConfig, OpenHandsConfig, load_openhands_config from openhands.core.logger import openhands_logger as logger from openhands.events import EventStream from openhands.runtime.base import Runtime @@ -218,14 +218,14 @@ def _load_runtime( runtime_startup_env_vars: dict[str, str] | None = None, docker_runtime_kwargs: dict[str, str] | None = None, override_mcp_config: MCPConfig | None = None, -) -> tuple[Runtime, AppConfig]: +) -> tuple[Runtime, OpenHandsConfig]: sid = 'rt_' + str(random.randint(100000, 999999)) # AgentSkills need to be initialized **before** Jupyter # otherwise Jupyter will not access the proper dependencies installed by AgentSkills plugins = [AgentSkillsRequirement(), JupyterRequirement()] - config = load_app_config() + config = load_openhands_config() config.run_as_openhands = run_as_openhands config.sandbox.force_rebuild_runtime = force_rebuild_runtime config.sandbox.keep_runtime_alive = False diff --git a/tests/runtime/test_microagent.py b/tests/runtime/test_microagent.py index f73ef77679..54ba528026 100644 --- a/tests/runtime/test_microagent.py +++ b/tests/runtime/test_microagent.py @@ -208,7 +208,7 @@ async def test_add_mcp_tools_from_microagents(): """Test that add_mcp_tools_to_agent adds tools from microagents.""" # Import ActionExecutionClient for mocking - from openhands.core.config.app_config import AppConfig + from openhands.core.config.openhands_config import OpenHandsConfig from openhands.runtime.impl.action_execution.action_execution_client import ( ActionExecutionClient, ) @@ -219,8 +219,8 @@ async def test_add_mcp_tools_from_microagents(): mock_memory = MagicMock() mock_mcp_config = MCPConfig() - # Create a mock AppConfig with the MCP config - mock_app_config = AppConfig(mcp=mock_mcp_config, search_api_key=None) + # Create a mock OpenHandsConfig with the MCP config + mock_app_config = OpenHandsConfig(mcp=mock_mcp_config, search_api_key=None) # Configure the mock memory to return a microagent MCP config mock_stdio_server = MCPStdioServerConfig( @@ -247,7 +247,7 @@ async def test_add_mcp_tools_from_microagents(): 'openhands.mcp.utils.fetch_mcp_tools_from_config', new=AsyncMock(return_value=[mock_tool]), ): - # Call the function with the AppConfig instead of MCPConfig + # Call the function with the OpenHandsConfig instead of MCPConfig await add_mcp_tools_to_agent( mock_agent, mock_runtime, mock_memory, mock_app_config ) diff --git a/tests/runtime/test_replay.py b/tests/runtime/test_replay.py index 33a5b35956..85e3bbf0a0 100644 --- a/tests/runtime/test_replay.py +++ b/tests/runtime/test_replay.py @@ -6,8 +6,8 @@ from pathlib import Path from conftest import _close_test_runtime, _load_runtime from openhands.controller.state.state import State -from openhands.core.config.app_config import AppConfig from openhands.core.config.config_utils import OH_DEFAULT_AGENT +from openhands.core.config.openhands_config import OpenHandsConfig from openhands.core.main import run_controller from openhands.core.schema.agent import AgentState from openhands.events.action.empty import NullAction @@ -17,7 +17,7 @@ from openhands.events.observation.commands import CmdOutputObservation def _get_config(trajectory_name: str, agent: str = OH_DEFAULT_AGENT): - return AppConfig( + return OpenHandsConfig( default_agent=agent, run_as_openhands=False, # do not mount workspace diff --git a/tests/runtime/test_stress_remote_runtime.py b/tests/runtime/test_stress_remote_runtime.py index c95fc1a24c..e10f2868e1 100644 --- a/tests/runtime/test_stress_remote_runtime.py +++ b/tests/runtime/test_stress_remote_runtime.py @@ -37,8 +37,8 @@ from openhands.agenthub import Agent from openhands.controller.state.state import State from openhands.core.config import ( AgentConfig, - AppConfig, LLMConfig, + OpenHandsConfig, SandboxConfig, ) from openhands.core.logger import openhands_logger as logger @@ -60,8 +60,8 @@ AGENT_CLS_TO_FAKE_USER_RESPONSE_FN = { } -def get_config() -> AppConfig: - config = AppConfig( +def get_config() -> OpenHandsConfig: + config = OpenHandsConfig( run_as_openhands=False, runtime=os.environ.get('RUNTIME', 'remote'), sandbox=SandboxConfig( diff --git a/tests/unit/core/config/test_config_utils.py b/tests/unit/core/config/test_config_utils.py index a18b26b817..16f4f6e307 100644 --- a/tests/unit/core/config/test_config_utils.py +++ b/tests/unit/core/config/test_config_utils.py @@ -1,135 +1,168 @@ import pytest from openhands.core.config.agent_config import AgentConfig -from openhands.core.config.app_config import AppConfig -from openhands.core.config.utils import finalize_config, load_from_env, load_from_toml +from openhands.core.config.openhands_config import OpenHandsConfig +from openhands.core.config.utils import finalize_config # Define a dummy agent name often used in tests or as a default DEFAULT_AGENT_NAME = 'CodeActAgent' + def test_finalize_config_cli_disables_jupyter_and_browsing_when_true(): """ Test that finalize_config sets enable_jupyter and enable_browsing to False when runtime is 'cli' and they were initially True. """ - app_config = AppConfig() + app_config = OpenHandsConfig() app_config.runtime = 'cli' - + agent_config = AgentConfig(enable_jupyter=True, enable_browsing=True) app_config.agents[DEFAULT_AGENT_NAME] = agent_config - + finalize_config(app_config) - - assert not app_config.agents[DEFAULT_AGENT_NAME].enable_jupyter, \ + + assert not app_config.agents[DEFAULT_AGENT_NAME].enable_jupyter, ( "enable_jupyter should be False when runtime is 'cli'" - assert not app_config.agents[DEFAULT_AGENT_NAME].enable_browsing, \ + ) + assert not app_config.agents[DEFAULT_AGENT_NAME].enable_browsing, ( "enable_browsing should be False when runtime is 'cli'" + ) + def test_finalize_config_cli_keeps_jupyter_and_browsing_false_when_false(): """ Test that finalize_config keeps enable_jupyter and enable_browsing as False when runtime is 'cli' and they were initially False. """ - app_config = AppConfig() + app_config = OpenHandsConfig() app_config.runtime = 'cli' - + agent_config = AgentConfig(enable_jupyter=False, enable_browsing=False) app_config.agents[DEFAULT_AGENT_NAME] = agent_config - + finalize_config(app_config) - - assert not app_config.agents[DEFAULT_AGENT_NAME].enable_jupyter, \ + + assert not app_config.agents[DEFAULT_AGENT_NAME].enable_jupyter, ( "enable_jupyter should remain False when runtime is 'cli' and initially False" - assert not app_config.agents[DEFAULT_AGENT_NAME].enable_browsing, \ + ) + assert not app_config.agents[DEFAULT_AGENT_NAME].enable_browsing, ( "enable_browsing should remain False when runtime is 'cli' and initially False" + ) + def test_finalize_config_other_runtime_keeps_jupyter_and_browsing_true_by_default(): """ Test that finalize_config keeps enable_jupyter and enable_browsing as True (default) when runtime is not 'cli'. """ - app_config = AppConfig() + app_config = OpenHandsConfig() app_config.runtime = 'docker' # A non-cli runtime - + # AgentConfig defaults enable_jupyter and enable_browsing to True agent_config = AgentConfig() app_config.agents[DEFAULT_AGENT_NAME] = agent_config - + finalize_config(app_config) - - assert app_config.agents[DEFAULT_AGENT_NAME].enable_jupyter, \ - "enable_jupyter should remain True by default for non-cli runtimes" - assert app_config.agents[DEFAULT_AGENT_NAME].enable_browsing, \ - "enable_browsing should remain True by default for non-cli runtimes" + + assert app_config.agents[DEFAULT_AGENT_NAME].enable_jupyter, ( + 'enable_jupyter should remain True by default for non-cli runtimes' + ) + assert app_config.agents[DEFAULT_AGENT_NAME].enable_browsing, ( + 'enable_browsing should remain True by default for non-cli runtimes' + ) + def test_finalize_config_other_runtime_keeps_jupyter_and_browsing_false_if_set(): """ Test that finalize_config keeps enable_jupyter and enable_browsing as False when runtime is not 'cli' but they were explicitly set to False. """ - app_config = AppConfig() + app_config = OpenHandsConfig() app_config.runtime = 'docker' # A non-cli runtime - + agent_config = AgentConfig(enable_jupyter=False, enable_browsing=False) app_config.agents[DEFAULT_AGENT_NAME] = agent_config - + finalize_config(app_config) - - assert not app_config.agents[DEFAULT_AGENT_NAME].enable_jupyter, \ - "enable_jupyter should remain False for non-cli runtimes if explicitly set to False" - assert not app_config.agents[DEFAULT_AGENT_NAME].enable_browsing, \ - "enable_browsing should remain False for non-cli runtimes if explicitly set to False" + + assert not app_config.agents[DEFAULT_AGENT_NAME].enable_jupyter, ( + 'enable_jupyter should remain False for non-cli runtimes if explicitly set to False' + ) + assert not app_config.agents[DEFAULT_AGENT_NAME].enable_browsing, ( + 'enable_browsing should remain False for non-cli runtimes if explicitly set to False' + ) + def test_finalize_config_no_agents_defined(): """ Test that finalize_config runs without error if no agents are defined in the config, even when runtime is 'cli'. """ - app_config = AppConfig() + app_config = OpenHandsConfig() app_config.runtime = 'cli' # No agents are added to app_config.agents - + try: finalize_config(app_config) except Exception as e: - pytest.fail(f"finalize_config raised an exception with no agents defined: {e}") + pytest.fail(f'finalize_config raised an exception with no agents defined: {e}') + def test_finalize_config_multiple_agents_cli_runtime(): """ Test that finalize_config correctly disables jupyter and browsing for multiple agents when runtime is 'cli'. """ - app_config = AppConfig() + app_config = OpenHandsConfig() app_config.runtime = 'cli' - + agent_config1 = AgentConfig(enable_jupyter=True, enable_browsing=True) agent_config2 = AgentConfig(enable_jupyter=True, enable_browsing=True) app_config.agents['Agent1'] = agent_config1 app_config.agents['Agent2'] = agent_config2 - + finalize_config(app_config) - - assert not app_config.agents['Agent1'].enable_jupyter, "Jupyter should be disabled for Agent1" - assert not app_config.agents['Agent1'].enable_browsing, "Browsing should be disabled for Agent1" - assert not app_config.agents['Agent2'].enable_jupyter, "Jupyter should be disabled for Agent2" - assert not app_config.agents['Agent2'].enable_browsing, "Browsing should be disabled for Agent2" + + assert not app_config.agents['Agent1'].enable_jupyter, ( + 'Jupyter should be disabled for Agent1' + ) + assert not app_config.agents['Agent1'].enable_browsing, ( + 'Browsing should be disabled for Agent1' + ) + assert not app_config.agents['Agent2'].enable_jupyter, ( + 'Jupyter should be disabled for Agent2' + ) + assert not app_config.agents['Agent2'].enable_browsing, ( + 'Browsing should be disabled for Agent2' + ) + def test_finalize_config_multiple_agents_other_runtime(): """ Test that finalize_config correctly keeps jupyter and browsing enabled (or as set) for multiple agents when runtime is not 'cli'. """ - app_config = AppConfig() + app_config = OpenHandsConfig() app_config.runtime = 'docker' - - agent_config1 = AgentConfig(enable_jupyter=True, enable_browsing=True) # Defaults - agent_config2 = AgentConfig(enable_jupyter=False, enable_browsing=False) # Explicitly false + + agent_config1 = AgentConfig(enable_jupyter=True, enable_browsing=True) # Defaults + agent_config2 = AgentConfig( + enable_jupyter=False, enable_browsing=False + ) # Explicitly false app_config.agents['Agent1'] = agent_config1 app_config.agents['Agent2'] = agent_config2 - + finalize_config(app_config) - - assert app_config.agents['Agent1'].enable_jupyter, "Jupyter should be True for Agent1" - assert app_config.agents['Agent1'].enable_browsing, "Browsing should be True for Agent1" - assert not app_config.agents['Agent2'].enable_jupyter, "Jupyter should be False for Agent2" - assert not app_config.agents['Agent2'].enable_browsing, "Browsing should be False for Agent2" \ No newline at end of file + + assert app_config.agents['Agent1'].enable_jupyter, ( + 'Jupyter should be True for Agent1' + ) + assert app_config.agents['Agent1'].enable_browsing, ( + 'Browsing should be True for Agent1' + ) + assert not app_config.agents['Agent2'].enable_jupyter, ( + 'Jupyter should be False for Agent2' + ) + assert not app_config.agents['Agent2'].enable_browsing, ( + 'Browsing should be False for Agent2' + ) diff --git a/tests/unit/resolver/gitlab/test_gitlab_resolve_issues.py b/tests/unit/resolver/gitlab/test_gitlab_resolve_issues.py index 0840926a23..20c4fa7dd7 100644 --- a/tests/unit/resolver/gitlab/test_gitlab_resolve_issues.py +++ b/tests/unit/resolver/gitlab/test_gitlab_resolve_issues.py @@ -525,7 +525,10 @@ async def test_process_issue( patch( 'openhands.resolver.issue_resolver.SandboxConfig', return_value=MagicMock() ), - patch('openhands.resolver.issue_resolver.AppConfig', return_value=MagicMock()), + patch( + 'openhands.resolver.issue_resolver.OpenHandsConfig', + return_value=MagicMock(), + ), ): # Call the process_issue method result = await resolver.process_issue(issue, base_commit, handler_instance) diff --git a/tests/unit/test_acompletion.py b/tests/unit/test_acompletion.py index 55122c1c7a..5d519562a3 100644 --- a/tests/unit/test_acompletion.py +++ b/tests/unit/test_acompletion.py @@ -4,13 +4,13 @@ from unittest.mock import AsyncMock, MagicMock, patch import pytest -from openhands.core.config import load_app_config +from openhands.core.config import load_openhands_config from openhands.core.exceptions import UserCancelledError from openhands.llm.async_llm import AsyncLLM from openhands.llm.llm import LLM from openhands.llm.streaming_llm import StreamingLLM -config = load_app_config() +config = load_openhands_config() @pytest.fixture diff --git a/tests/unit/test_agent_controller.py b/tests/unit/test_agent_controller.py index c5cca37be2..f0ab40be71 100644 --- a/tests/unit/test_agent_controller.py +++ b/tests/unit/test_agent_controller.py @@ -12,7 +12,7 @@ from litellm import ( from openhands.controller.agent import Agent from openhands.controller.agent_controller import AgentController from openhands.controller.state.state import State, TrafficControlState -from openhands.core.config import AppConfig +from openhands.core.config import OpenHandsConfig from openhands.core.config.agent_config import AgentConfig from openhands.core.main import run_controller from openhands.core.schema import AgentState @@ -55,7 +55,7 @@ def mock_agent(): agent = MagicMock(spec=Agent) agent.llm = MagicMock(spec=LLM) agent.llm.metrics = Metrics() - agent.llm.config = AppConfig().get_llm_config() + agent.llm.config = OpenHandsConfig().get_llm_config() # Add config with enable_mcp attribute agent.config = MagicMock(spec=AgentConfig) @@ -235,7 +235,7 @@ async def test_react_to_content_policy_violation( async def test_run_controller_with_fatal_error( test_event_stream, mock_memory, mock_agent ): - config = AppConfig() + config = OpenHandsConfig() def agent_step_fn(state): print(f'agent_step_fn received state: {state}') @@ -300,7 +300,7 @@ async def test_run_controller_with_fatal_error( async def test_run_controller_stop_with_stuck( test_event_stream, mock_memory, mock_agent ): - config = AppConfig() + config = OpenHandsConfig() def agent_step_fn(state): print(f'agent_step_fn received state: {state}') @@ -653,7 +653,7 @@ async def test_reset_with_pending_action_no_metadata( async def test_run_controller_max_iterations_has_metrics( test_event_stream, mock_memory, mock_agent ): - config = AppConfig( + config = OpenHandsConfig( max_iterations=3, ) event_stream = test_event_stream @@ -805,7 +805,7 @@ async def test_context_window_exceeded_error_handling( # handles the truncation correctly. final_state = await asyncio.wait_for( run_controller( - config=AppConfig(max_iterations=max_iterations), + config=OpenHandsConfig(max_iterations=max_iterations), initial_user_action=MessageAction(content='INITIAL'), runtime=mock_runtime, sid='test', @@ -943,7 +943,7 @@ async def test_run_controller_with_context_window_exceeded_with_truncation( try: state = await asyncio.wait_for( run_controller( - config=AppConfig(max_iterations=5), + config=OpenHandsConfig(max_iterations=5), initial_user_action=MessageAction(content='INITIAL'), runtime=mock_runtime, sid='test', @@ -1019,7 +1019,7 @@ async def test_run_controller_with_context_window_exceeded_without_truncation( try: state = await asyncio.wait_for( run_controller( - config=AppConfig(max_iterations=3), + config=OpenHandsConfig(max_iterations=3), initial_user_action=MessageAction(content='INITIAL'), runtime=mock_runtime, sid='test', @@ -1063,7 +1063,7 @@ async def test_run_controller_with_context_window_exceeded_without_truncation( @pytest.mark.asyncio async def test_run_controller_with_memory_error(test_event_stream, mock_agent): - config = AppConfig() + config = OpenHandsConfig() event_stream = test_event_stream # Create a proper agent that returns an action without an ID @@ -1330,7 +1330,7 @@ async def test_first_user_message_with_identical_content(test_event_stream, mock # Create an agent controller mock_agent.llm = MagicMock(spec=LLM) mock_agent.llm.metrics = Metrics() - mock_agent.llm.config = AppConfig().get_llm_config() + mock_agent.llm.config = OpenHandsConfig().get_llm_config() controller = AgentController( agent=mock_agent, @@ -1397,7 +1397,7 @@ async def test_agent_controller_processes_null_observation_with_cause(): mock_agent = MagicMock(spec=Agent) mock_agent.llm = MagicMock(spec=LLM) mock_agent.llm.metrics = Metrics() - mock_agent.llm.config = AppConfig().get_llm_config() + mock_agent.llm.config = OpenHandsConfig().get_llm_config() # Create a controller with the mock agent controller = AgentController( diff --git a/tests/unit/test_agent_history.py b/tests/unit/test_agent_history.py index 1c53a03a26..d85280d422 100644 --- a/tests/unit/test_agent_history.py +++ b/tests/unit/test_agent_history.py @@ -5,7 +5,7 @@ import pytest from openhands.controller.agent import Agent from openhands.controller.agent_controller import AgentController from openhands.controller.state.state import State -from openhands.core.config import AppConfig +from openhands.core.config import OpenHandsConfig from openhands.events import EventSource from openhands.events.action import CmdRunAction, MessageAction, RecallAction from openhands.events.action.message import SystemMessageAction @@ -90,8 +90,8 @@ def controller_fixture(): mock_agent = MagicMock(spec=Agent) mock_agent.llm = MagicMock(spec=LLM) mock_agent.llm.metrics = Metrics() - mock_agent.llm.config = AppConfig().get_llm_config() - mock_agent.config = AppConfig().get_agent_config('CodeActAgent') + mock_agent.llm.config = OpenHandsConfig().get_llm_config() + mock_agent.config = OpenHandsConfig().get_agent_config('CodeActAgent') mock_event_stream = MagicMock(spec=EventStream) mock_event_stream.sid = 'test_sid' diff --git a/tests/unit/test_agent_session.py b/tests/unit/test_agent_session.py index 66fa9b40c1..de6c0d7f8f 100644 --- a/tests/unit/test_agent_session.py +++ b/tests/unit/test_agent_session.py @@ -5,7 +5,7 @@ import pytest from openhands.controller.agent import Agent from openhands.controller.agent_controller import AgentController from openhands.controller.state.state import State -from openhands.core.config import AppConfig, LLMConfig +from openhands.core.config import LLMConfig, OpenHandsConfig from openhands.core.config.agent_config import AgentConfig from openhands.events import EventStream, EventStreamSubscriber from openhands.llm import LLM @@ -110,7 +110,7 @@ async def test_agent_session_start_with_no_state(mock_agent): ): await session.start( runtime_name='test-runtime', - config=AppConfig(), + config=OpenHandsConfig(), agent=mock_agent, max_iterations=10, ) @@ -203,7 +203,7 @@ async def test_agent_session_start_with_restored_state(mock_agent): ): await session.start( runtime_name='test-runtime', - config=AppConfig(), + config=OpenHandsConfig(), agent=mock_agent, max_iterations=10, ) diff --git a/tests/unit/test_auto_generate_title.py b/tests/unit/test_auto_generate_title.py index dd7bbe5ca6..f8374b9a4f 100644 --- a/tests/unit/test_auto_generate_title.py +++ b/tests/unit/test_auto_generate_title.py @@ -5,8 +5,8 @@ from unittest.mock import AsyncMock, MagicMock, patch import pytest -from openhands.core.config.app_config import AppConfig from openhands.core.config.llm_config import LLMConfig +from openhands.core.config.openhands_config import OpenHandsConfig from openhands.events.action import MessageAction from openhands.events.event import EventSource from openhands.events.stream import EventStream @@ -207,7 +207,7 @@ async def test_update_conversation_with_title(): # Create the conversation manager manager = StandaloneConversationManager( sio=sio, - config=AppConfig(), + config=OpenHandsConfig(), file_store=file_store, server_config=server_config, monitoring_listener=MonitoringListener(), diff --git a/tests/unit/test_cli_commands.py b/tests/unit/test_cli_commands.py index 9024aa26f8..210c43540a 100644 --- a/tests/unit/test_cli_commands.py +++ b/tests/unit/test_cli_commands.py @@ -13,7 +13,7 @@ from openhands.cli.commands import ( handle_status_command, ) from openhands.cli.tui import UsageMetrics -from openhands.core.config import AppConfig +from openhands.core.config import OpenHandsConfig from openhands.core.schema import AgentState from openhands.events import EventSource from openhands.events.action import ChangeAgentStateAction, MessageAction @@ -27,7 +27,7 @@ class TestHandleCommands: event_stream = MagicMock(spec=EventStream) usage_metrics = MagicMock(spec=UsageMetrics) sid = 'test-session-id' - config = MagicMock(spec=AppConfig) + config = MagicMock(spec=OpenHandsConfig) current_dir = '/test/dir' settings_store = MagicMock(spec=FileSettingsStore) @@ -278,7 +278,7 @@ class TestHandleInitCommand: @pytest.mark.asyncio @patch('openhands.cli.commands.init_repository') async def test_init_local_runtime_successful(self, mock_init_repository): - config = MagicMock(spec=AppConfig) + config = MagicMock(spec=OpenHandsConfig) config.runtime = 'local' event_stream = MagicMock(spec=EventStream) current_dir = '/test/dir' @@ -306,7 +306,7 @@ class TestHandleInitCommand: @pytest.mark.asyncio @patch('openhands.cli.commands.init_repository') async def test_init_local_runtime_unsuccessful(self, mock_init_repository): - config = MagicMock(spec=AppConfig) + config = MagicMock(spec=OpenHandsConfig) config.runtime = 'local' event_stream = MagicMock(spec=EventStream) current_dir = '/test/dir' @@ -330,7 +330,7 @@ class TestHandleInitCommand: @patch('openhands.cli.commands.print_formatted_text') @patch('openhands.cli.commands.init_repository') async def test_init_non_local_runtime(self, mock_init_repository, mock_print): - config = MagicMock(spec=AppConfig) + config = MagicMock(spec=OpenHandsConfig) config.runtime = 'remote' # Not local event_stream = MagicMock(spec=EventStream) current_dir = '/test/dir' @@ -360,7 +360,7 @@ class TestHandleSettingsCommand: mock_cli_confirm, mock_display_settings, ): - config = MagicMock(spec=AppConfig) + config = MagicMock(spec=OpenHandsConfig) settings_store = MagicMock(spec=FileSettingsStore) # Mock user selecting "Basic" settings @@ -384,7 +384,7 @@ class TestHandleSettingsCommand: mock_cli_confirm, mock_display_settings, ): - config = MagicMock(spec=AppConfig) + config = MagicMock(spec=OpenHandsConfig) settings_store = MagicMock(spec=FileSettingsStore) # Mock user selecting "Basic" settings @@ -408,7 +408,7 @@ class TestHandleSettingsCommand: mock_cli_confirm, mock_display_settings, ): - config = MagicMock(spec=AppConfig) + config = MagicMock(spec=OpenHandsConfig) settings_store = MagicMock(spec=FileSettingsStore) # Mock user selecting "Advanced" settings @@ -432,7 +432,7 @@ class TestHandleSettingsCommand: mock_cli_confirm, mock_display_settings, ): - config = MagicMock(spec=AppConfig) + config = MagicMock(spec=OpenHandsConfig) settings_store = MagicMock(spec=FileSettingsStore) # Mock user selecting "Advanced" settings @@ -450,7 +450,7 @@ class TestHandleSettingsCommand: @patch('openhands.cli.commands.display_settings') @patch('openhands.cli.commands.cli_confirm') async def test_settings_go_back(self, mock_cli_confirm, mock_display_settings): - config = MagicMock(spec=AppConfig) + config = MagicMock(spec=OpenHandsConfig) settings_store = MagicMock(spec=FileSettingsStore) # Mock user selecting "Go back" diff --git a/tests/unit/test_cli_settings.py b/tests/unit/test_cli_settings.py index 7fd3840477..15602cda93 100644 --- a/tests/unit/test_cli_settings.py +++ b/tests/unit/test_cli_settings.py @@ -10,7 +10,7 @@ from openhands.cli.settings import ( modify_llm_settings_basic, ) from openhands.cli.tui import UserCancelledError -from openhands.core.config import AppConfig +from openhands.core.config import OpenHandsConfig from openhands.storage.data_models.settings import Settings from openhands.storage.settings.file_settings_store import FileSettingsStore @@ -30,7 +30,7 @@ class MockNoOpCondenserConfig: class TestDisplaySettings: @pytest.fixture def app_config(self): - config = MagicMock(spec=AppConfig) + config = MagicMock(spec=OpenHandsConfig) llm_config = MagicMock() llm_config.base_url = None llm_config.model = 'openai/gpt-4' @@ -48,7 +48,7 @@ class TestDisplaySettings: @pytest.fixture def advanced_app_config(self): - config = MagicMock(spec=AppConfig) + config = MagicMock(spec=OpenHandsConfig) llm_config = MagicMock() llm_config.base_url = 'https://custom-api.com' llm_config.model = 'custom-model' @@ -114,7 +114,7 @@ class TestDisplaySettings: class TestModifyLLMSettingsBasic: @pytest.fixture def app_config(self): - config = MagicMock(spec=AppConfig) + config = MagicMock(spec=OpenHandsConfig) llm_config = MagicMock() llm_config.model = 'openai/gpt-4' llm_config.api_key = SecretStr('test-api-key') @@ -313,7 +313,7 @@ class TestModifyLLMSettingsBasic: class TestModifyLLMSettingsAdvanced: @pytest.fixture def app_config(self): - config = MagicMock(spec=AppConfig) + config = MagicMock(spec=OpenHandsConfig) llm_config = MagicMock() llm_config.model = 'custom-model' llm_config.api_key = SecretStr('test-api-key') diff --git a/tests/unit/test_cli_tui.py b/tests/unit/test_cli_tui.py index 71c23a328d..c3b23131d6 100644 --- a/tests/unit/test_cli_tui.py +++ b/tests/unit/test_cli_tui.py @@ -18,7 +18,7 @@ from openhands.cli.tui import ( get_session_duration, read_confirmation_input, ) -from openhands.core.config import AppConfig +from openhands.core.config import OpenHandsConfig from openhands.events import EventSource from openhands.events.action import ( Action, @@ -74,7 +74,7 @@ class TestDisplayFunctions: @patch('openhands.cli.tui.display_message') def test_display_event_message_action(self, mock_display_message): - config = MagicMock(spec=AppConfig) + config = MagicMock(spec=OpenHandsConfig) message = MessageAction(content='Test message') message._source = EventSource.AGENT @@ -84,7 +84,7 @@ class TestDisplayFunctions: @patch('openhands.cli.tui.display_command') def test_display_event_cmd_action(self, mock_display_command): - config = MagicMock(spec=AppConfig) + config = MagicMock(spec=OpenHandsConfig) cmd_action = CmdRunAction(command='echo test') display_event(cmd_action, config) @@ -93,7 +93,7 @@ class TestDisplayFunctions: @patch('openhands.cli.tui.display_command_output') def test_display_event_cmd_output(self, mock_display_output): - config = MagicMock(spec=AppConfig) + config = MagicMock(spec=OpenHandsConfig) cmd_output = CmdOutputObservation(content='Test output', command='echo test') display_event(cmd_output, config) @@ -102,7 +102,7 @@ class TestDisplayFunctions: @patch('openhands.cli.tui.display_file_edit') def test_display_event_file_edit_observation(self, mock_display_file_edit): - config = MagicMock(spec=AppConfig) + config = MagicMock(spec=OpenHandsConfig) file_edit_obs = FileEditObservation(path='test.py', content="print('hello')") display_event(file_edit_obs, config) @@ -111,7 +111,7 @@ class TestDisplayFunctions: @patch('openhands.cli.tui.display_file_read') def test_display_event_file_read(self, mock_display_file_read): - config = MagicMock(spec=AppConfig) + config = MagicMock(spec=OpenHandsConfig) file_read = FileReadObservation(path='test.py', content="print('hello')") display_event(file_read, config) @@ -120,7 +120,7 @@ class TestDisplayFunctions: @patch('openhands.cli.tui.display_message') def test_display_event_thought(self, mock_display_message): - config = MagicMock(spec=AppConfig) + config = MagicMock(spec=OpenHandsConfig) action = Action() action.thought = 'Thinking about this...' diff --git a/tests/unit/test_cli_workspace.py b/tests/unit/test_cli_workspace.py index 6360fbd296..2dbb30973b 100644 --- a/tests/unit/test_cli_workspace.py +++ b/tests/unit/test_cli_workspace.py @@ -5,7 +5,7 @@ import tempfile import pytest -from openhands.core.config import AppConfig +from openhands.core.config import OpenHandsConfig from openhands.core.exceptions import LLMMalformedActionError from openhands.events import EventStream from openhands.runtime.impl.cli.cli_runtime import CLIRuntime @@ -24,7 +24,7 @@ def cli_runtime(temp_dir): """Create a CLIRuntime instance for testing.""" file_store = get_file_store('local', temp_dir) event_stream = EventStream('test', file_store) - config = AppConfig() + config = OpenHandsConfig() config.workspace_base = temp_dir runtime = CLIRuntime(config, event_stream) runtime._runtime_initialized = True # Skip initialization diff --git a/tests/unit/test_config.py b/tests/unit/test_config.py index 92c8a8dbfc..23e9a75077 100644 --- a/tests/unit/test_config.py +++ b/tests/unit/test_config.py @@ -6,14 +6,14 @@ import pytest from openhands.core.config import ( AgentConfig, - AppConfig, LLMConfig, + OpenHandsConfig, finalize_config, get_agent_config_arg, get_llm_config_arg, - load_app_config, load_from_env, load_from_toml, + load_openhands_config, ) from openhands.core.config.condenser_config import ( LLMSummarizingCondenserConfig, @@ -48,8 +48,8 @@ def temp_toml_file(tmp_path): @pytest.fixture def default_config(monkeypatch): - # Fixture to provide a default AppConfig instance - yield AppConfig() + # Fixture to provide a default OpenHandsConfig instance + yield OpenHandsConfig() def test_compat_env_to_config(monkeypatch, setup_env): @@ -60,7 +60,7 @@ def test_compat_env_to_config(monkeypatch, setup_env): monkeypatch.setenv('DEFAULT_AGENT', 'CodeActAgent') monkeypatch.setenv('SANDBOX_TIMEOUT', '10') - config = AppConfig() + config = OpenHandsConfig() load_from_env(config, os.environ) finalize_config(config) @@ -413,7 +413,7 @@ def test_defaults_dict_after_updates(default_config): assert initial_defaults['workspace_mount_path']['default'] is None assert initial_defaults['default_agent']['default'] == 'CodeActAgent' - updated_config = AppConfig() + updated_config = OpenHandsConfig() updated_config.get_llm_config().api_key = 'updated-api-key' updated_config.get_llm_config('llm').api_key = 'updated-api-key' updated_config.get_llm_config_from_agent('agent').api_key = 'updated-api-key' @@ -678,7 +678,7 @@ def test_sandbox_volumes_with_workspace_not_first(default_config): def test_agent_config_condenser_with_no_enabled(): """Test default agent condenser with enable_default_condenser=False.""" - config = AppConfig(enable_default_condenser=False) + config = OpenHandsConfig(enable_default_condenser=False) agent_config = config.get_agent_config() assert isinstance(agent_config.condenser, NoOpCondenserConfig) @@ -986,8 +986,8 @@ def test_api_keys_repr_str(): f"Unexpected attribute '{attr_name}' contains 'token' in AgentConfig" ) - # Test AppConfig - app_config = AppConfig( + # Test OpenHandsConfig + app_config = OpenHandsConfig( llms={'llm': llm_config}, agents={'agent': agent_config}, e2b_api_key='my_e2b_api_key', @@ -1010,7 +1010,7 @@ def test_api_keys_repr_str(): assert 'my_daytona_api_key' not in repr(app_config) assert 'my_daytona_api_key' not in str(app_config) - # Check that no other attrs in AppConfig have 'key' or 'token' in their name + # Check that no other attrs in OpenHandsConfig have 'key' or 'token' in their name # This will fail when new attrs are added, and attract attention known_key_token_attrs_app = [ 'e2b_api_key', @@ -1020,16 +1020,16 @@ def test_api_keys_repr_str(): 'daytona_api_key', 'search_api_key', ] - for attr_name in AppConfig.model_fields.keys(): + for attr_name in OpenHandsConfig.model_fields.keys(): if ( not attr_name.startswith('__') and attr_name not in known_key_token_attrs_app ): assert 'key' not in attr_name.lower(), ( - f"Unexpected attribute '{attr_name}' contains 'key' in AppConfig" + f"Unexpected attribute '{attr_name}' contains 'key' in OpenHandsConfig" ) assert 'token' not in attr_name.lower() or 'tokens' in attr_name.lower(), ( - f"Unexpected attribute '{attr_name}' contains 'token' in AppConfig" + f"Unexpected attribute '{attr_name}' contains 'token' in OpenHandsConfig" ) @@ -1040,7 +1040,7 @@ max_iterations = 42 max_budget_per_task = 4.7 """ - config = AppConfig() + config = OpenHandsConfig() with open(temp_toml_file, 'w') as f: f.write(temp_toml) @@ -1138,7 +1138,7 @@ enable_prompt_extensions = false f.write(temp_toml) # just a sanity check that load app config wouldn't fail - app_config = load_app_config(config_file=temp_toml_file) + app_config = load_openhands_config(config_file=temp_toml_file) assert app_config.max_iterations == 99 # run_infer in evaluation can use `get_agent_config_arg` to load custom diff --git a/tests/unit/test_config_dict_casting.py b/tests/unit/test_config_dict_casting.py index eaf0aeabef..bcc6c0c457 100644 --- a/tests/unit/test_config_dict_casting.py +++ b/tests/unit/test_config_dict_casting.py @@ -2,7 +2,7 @@ import os import pytest -from openhands.core.config import AppConfig, load_from_env +from openhands.core.config import OpenHandsConfig, load_from_env def test_load_from_env_with_dict(monkeypatch, default_config): @@ -35,5 +35,5 @@ def test_load_from_env_with_dict(monkeypatch, default_config): @pytest.fixture def default_config(): - # Fixture to provide a default AppConfig instance - yield AppConfig() + # Fixture to provide a default OpenHandsConfig instance + yield OpenHandsConfig() diff --git a/tests/unit/test_config_extended.py b/tests/unit/test_config_extended.py index eb579db31f..0ee5fcfe87 100644 --- a/tests/unit/test_config_extended.py +++ b/tests/unit/test_config_extended.py @@ -2,8 +2,8 @@ import os import pytest -from openhands.core.config.app_config import AppConfig from openhands.core.config.extended_config import ExtendedConfig +from openhands.core.config.openhands_config import OpenHandsConfig from openhands.core.config.utils import load_from_toml @@ -83,7 +83,7 @@ def test_extended_config_invalid_key(): def test_app_config_extended_from_toml(tmp_path: os.PathLike) -> None: """Test that the [extended] section in a TOML file is correctly loaded. - This test verifies that the [extended] section is loaded into AppConfig.extended + This test verifies that the [extended] section is loaded into OpenHandsConfig.extended and that it accepts arbitrary keys. """ # Create a temporary TOML file with multiple sections including [extended] @@ -106,8 +106,8 @@ enable_prompt_extensions = true config_file = tmp_path / 'config.toml' config_file.write_text(config_content) - # Load the TOML into the AppConfig instance - config = AppConfig() + # Load the TOML into the OpenHandsConfig instance + config = OpenHandsConfig() load_from_toml(config, str(config_file)) # Verify that extended section is applied @@ -121,7 +121,7 @@ def test_app_config_extended_default(tmp_path: os.PathLike) -> None: """Test default behavior when no [extended] section exists. This test verifies that if there is no [extended] section in the TOML file, - AppConfig.extended remains its default (empty) ExtendedConfig. + OpenHandsConfig.extended remains its default (empty) ExtendedConfig. """ config_content = """ [core] @@ -137,7 +137,7 @@ enable_prompt_extensions = true config_file = tmp_path / 'config.toml' config_file.write_text(config_content) - config = AppConfig() + config = OpenHandsConfig() load_from_toml(config, str(config_file)) # Extended config should be empty @@ -161,7 +161,7 @@ another_key = 3.14 config_file = tmp_path / 'config.toml' config_file.write_text(config_content) - config = AppConfig() + config = OpenHandsConfig() load_from_toml(config, str(config_file)) # Verify that extended config holds the arbitrary keys with correct values. diff --git a/tests/unit/test_conversation.py b/tests/unit/test_conversation.py index 4aca4b9dad..dae39f3475 100644 --- a/tests/unit/test_conversation.py +++ b/tests/unit/test_conversation.py @@ -46,7 +46,7 @@ def _patch_store(): get_conversation_metadata_filename('some_conversation_id'), json.dumps( { - 'title': 'Some Conversation', + 'title': 'Some ServerConversation', 'selected_repository': 'foobar', 'conversation_id': 'some_conversation_id', 'user_id': '12345', @@ -140,7 +140,7 @@ async def test_search_conversations(): results=[ ConversationMetadata( conversation_id='some_conversation_id', - title='Some Conversation', + title='Some ServerConversation', created_at=datetime.fromisoformat( '2025-01-01T00:00:00+00:00' ), @@ -164,7 +164,7 @@ async def test_search_conversations(): results=[ ConversationInfo( conversation_id='some_conversation_id', - title='Some Conversation', + title='Some ServerConversation', created_at=datetime.fromisoformat( '2025-01-01T00:00:00+00:00' ), @@ -189,7 +189,7 @@ async def test_get_conversation(): mock_store.get_metadata = AsyncMock( return_value=ConversationMetadata( conversation_id='some_conversation_id', - title='Some Conversation', + title='Some ServerConversation', created_at=datetime.fromisoformat('2025-01-01T00:00:00+00:00'), last_updated_at=datetime.fromisoformat('2025-01-01T00:01:00+00:00'), selected_repository='foobar', @@ -211,7 +211,7 @@ async def test_get_conversation(): expected = ConversationInfo( conversation_id='some_conversation_id', - title='Some Conversation', + title='Some ServerConversation', created_at=datetime.fromisoformat('2025-01-01T00:00:00+00:00'), last_updated_at=datetime.fromisoformat('2025-01-01T00:01:00+00:00'), status=ConversationStatus.STOPPED, @@ -418,7 +418,7 @@ async def test_delete_conversation(): mock_store.get_metadata = AsyncMock( return_value=ConversationMetadata( conversation_id='some_conversation_id', - title='Some Conversation', + title='Some ServerConversation', created_at=datetime.fromisoformat('2025-01-01T00:00:00+00:00'), last_updated_at=datetime.fromisoformat('2025-01-01T00:01:00+00:00'), selected_repository='foobar', diff --git a/tests/unit/test_docker_runtime.py b/tests/unit/test_docker_runtime.py index 7f80d11943..de0581ee18 100644 --- a/tests/unit/test_docker_runtime.py +++ b/tests/unit/test_docker_runtime.py @@ -2,7 +2,7 @@ from unittest.mock import MagicMock, patch import pytest -from openhands.core.config import AppConfig +from openhands.core.config import OpenHandsConfig from openhands.events import EventStream from openhands.runtime.impl.docker.docker_runtime import DockerRuntime @@ -30,7 +30,7 @@ def mock_docker_client(): @pytest.fixture def config(): - config = AppConfig() + config = OpenHandsConfig() config.sandbox.keep_runtime_alive = False return config diff --git a/tests/unit/test_file_conversation_store.py b/tests/unit/test_file_conversation_store.py index c7daadae6b..8ec3b2c1b8 100644 --- a/tests/unit/test_file_conversation_store.py +++ b/tests/unit/test_file_conversation_store.py @@ -108,7 +108,7 @@ async def test_search_pagination(): 'conversation_id': f'conv{i}', 'user_id': '123', 'selected_repository': 'repo1', - 'title': f'Conversation {i}', + 'title': f'ServerConversation {i}', 'created_at': f'2025-01-{15 + i}T19:51:04Z', } ) diff --git a/tests/unit/test_file_settings_store.py b/tests/unit/test_file_settings_store.py index 5544aa9cf5..94c6f70277 100644 --- a/tests/unit/test_file_settings_store.py +++ b/tests/unit/test_file_settings_store.py @@ -2,7 +2,7 @@ from unittest.mock import MagicMock, patch import pytest -from openhands.core.config.app_config import AppConfig +from openhands.core.config.openhands_config import OpenHandsConfig from openhands.storage.data_models.settings import Settings from openhands.storage.files import FileStore from openhands.storage.settings.file_settings_store import FileSettingsStore @@ -21,8 +21,8 @@ def file_settings_store(mock_file_store): @pytest.mark.asyncio async def test_load_nonexistent_data(file_settings_store): with patch( - 'openhands.storage.data_models.settings.load_app_config', - MagicMock(return_value=AppConfig()), + 'openhands.storage.data_models.settings.load_openhands_config', + MagicMock(return_value=OpenHandsConfig()), ): file_settings_store.file_store.read.side_effect = FileNotFoundError() assert await file_settings_store.load() is None @@ -74,7 +74,7 @@ async def test_store_and_load_data(file_settings_store): @pytest.mark.asyncio async def test_get_instance(): - config = AppConfig(file_store='local', file_store_path='/test/path') + config = OpenHandsConfig(file_store='local', file_store_path='/test/path') with patch( 'openhands.storage.settings.file_settings_store.get_file_store' diff --git a/tests/unit/test_io.py b/tests/unit/test_io.py index 3931f2fdd7..1449df8517 100644 --- a/tests/unit/test_io.py +++ b/tests/unit/test_io.py @@ -1,12 +1,12 @@ from unittest.mock import patch -from openhands.core.config import AppConfig +from openhands.core.config import OpenHandsConfig from openhands.io import read_input def test_single_line_input(): """Test that single line input works when cli_multiline_input is False""" - config = AppConfig() + config = OpenHandsConfig() config.cli_multiline_input = False with patch('builtins.input', return_value='hello world'): @@ -16,7 +16,7 @@ def test_single_line_input(): def test_multiline_input(): """Test that multiline input works when cli_multiline_input is True""" - config = AppConfig() + config = OpenHandsConfig() config.cli_multiline_input = True # Simulate multiple lines of input followed by /exit diff --git a/tests/unit/test_listen.py b/tests/unit/test_listen.py index dfda6d6437..f740af7622 100644 --- a/tests/unit/test_listen.py +++ b/tests/unit/test_listen.py @@ -1,6 +1,6 @@ from unittest.mock import patch -from openhands.core.config import AppConfig +from openhands.core.config import OpenHandsConfig # Mock StaticFiles @@ -20,7 +20,7 @@ with ( def test_load_file_upload_config(): - config = AppConfig( + config = OpenHandsConfig( file_uploads_max_file_size_mb=10, file_uploads_restrict_file_types=True, file_uploads_allowed_extensions=['.txt', '.pdf'], @@ -33,7 +33,7 @@ def test_load_file_upload_config(): def test_load_file_upload_config_invalid_max_size(): - config = AppConfig( + config = OpenHandsConfig( file_uploads_max_file_size_mb=-5, file_uploads_restrict_file_types=False, file_uploads_allowed_extensions=[], diff --git a/tests/unit/test_llm_config.py b/tests/unit/test_llm_config.py index 17fb0e9f6e..6aa6164d28 100644 --- a/tests/unit/test_llm_config.py +++ b/tests/unit/test_llm_config.py @@ -2,14 +2,14 @@ import pathlib import pytest -from openhands.core.config import AppConfig +from openhands.core.config import OpenHandsConfig from openhands.core.config.utils import load_from_toml @pytest.fixture def default_config(monkeypatch): - # Fixture to provide a default AppConfig instance - yield AppConfig() + # Fixture to provide a default OpenHandsConfig instance + yield OpenHandsConfig() @pytest.fixture @@ -48,7 +48,7 @@ api_key = "custom-api-key-3" def test_load_from_toml_llm_with_fallback( - default_config: AppConfig, generic_llm_toml: str + default_config: OpenHandsConfig, generic_llm_toml: str ) -> None: """Test that custom LLM configurations fallback non-overridden attributes like 'num_retries' from the generic [llm] section. @@ -81,7 +81,7 @@ def test_load_from_toml_llm_with_fallback( def test_load_from_toml_llm_custom_overrides_all( - default_config: AppConfig, tmp_path: pathlib.Path + default_config: OpenHandsConfig, tmp_path: pathlib.Path ) -> None: """Test that a custom LLM can fully override all attributes from the generic [llm] section.""" toml_content = """ @@ -117,7 +117,7 @@ num_retries = 10 def test_load_from_toml_llm_custom_partial_override( - default_config: AppConfig, generic_llm_toml: str + default_config: OpenHandsConfig, generic_llm_toml: str ) -> None: """Test that custom LLM configurations can partially override attributes from the generic [llm] section while inheriting others. @@ -138,7 +138,7 @@ def test_load_from_toml_llm_custom_partial_override( def test_load_from_toml_llm_custom_no_override( - default_config: AppConfig, generic_llm_toml: str + default_config: OpenHandsConfig, generic_llm_toml: str ) -> None: """Test that custom LLM configurations with no additional overrides inherit all non-specified attributes from the generic [llm] section. @@ -153,7 +153,7 @@ def test_load_from_toml_llm_custom_no_override( def test_load_from_toml_llm_missing_generic( - default_config: AppConfig, tmp_path: pathlib.Path + default_config: OpenHandsConfig, tmp_path: pathlib.Path ) -> None: """Test that custom LLM configurations without a generic [llm] section use only their own attributes and fallback to defaults for others. @@ -179,7 +179,7 @@ api_key = "custom-only-api-key" def test_load_from_toml_llm_invalid_config( - default_config: AppConfig, tmp_path: pathlib.Path + default_config: OpenHandsConfig, tmp_path: pathlib.Path ) -> None: """Test that invalid custom LLM configurations do not override the generic and raise appropriate warnings. @@ -215,7 +215,7 @@ unknown_attr = "should_not_exist" def test_azure_model_api_version( - default_config: AppConfig, tmp_path: pathlib.Path + default_config: OpenHandsConfig, tmp_path: pathlib.Path ) -> None: """Test that Azure models get the correct API version by default.""" toml_content = """ diff --git a/tests/unit/test_llm_draft_config.py b/tests/unit/test_llm_draft_config.py index f5ba838a17..302cc2b37a 100644 --- a/tests/unit/test_llm_draft_config.py +++ b/tests/unit/test_llm_draft_config.py @@ -2,7 +2,7 @@ import pathlib import pytest -from openhands.core.config import AppConfig +from openhands.core.config import OpenHandsConfig from openhands.core.config.utils import load_from_toml @@ -63,7 +63,7 @@ def test_no_draft_editor_in_config(config_toml_without_draft_editor): Previously, we tested fallback behavior. Now, it's simplified to not exist at all. This docstring remains to illustrate that the old fallback logic is removed. """ - config = AppConfig() + config = OpenHandsConfig() # Load config from TOML load_from_toml(config, config_toml_without_draft_editor) @@ -77,7 +77,7 @@ def test_draft_editor_as_named_llm(config_toml_with_draft_editor): Test that draft_editor is loaded if declared in the TOML under [llm.draft_editor]. This docstring references the simpler approach: if it exists, it's just another named LLM. """ - config = AppConfig() + config = OpenHandsConfig() load_from_toml(config, config_toml_with_draft_editor) # draft_editor should appear as a normal named LLM @@ -96,7 +96,7 @@ def test_draft_editor_fallback(config_toml_with_draft_editor): We expect the 'draft_editor' LLM to behave just like any custom LLM would. """ - config = AppConfig() + config = OpenHandsConfig() load_from_toml(config, config_toml_with_draft_editor) # Check that the normal default fields come from LLMConfig where not overridden diff --git a/tests/unit/test_logging.py b/tests/unit/test_logging.py index 4698637cfd..7055f69b18 100644 --- a/tests/unit/test_logging.py +++ b/tests/unit/test_logging.py @@ -5,7 +5,7 @@ from unittest.mock import patch import pytest -from openhands.core.config import AppConfig, LLMConfig +from openhands.core.config import LLMConfig, OpenHandsConfig from openhands.core.logger import OpenHandsLoggerAdapter, json_log_handler from openhands.core.logger import openhands_logger as openhands_logger @@ -84,7 +84,7 @@ def test_llm_config_attributes_masking(test_handler): def test_app_config_attributes_masking(test_handler): logger, stream = test_handler - app_config = AppConfig(e2b_api_key='e2b-xyz789') + app_config = OpenHandsConfig(e2b_api_key='e2b-xyz789') logger.info(f'App Config: {app_config}') log_output = stream.getvalue() assert 'github_token' not in log_output diff --git a/tests/unit/test_memory.py b/tests/unit/test_memory.py index c4897a4475..1e1fd108ee 100644 --- a/tests/unit/test_memory.py +++ b/tests/unit/test_memory.py @@ -8,7 +8,7 @@ import pytest from openhands.controller.agent import Agent from openhands.controller.agent_controller import AgentController -from openhands.core.config import AppConfig +from openhands.core.config import OpenHandsConfig from openhands.core.main import run_controller from openhands.core.schema.agent import AgentState from openhands.events.action.agent import RecallAction @@ -75,7 +75,7 @@ def mock_agent(): agent = MagicMock(spec=Agent) agent.llm = MagicMock(spec=LLM) agent.llm.metrics = Metrics() - agent.llm.config = AppConfig().get_llm_config() + agent.llm.config = OpenHandsConfig().get_llm_config() # Add a proper system message mock system_message = SystemMessageAction(content='Test system message') @@ -101,7 +101,7 @@ async def test_memory_on_event_exception_handling(memory, event_stream, mock_age memory, '_on_workspace_context_recall', side_effect=Exception('Test error') ): state = await run_controller( - config=AppConfig(), + config=OpenHandsConfig(), initial_user_action=MessageAction(content='Test message'), runtime=runtime, sid='test', @@ -132,7 +132,7 @@ async def test_memory_on_workspace_context_recall_exception_handling( side_effect=Exception('Test error from _find_microagent_knowledge'), ): state = await run_controller( - config=AppConfig(), + config=OpenHandsConfig(), initial_user_action=MessageAction(content='Test message'), runtime=runtime, sid='test', @@ -626,7 +626,7 @@ async def test_conversation_instructions_plumbed_to_memory( ): await session.start( runtime_name='test-runtime', - config=AppConfig(), + config=OpenHandsConfig(), agent=mock_agent, max_iterations=10, conversation_instructions='instructions for conversation', diff --git a/tests/unit/test_runtime_git_tokens.py b/tests/unit/test_runtime_git_tokens.py index 8a3f6f4c26..d88fe1712b 100644 --- a/tests/unit/test_runtime_git_tokens.py +++ b/tests/unit/test_runtime_git_tokens.py @@ -4,7 +4,7 @@ from unittest.mock import MagicMock, patch import pytest from pydantic import SecretStr -from openhands.core.config import AppConfig +from openhands.core.config import OpenHandsConfig from openhands.core.config.mcp_config import MCPConfig, MCPStdioServerConfig from openhands.events.action import Action from openhands.events.action.commands import CmdRunAction @@ -83,7 +83,7 @@ def temp_dir(tmp_path_factory: pytest.TempPathFactory) -> str: @pytest.fixture def runtime(temp_dir): """Fixture for runtime testing""" - config = AppConfig() + config = OpenHandsConfig() git_provider_tokens = MappingProxyType( {ProviderType.GITHUB: ProviderToken(token=SecretStr('test_token'))} ) @@ -116,7 +116,7 @@ def mock_repo_and_patch(monkeypatch, provider=ProviderType.GITHUB, is_public=Tru @pytest.mark.asyncio async def test_export_latest_git_provider_tokens_no_user_id(temp_dir): """Test that no token export happens when user_id is not set""" - config = AppConfig() + config = OpenHandsConfig() file_store = get_file_store('local', temp_dir) event_stream = EventStream('abc', file_store) runtime = TestRuntime(config=config, event_stream=event_stream, sid='test') @@ -134,7 +134,7 @@ async def test_export_latest_git_provider_tokens_no_user_id(temp_dir): @pytest.mark.asyncio async def test_export_latest_git_provider_tokens_no_token_ref(temp_dir): """Test that no token export happens when command doesn't reference tokens""" - config = AppConfig() + config = OpenHandsConfig() file_store = get_file_store('local', temp_dir) event_stream = EventStream('abc', file_store) runtime = TestRuntime( @@ -167,7 +167,7 @@ async def test_export_latest_git_provider_tokens_success(runtime): @pytest.mark.asyncio async def test_export_latest_git_provider_tokens_multiple_refs(temp_dir): """Test token export with multiple token references""" - config = AppConfig() + config = OpenHandsConfig() # Initialize with both GitHub and GitLab tokens git_provider_tokens = MappingProxyType( { @@ -221,7 +221,7 @@ async def test_export_latest_git_provider_tokens_token_update(runtime): @pytest.mark.asyncio async def test_clone_or_init_repo_no_repo_with_user_id(temp_dir): """Test that git init is run when no repository is selected and user_id is set""" - config = AppConfig() + config = OpenHandsConfig() file_store = get_file_store('local', temp_dir) event_stream = EventStream('abc', file_store) runtime = TestRuntime( @@ -241,7 +241,7 @@ async def test_clone_or_init_repo_no_repo_with_user_id(temp_dir): @pytest.mark.asyncio async def test_clone_or_init_repo_no_repo_no_user_id_no_workspace_base(temp_dir): """Test that git init is run when no repository is selected, no user_id, and no workspace_base""" - config = AppConfig() + config = OpenHandsConfig() config.workspace_base = None # Ensure workspace_base is not set file_store = get_file_store('local', temp_dir) event_stream = EventStream('abc', file_store) @@ -262,7 +262,7 @@ async def test_clone_or_init_repo_no_repo_no_user_id_no_workspace_base(temp_dir) @pytest.mark.asyncio async def test_clone_or_init_repo_no_repo_no_user_id_with_workspace_base(temp_dir): """Test that git init is not run when no repository is selected, no user_id, but workspace_base is set""" - config = AppConfig() + config = OpenHandsConfig() config.workspace_base = '/some/path' # Set workspace_base file_store = get_file_store('local', temp_dir) event_stream = EventStream('abc', file_store) @@ -281,7 +281,7 @@ async def test_clone_or_init_repo_no_repo_no_user_id_with_workspace_base(temp_di @pytest.mark.asyncio async def test_clone_or_init_repo_auth_error(temp_dir): """Test that RuntimeError is raised when authentication fails""" - config = AppConfig() + config = OpenHandsConfig() file_store = get_file_store('local', temp_dir) event_stream = EventStream('abc', file_store) runtime = TestRuntime( @@ -306,7 +306,7 @@ async def test_clone_or_init_repo_auth_error(temp_dir): @pytest.mark.asyncio async def test_clone_or_init_repo_github_with_token(temp_dir, monkeypatch): - config = AppConfig() + config = OpenHandsConfig() file_store = get_file_store('local', temp_dir) event_stream = EventStream('abc', file_store) @@ -335,7 +335,7 @@ async def test_clone_or_init_repo_github_with_token(temp_dir, monkeypatch): @pytest.mark.asyncio async def test_clone_or_init_repo_github_no_token(temp_dir, monkeypatch): """Test cloning a GitHub repository without a token""" - config = AppConfig() + config = OpenHandsConfig() file_store = get_file_store('local', temp_dir) event_stream = EventStream('abc', file_store) @@ -360,7 +360,7 @@ async def test_clone_or_init_repo_github_no_token(temp_dir, monkeypatch): @pytest.mark.asyncio async def test_clone_or_init_repo_gitlab_with_token(temp_dir, monkeypatch): - config = AppConfig() + config = OpenHandsConfig() file_store = get_file_store('local', temp_dir) event_stream = EventStream('abc', file_store) @@ -391,7 +391,7 @@ async def test_clone_or_init_repo_gitlab_with_token(temp_dir, monkeypatch): @pytest.mark.asyncio async def test_clone_or_init_repo_with_branch(temp_dir, monkeypatch): """Test cloning a repository with a specified branch""" - config = AppConfig() + config = OpenHandsConfig() file_store = get_file_store('local', temp_dir) event_stream = EventStream('abc', file_store) diff --git a/tests/unit/test_search_utils.py b/tests/unit/test_search_utils.py index 8417ebb4b2..06f315b5f4 100644 --- a/tests/unit/test_search_utils.py +++ b/tests/unit/test_search_utils.py @@ -90,7 +90,7 @@ async def test_iterate_multiple_pages(): 'github_user_id': '123', 'user_id': '123', 'selected_repository': 'repo1', - 'title': f'Conversation {i}', + 'title': f'ServerConversation {i}', 'created_at': f'2025-01-{15 + i}T19:51:04Z', } ) diff --git a/tests/unit/test_session.py b/tests/unit/test_session.py index 7f61e66f01..b14dc82a4b 100644 --- a/tests/unit/test_session.py +++ b/tests/unit/test_session.py @@ -5,8 +5,8 @@ from litellm.exceptions import ( RateLimitError, ) -from openhands.core.config.app_config import AppConfig from openhands.core.config.llm_config import LLMConfig +from openhands.core.config.openhands_config import OpenHandsConfig from openhands.server.session.session import Session from openhands.storage.memory import InMemoryFileStore @@ -37,7 +37,7 @@ def default_llm_config(): async def test_notify_on_llm_retry( mock_litellm_completion, mock_sio, default_llm_config ): - config = AppConfig() + config = OpenHandsConfig() config.set_llm_config(default_llm_config) session = Session( sid='..sid..', diff --git a/tests/unit/test_settings.py b/tests/unit/test_settings.py index c74e3982cb..aacc431dbd 100644 --- a/tests/unit/test_settings.py +++ b/tests/unit/test_settings.py @@ -2,8 +2,8 @@ from unittest.mock import patch from pydantic import SecretStr -from openhands.core.config.app_config import AppConfig from openhands.core.config.llm_config import LLMConfig +from openhands.core.config.openhands_config import OpenHandsConfig from openhands.core.config.sandbox_config import SandboxConfig from openhands.core.config.security_config import SecurityConfig from openhands.server.routes.settings import convert_to_settings @@ -12,7 +12,7 @@ from openhands.storage.data_models.settings import Settings def test_settings_from_config(): # Mock configuration - mock_app_config = AppConfig( + mock_app_config = OpenHandsConfig( default_agent='test-agent', max_iterations=100, security=SecurityConfig( @@ -29,7 +29,7 @@ def test_settings_from_config(): ) with patch( - 'openhands.storage.data_models.settings.load_app_config', + 'openhands.storage.data_models.settings.load_openhands_config', return_value=mock_app_config, ): settings = Settings.from_config() @@ -49,7 +49,7 @@ def test_settings_from_config(): def test_settings_from_config_no_api_key(): # Mock configuration without API key - mock_app_config = AppConfig( + mock_app_config = OpenHandsConfig( default_agent='test-agent', max_iterations=100, security=SecurityConfig( @@ -64,7 +64,7 @@ def test_settings_from_config_no_api_key(): ) with patch( - 'openhands.storage.data_models.settings.load_app_config', + 'openhands.storage.data_models.settings.load_openhands_config', return_value=mock_app_config, ): settings = Settings.from_config() diff --git a/tests/unit/test_standalone_conversation_manager.py b/tests/unit/test_standalone_conversation_manager.py index 7174c6ae3a..5e71cda96b 100644 --- a/tests/unit/test_standalone_conversation_manager.py +++ b/tests/unit/test_standalone_conversation_manager.py @@ -5,7 +5,7 @@ from unittest.mock import AsyncMock, MagicMock, patch import pytest -from openhands.core.config.app_config import AppConfig +from openhands.core.config.openhands_config import OpenHandsConfig from openhands.server.conversation_manager.standalone_conversation_manager import ( StandaloneConversationManager, ) @@ -58,7 +58,7 @@ async def test_init_new_local_session(): ), ): async with StandaloneConversationManager( - sio, AppConfig(), InMemoryFileStore(), MonitoringListener() + sio, OpenHandsConfig(), InMemoryFileStore(), MonitoringListener() ) as conversation_manager: await conversation_manager.maybe_start_agent_loop( 'new-session-id', ConversationInitData(), 1 @@ -102,7 +102,7 @@ async def test_join_local_session(): ), ): async with StandaloneConversationManager( - sio, AppConfig(), InMemoryFileStore(), MonitoringListener() + sio, OpenHandsConfig(), InMemoryFileStore(), MonitoringListener() ) as conversation_manager: await conversation_manager.maybe_start_agent_loop( 'new-session-id', ConversationInitData(), None @@ -150,7 +150,7 @@ async def test_add_to_local_event_stream(): ), ): async with StandaloneConversationManager( - sio, AppConfig(), InMemoryFileStore(), MonitoringListener() + sio, OpenHandsConfig(), InMemoryFileStore(), MonitoringListener() ) as conversation_manager: await conversation_manager.maybe_start_agent_loop( 'new-session-id', ConversationInitData(), 1 @@ -168,7 +168,7 @@ async def test_add_to_local_event_stream(): async def test_cleanup_session_connections(): sio = get_mock_sio() async with StandaloneConversationManager( - sio, AppConfig(), InMemoryFileStore(), MonitoringListener() + sio, OpenHandsConfig(), InMemoryFileStore(), MonitoringListener() ) as conversation_manager: conversation_manager._local_connection_id_to_session_id.update( {