fixed bug in check terminal requirements for slot pool

This commit is contained in:
Shannon Sands 2026-02-10 09:22:22 +00:00
parent 62001e3bf5
commit 3951eab399
4 changed files with 41 additions and 19 deletions

View file

@ -31,8 +31,11 @@ def _require_atroposlib() -> None:
_require_atroposlib() _require_atroposlib()
# Re-export the most commonly used pieces for convenience. # Re-export the most commonly used pieces for convenience.
# Agent imports are eager (always available).
from .agent import AgentConfig, AgentResult, AgentStep, AtroposAgent, SequenceData # noqa: E402 from .agent import AgentConfig, AgentResult, AgentStep, AtroposAgent, SequenceData # noqa: E402
from .envs import AgentEnv, AgentEnvConfig # noqa: E402
# Env imports are lazy to avoid pulling in deleted atropos.tools dependencies.
# Use: from atropos.envs import AgentEnv, AgentEnvConfig (if needed)
__all__ = [ __all__ = [
"AtroposAgent", "AtroposAgent",
@ -40,7 +43,5 @@ __all__ = [
"AgentResult", "AgentResult",
"AgentStep", "AgentStep",
"SequenceData", "SequenceData",
"AgentEnv",
"AgentEnvConfig",
] ]

View file

@ -1,10 +1,18 @@
""" """
Environment implementations for atropos-agent. Environment implementations for atropos-agent.
NOTE: AgentEnv is the OLD environment system, replaced by
environments/hermes_base_env.py (HermesAgentBaseEnv).
Import is lazy to avoid pulling in deleted dependencies.
""" """
from .agent_env import AgentEnv, AgentEnvConfig
# NOTE: Additional example envs exist as modules (e.g. `test_env`, `swe_smith_oracle_env`), def __getattr__(name):
# but are intentionally not imported here to avoid pulling heavy optional deps at import time. """Lazy import to avoid breaking when old dependencies are removed."""
if name in ("AgentEnv", "AgentEnvConfig"):
from .agent_env import AgentEnv, AgentEnvConfig
return {"AgentEnv": AgentEnv, "AgentEnvConfig": AgentEnvConfig}[name]
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
__all__ = ["AgentEnv", "AgentEnvConfig"] __all__ = ["AgentEnv", "AgentEnvConfig"]

View file

@ -332,8 +332,13 @@ class HermesAgentBaseEnv(BaseEnv):
os.environ.setdefault("TERMINAL_NOMAD_MIN", str(self.config.min_containers)) os.environ.setdefault("TERMINAL_NOMAD_MIN", str(self.config.min_containers))
os.environ.setdefault("TERMINAL_NOMAD_MAX", str(self.config.max_containers)) os.environ.setdefault("TERMINAL_NOMAD_MAX", str(self.config.max_containers))
# Eagerly start the _SlotPoolManager so the backend is ready
# before any trajectories try to use it
from tools.terminal_tool import _SlotPoolManager
_SlotPoolManager.get_instance() # Triggers _start() which creates sandboxes
self._sandbox_backend = True # Flag that sandbox mode is active self._sandbox_backend = True # Flag that sandbox mode is active
print(f"🔧 Slot pool configured: TERMINAL_ENV=slot_pool, backend={mode}") print(f"🔧 Slot pool started: TERMINAL_ENV=slot_pool, backend={mode}")
async def _stop_sandbox_backend(self) -> None: async def _stop_sandbox_backend(self) -> None:
"""Stop the slot pool backend.""" """Stop the slot pool backend."""
@ -710,18 +715,27 @@ class HermesAgentBaseEnv(BaseEnv):
logger.info("Sandbox slot acquired for task %s", task_id) logger.info("Sandbox slot acquired for task %s", task_id)
# 2. Create exec_tool for setup/verify hooks # 2. Create exec_tool for setup/verify hooks
# Routes through _SlotPoolManager (same slot as terminal_tool) # Routes through handle_function_call → terminal_tool → same _SlotPoolEnvironment
async def exec_tool(tool_name: str, args: Dict[str, Any], timeout: float = 300) -> _ExecResult: async def exec_tool(tool_name: str, args: Dict[str, Any], timeout: float = 300) -> _ExecResult:
command = args.get("command", "") command = args.get("command", "")
result_dict = _SlotPoolManager.get_instance().execute( result_json = await loop.run_in_executor(
task_id, command, timeout=timeout None,
lambda: handle_function_call(
"terminal",
{"command": command, "timeout": int(timeout)},
task_id=task_id,
),
) )
returncode = result_dict.get("returncode", 1) try:
result_dict = json.loads(result_json)
except (json.JSONDecodeError, TypeError):
result_dict = {"output": str(result_json), "exit_code": 1}
returncode = result_dict.get("exit_code", result_dict.get("returncode", 1))
output = result_dict.get("output", "") output = result_dict.get("output", "")
return _ExecResult( return _ExecResult(
success=(returncode == 0), success=(returncode == 0),
output=output, output=output,
error="" if returncode == 0 else f"Exit code: {returncode}", error=result_dict.get("error", "") if returncode != 0 else "",
metadata={"returncode": returncode}, metadata={"returncode": returncode},
) )

View file

@ -2411,17 +2411,14 @@ def check_terminal_requirements() -> bool:
try: try:
if env_type == "local": if env_type == "local":
from minisweagent.environments.local import LocalEnvironment
return True return True
elif env_type == "docker": elif env_type == "docker":
from minisweagent.environments.docker import DockerEnvironment # check actually available..
# Check if docker is available
import subprocess import subprocess
result = subprocess.run(["docker", "version"], capture_output=True, timeout=5) result = subprocess.run(["docker", "version"], capture_output=True, timeout=5)
return result.returncode == 0 return result.returncode == 0
elif env_type == "singularity": elif env_type == "singularity":
from minisweagent.environments.singularity import SingularityEnvironment # Check if singularity/apptainer is available (doesn't work on mac)
# Check if singularity/apptainer is available
import subprocess import subprocess
import shutil import shutil
executable = shutil.which("apptainer") or shutil.which("singularity") executable = shutil.which("apptainer") or shutil.which("singularity")
@ -2430,9 +2427,11 @@ def check_terminal_requirements() -> bool:
return result.returncode == 0 return result.returncode == 0
return False return False
elif env_type == "modal": elif env_type == "modal":
from minisweagent.environments.extra.swerex_modal import SwerexModalEnvironment # check modal is actually configured
# Check for modal token
return os.getenv("MODAL_TOKEN_ID") is not None or Path.home().joinpath(".modal.toml").exists() return os.getenv("MODAL_TOKEN_ID") is not None or Path.home().joinpath(".modal.toml").exists()
elif env_type == "slot_pool":
# Slot pool uses atropos/backends/ & always available if modal/nomad is configured
return True
else: else:
return False return False
except Exception as e: except Exception as e: