diff --git a/opendevin/runtime/runtime.py b/opendevin/runtime/runtime.py index e3bd0d41a7..77638b7bf5 100644 --- a/opendevin/runtime/runtime.py +++ b/opendevin/runtime/runtime.py @@ -75,10 +75,10 @@ class Runtime: This method should be called after the runtime's constructor. """ logger.debug(f'Adding default env vars: {self.DEFAULT_ENV_VARS}') - await self.add_env_var(self.DEFAULT_ENV_VARS) + await self.add_env_vars(self.DEFAULT_ENV_VARS) if env_vars is not None: logger.debug(f'Adding provided env vars: {env_vars}') - await self.add_env_var(env_vars) + await self.add_env_vars(env_vars) async def close(self) -> None: pass @@ -115,16 +115,20 @@ class Runtime: # ==================================================================== - async def add_env_var(self, vars): + async def add_env_vars(self, env_vars: dict[str, str]) -> None: cmd = '' - for key, value in vars.items(): + for key, value in env_vars.items(): # Note: json.dumps gives us nice escaping for free cmd += f'export {key}={json.dumps(value)}; ' + if not cmd: + return cmd = cmd.strip() logger.debug(f'Adding env var: {cmd}') obs: Observation = await self.run(CmdRunAction(cmd)) if not isinstance(obs, CmdOutputObservation) or obs.exit_code != 0: - raise RuntimeError(f'Failed to add {key} to environment: {obs}') + raise RuntimeError( + f'Failed to add env vars [{env_vars}] to environment: {obs.content}' + ) async def on_event(self, event: Event) -> None: if isinstance(event, Action): diff --git a/tests/unit/test_runtime.py b/tests/unit/test_runtime.py index 0ef9a5413b..368a47cec4 100644 --- a/tests/unit/test_runtime.py +++ b/tests/unit/test_runtime.py @@ -91,7 +91,7 @@ async def test_env_vars_os_environ(): @pytest.mark.asyncio -async def test_env_vars_runtime_add_env_var(): +async def test_env_vars_runtime_add_env_vars(): plugins = [JupyterRequirement(), AgentSkillsRequirement()] sid = 'test' cli_session = 'main_test' @@ -99,7 +99,7 @@ async def test_env_vars_runtime_add_env_var(): for box_class in RUNTIME_TO_TEST: event_stream = EventStream(cli_session) runtime = await _load_runtime(box_class, event_stream, plugins, sid) - await runtime.add_env_var({'QUUX': 'abc"def'}) + await runtime.add_env_vars({'QUUX': 'abc"def'}) obs: CmdOutputObservation = await runtime.run_action( CmdRunAction(command='echo $QUUX') @@ -112,6 +112,32 @@ async def test_env_vars_runtime_add_env_var(): await runtime.close() +@pytest.mark.asyncio +async def test_env_vars_runtime_add_empty_dict(): + plugins = [JupyterRequirement(), AgentSkillsRequirement()] + sid = 'test' + cli_session = 'main_test' + + for box_class in RUNTIME_TO_TEST: + event_stream = EventStream(cli_session) + runtime = await _load_runtime(box_class, event_stream, plugins, sid) + + prev_obs = await runtime.run_action(CmdRunAction(command='env')) + assert prev_obs.exit_code == 0, 'The exit code should be 0.' + print(prev_obs) + + await runtime.add_env_vars({}) + + obs = await runtime.run_action(CmdRunAction(command='env')) + assert obs.exit_code == 0, 'The exit code should be 0.' + print(obs) + assert ( + obs.content == prev_obs.content + ), 'The env var content should be the same after adding an empty dict.' + + await runtime.close() + + @pytest.mark.asyncio async def test_env_vars_runtime_add_multiple_env_vars(): plugins = [JupyterRequirement(), AgentSkillsRequirement()] @@ -121,7 +147,7 @@ async def test_env_vars_runtime_add_multiple_env_vars(): for box_class in RUNTIME_TO_TEST: event_stream = EventStream(cli_session) runtime = await _load_runtime(box_class, event_stream, plugins, sid) - await runtime.add_env_var({'QUUX': 'abc"def', 'FOOBAR': 'xyz'}) + await runtime.add_env_vars({'QUUX': 'abc"def', 'FOOBAR': 'xyz'}) obs: CmdOutputObservation = await runtime.run_action( CmdRunAction(command='echo $QUUX $FOOBAR') @@ -135,7 +161,7 @@ async def test_env_vars_runtime_add_multiple_env_vars(): @pytest.mark.asyncio -async def test_env_vars_runtime_add_env_var_overwrite(): +async def test_env_vars_runtime_add_env_vars_overwrite(): plugins = [JupyterRequirement(), AgentSkillsRequirement()] sid = 'test' cli_session = 'main_test' @@ -144,7 +170,7 @@ async def test_env_vars_runtime_add_env_var_overwrite(): with patch.dict(os.environ, {'SANDBOX_ENV_FOOBAR': 'BAZ'}): event_stream = EventStream(cli_session) runtime = await _load_runtime(box_class, event_stream, plugins, sid) - await runtime.add_env_var({'FOOBAR': 'xyz'}) + await runtime.add_env_vars({'FOOBAR': 'xyz'}) obs: CmdOutputObservation = await runtime.run_action( CmdRunAction(command='echo $FOOBAR')