Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions codeclash/arenas/cyborg/cyborg.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,20 @@ def validate_code(self, agent: Player) -> tuple[bool, str | None]:
"assert hasattr(module, 'MyAgent'), 'MyAgent class not found'\n"
"from CybORG.Agents import BaseAgent\n"
"assert issubclass(module.MyAgent, BaseAgent), 'MyAgent must inherit from a CybORG BaseAgent class'\n"
"def make_agent(agent_class, agent_name):\n"
" try:\n"
" return agent_class(name=agent_name)\n"
" except TypeError:\n"
" try:\n"
" return agent_class(agent_name)\n"
" except TypeError:\n"
" try:\n"
" return agent_class()\n"
" except TypeError as final_error:\n"
" raise TypeError(\n"
" 'MyAgent could not be constructed with the CybORG runtime constructor fallbacks'\n"
" ) from final_error\n"
"make_agent(module.MyAgent, 'validation-agent')\n"
"PY"
)
if import_check["returncode"] != 0:
Expand Down
61 changes: 61 additions & 0 deletions tests/arenas/test_cyborg.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,67 @@ def test_import_failure(self, mock_player_factory):
assert valid is False
assert "Could not import" in error

def test_validation_instantiates_agent_with_runtime_fallbacks(self, mock_player_factory):
arena = CybORGArena.__new__(CybORGArena)
arena.submission = "cyborg_agent.py"
player = mock_player_factory(
name="Alice",
files={"cyborg_agent.py": "from CybORG.Agents import RandomAgent\nclass MyAgent(RandomAgent):\n pass\n"},
command_outputs={
"test -f cyborg_agent.py && echo exists": {"output": "exists\n", "returncode": 0},
"cat cyborg_agent.py": {
"output": "from CybORG.Agents import RandomAgent\nclass MyAgent(RandomAgent):\n pass\n",
"returncode": 0,
},
"python -m py_compile cyborg_agent.py": {"output": "", "returncode": 0},
},
)

valid, error = arena.validate_code(player)

import_command = player.environment._executed_commands[-1]
assert valid is True
assert error is None
assert "make_agent(module.MyAgent, 'validation-agent')" in import_command

def test_validation_rejects_agent_constructor_failure(self, mock_player_factory):
arena = CybORGArena.__new__(CybORGArena)
arena.submission = "cyborg_agent.py"
player = mock_player_factory(
name="Alice",
files={
"cyborg_agent.py": (
"from CybORG.Agents import RandomAgent\n"
"class MyAgent(RandomAgent):\n"
" def __init__(self, seed=None):\n"
" super().__init__(seed=seed)\n"
)
},
command_outputs={
"test -f cyborg_agent.py && echo exists": {"output": "exists\n", "returncode": 0},
"cat cyborg_agent.py": {
"output": (
"from CybORG.Agents import RandomAgent\n"
"class MyAgent(RandomAgent):\n"
" def __init__(self, seed=None):\n"
" super().__init__(seed=seed)\n"
),
"returncode": 0,
},
"python -m py_compile cyborg_agent.py": {"output": "", "returncode": 0},
"python - <<'PY'": {
"output": "TypeError: RandomAgent.__init__() got an unexpected keyword argument 'seed'",
"returncode": 1,
},
},
)

valid, error = arena.validate_code(player)

assert valid is False
assert "Could not import `MyAgent`" in error
assert "unexpected keyword argument 'seed'" in error


class TestCybORGResults:
def test_parse_winner(self, tmp_log_dir):
Expand Down
Loading