mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-08 03:01:47 +00:00
fixed bug in check terminal requirements for slot pool
This commit is contained in:
parent
62001e3bf5
commit
3951eab399
4 changed files with 41 additions and 19 deletions
|
|
@ -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",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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"]
|
||||||
|
|
|
||||||
|
|
@ -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},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue