Skip to content

Commit 28e4a5f

Browse files
committed
Merge branch 'main' into john/ladder
2 parents ca627d1 + d77984c commit 28e4a5f

61 files changed

Lines changed: 2315 additions & 972 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.example

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@
44
# Required: GitHub token with repo access for cloning game repositories
55
GITHUB_TOKEN=your_github_token_here
66

7-
# Optional: LLM Provider API Keys (configure the ones you plan to use)
7+
# LLM provider API keys — set the ones for the models you run (see configs/models.yaml).
8+
# Models are resolved by litellm from their provider-prefixed names.
9+
ANTHROPIC_API_KEY=
810
OPENAI_API_KEY=
9-
ANTHROPIC_API_KEY=
11+
GEMINI_API_KEY=
12+
XAI_API_KEY=
13+
DASHSCOPE_API_KEY=
14+
15+
# Optional: only needed for legacy configs that still set `model_class: portkey`.
16+
PORTKEY_API_KEY=

.github/mlc_config.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,18 @@
1818
{
1919
"pattern": "https://docs\\.codeclash\\.io"
2020
},
21+
{
22+
"pattern": "https://robotrumble\\.org/boards/2"
23+
},
24+
{
25+
"pattern": "https://robocode\\.sourceforge\\.io.*"
26+
},
27+
{
28+
"pattern": "https://huskybench\\.com/.*"
29+
},
30+
{
31+
"pattern": "https://corewar\\.co\\.uk"
32+
},
2133
{
2234
"pattern": "https?://(.*\\.)?twitter\\.com/.*"
2335
},
@@ -26,6 +38,9 @@
2638
},
2739
{
2840
"pattern": "https://www\\.contributor-covenant\\.org/version/2/1/code_of_conduct\\.html"
41+
},
42+
{
43+
"pattern": "https://join\\.slack\\.com/t/swe-bench/shared_invite/.*"
2944
}
3045
]
3146
}

.github/workflows/check-links.yaml

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,29 @@ name: Check Markdown links
22

33
on:
44
workflow_dispatch:
5-
push:
65
pull_request:
76
schedule:
87
- cron: "0 0 1 * *"
98

109
jobs:
11-
markdown-link-check:
10+
markdown-link-check-pr:
11+
if: github.event_name == 'pull_request'
1212
runs-on: ubuntu-latest
1313
steps:
14-
- uses: actions/checkout@master
14+
- uses: actions/checkout@v4
15+
with:
16+
fetch-depth: 0
17+
- uses: gaurav-nelson/github-action-markdown-link-check@v1
18+
with:
19+
config-file: '.github/mlc_config.json'
20+
check-modified-files-only: 'yes'
21+
base-branch: 'main'
22+
23+
markdown-link-check-full:
24+
if: github.event_name == 'workflow_dispatch' || github.event_name == 'schedule'
25+
runs-on: ubuntu-latest
26+
steps:
27+
- uses: actions/checkout@v4
1528
- uses: gaurav-nelson/github-action-markdown-link-check@v1
1629
with:
1730
config-file: '.github/mlc_config.json'

.github/workflows/pre-commit.yaml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: Pre-commit
2+
3+
on:
4+
push:
5+
pull_request:
6+
7+
jobs:
8+
pre-commit:
9+
runs-on: ubuntu-latest
10+
defaults:
11+
run:
12+
shell: bash -l {0}
13+
steps:
14+
- uses: actions/checkout@v5
15+
- uses: actions/setup-python@v5
16+
with:
17+
python-version: "3.11"
18+
- name: Install uv
19+
run: curl -LsSf https://astral.sh/uv/install.sh | sh
20+
- name: Install dependencies
21+
run: uv sync --extra dev
22+
- name: Run pre-commit
23+
run: uv run pre-commit run --all-files --show-diff-on-failure

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ repos:
1515
- id: debug-statements
1616

1717
- repo: https://github.com/crate-ci/typos
18-
rev: v1
18+
rev: v1.46.0
1919
hooks:
2020
- id: typos
2121
files: \.(py|md|rst|yaml|toml)

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,19 @@ Critically, *LMs don't play the game directly*.
9595
Their code serves as their competitive proxy.
9696
The winner is the LM agent who wins the most rounds.
9797

98+
## 🧩 Available Arenas
99+
100+
CodeClash includes competitive programming games and simulation-backed arenas, including BattleSnake,
101+
CoreWar, CybORG, Halite, HuskyBench, RoboCode, RobotRumble, and SCML.
102+
103+
SCML is a supply-chain negotiation arena based on the ANAC Supply Chain Management League OneShot
104+
track. Agents edit a Python `scml_agent.py` implementation and compete to maximize average profit
105+
across multiple simulated supply-chain worlds.
106+
107+
CybORG is a simulated cyber-defense arena based on the CAGE Challenge 3 DroneSwarm scenario. Agents
108+
edit a Python `cyborg_agent.py` implementation and compete to maximize blue-team reward across
109+
simulated episodes.
110+
98111
## 🚀 Get Involved
99112

100113
- Check out our [docs](https://docs.codeclash.ai/) for more details on running different arenas, configuring tournaments, etc.

codeclash/agents/minisweagent.py

Lines changed: 14 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,9 @@
33
import traceback
44
from collections.abc import Callable
55

6-
from minisweagent import Model
76
from minisweagent.agents.default import AgentConfig, DefaultAgent
87
from minisweagent.environments.docker import DockerEnvironment
9-
from minisweagent.models import get_model
10-
from minisweagent.models.test_models import DeterministicModel
11-
from minisweagent.run.utils.save import save_traj
8+
from minisweagent.models import Model, get_model
129

1310
from codeclash import REPO_DIR
1411
from codeclash.agents.player import Player
@@ -22,10 +19,8 @@
2219

2320

2421
class ClashAgent(DefaultAgent):
25-
"""
26-
Slightly modified version of `DefaultAgent` from mini-SWE-agent
27-
(https://github.com/SWE-agent/mini-swe-agent)
28-
"""
22+
"""`DefaultAgent` from mini-SWE-agent (https://github.com/SWE-agent/mini-swe-agent)
23+
with per-player debug logging."""
2924

3025
def __init__(
3126
self,
@@ -39,9 +34,11 @@ def __init__(
3934
super().__init__(model, env, config_class=config_class, **kwargs)
4035
self.logger = logger
4136

42-
def add_message(self, role: str, content: str, **kwargs):
43-
super().add_message(role, content, **kwargs)
44-
self.logger.debug(f"[{role}] {content}", extra={"highlighter": None})
37+
def add_messages(self, *messages: dict) -> list[dict]:
38+
result = super().add_messages(*messages)
39+
for m in messages:
40+
self.logger.debug(f"[{m.get('role')}] {m.get('content')}", extra={"highlighter": None})
41+
return result
4542

4643

4744
class MiniSWEAgent(Player):
@@ -51,26 +48,21 @@ def __init__(self, config: dict, environment: DockerEnvironment, game_context: G
5148
super().__init__(config, environment=environment, game_context=game_context)
5249

5350
def run(self):
54-
# temporary workaround around https://github.com/SWE-agent/mini-swe-agent/issues/477
55-
if "DeterministicModel" not in self.config["config"]["model"].get("model_class", ""):
56-
model = get_model(config=self.config["config"]["model"])
57-
else:
58-
model = DeterministicModel(outputs=self.config["config"]["model"]["outputs"])
51+
model = get_model(config=self.config["config"]["model"])
5952
self.agent = ClashAgent(
6053
model=model,
6154
env=self.environment,
6255
logger=self.logger,
6356
**self.config["config"]["agent"],
6457
)
6558
exit_status = None
66-
result = None
6759
exc_message = None
6860
try:
69-
exit_status, result = self.agent.run(task="", **self.game_context.to_template_vars())
61+
result = self.agent.run(task="", **self.game_context.to_template_vars())
62+
exit_status = result.get("exit_status", "")
7063
except Exception as e:
7164
exit_status = str(e)
7265
exc_message = traceback.format_exc()
73-
result = exc_message
7466
self.logger.critical(exc_message)
7567
finally:
7668
traj_path = (
@@ -79,22 +71,16 @@ def run(self):
7971
/ self.name
8072
/ f"{self.name}_r{self.game_context.round}.traj.json"
8173
)
82-
save_traj(
83-
self.agent, # type: ignore
84-
traj_path,
85-
exit_status=exit_status,
86-
result=result,
87-
print_fct=self.logger.debug,
88-
)
74+
self.agent.save(traj_path)
8975
copy_to_container(
9076
self.environment,
9177
traj_path,
9278
self.game_context.log_env / "edits" / traj_path.name,
9379
)
9480
self._metadata["agent_stats"][self.game_context.round] = {
9581
"exit_status": exit_status,
96-
"cost": self.agent.model.cost,
97-
"api_calls": self.agent.model.n_calls,
82+
"cost": self.agent.cost,
83+
"api_calls": self.agent.n_calls,
9884
}
9985
if exit_status.lower().strip() not in ["", "submitted", "limitsexceeded"] and exc_message is not None:
10086
raise RuntimeError(f"Agent {self.name} failed with exit status: {exit_status} and exception: {exc_message}")

codeclash/analysis/llm_as_judge/hallucination.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ system_prompt: |
7171
by reasoning)
7272
- "My bot is working perfectly" (this is just a slightly overconfident statement, but not a concrete claim that can be corroborated or disproven)
7373
This violates 2 (the statement of fact is not concrete)
74-
- Agent using an incorrect linenumber when referring to a code snippet (as long as the agent recovers later on and this doens't cause an edit to
74+
- Agent using an incorrect linenumber when referring to a code snippet (as long as the agent recovers later on and this doesn't cause an edit to
7575
fail without being able to recover). This violates 6 (the incident is not relevant to the overall trajectory and objective of the agent)
7676
- Anything related to failed edits as long as the failure is spotted and corrected later on.
7777

codeclash/arenas/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from codeclash.arenas.bridge.bridge import BridgeArena
77
from codeclash.arenas.chess.chess import ChessArena
88
from codeclash.arenas.corewar.corewar import CoreWarArena
9+
from codeclash.arenas.cyborg.cyborg import CybORGArena
910
from codeclash.arenas.dummy.dummy import DummyArena
1011
from codeclash.arenas.figgie.figgie import FiggieArena
1112
from codeclash.arenas.gomoku.gomoku import GomokuArena
@@ -15,6 +16,7 @@
1516
from codeclash.arenas.huskybench.huskybench import HuskyBenchArena
1617
from codeclash.arenas.robocode.robocode import RoboCodeArena
1718
from codeclash.arenas.robotrumble.robotrumble import RobotRumbleArena
19+
from codeclash.arenas.scml.scml import SCMLOneShotArena
1820

1921
ARENAS = [
2022
BattleCode23Arena,
@@ -24,6 +26,7 @@
2426
BridgeArena,
2527
ChessArena,
2628
CoreWarArena,
29+
CybORGArena,
2730
DummyArena,
2831
FiggieArena,
2932
GomokuArena,
@@ -33,6 +36,7 @@
3336
HuskyBenchArena,
3437
RoboCodeArena,
3538
RobotRumbleArena,
39+
SCMLOneShotArena,
3640
]
3741

3842

codeclash/arenas/arena.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,12 @@
1212
from codeclash.agents.player import Player
1313
from codeclash.constants import DIR_LOGS, DIR_WORK, GH_ORG, RESULT_TIE
1414
from codeclash.utils.aws import is_running_in_aws_batch, pull_game_container_aws_ecr
15-
from codeclash.utils.environment import assert_zero_exit_code, copy_between_containers, copy_from_container
15+
from codeclash.utils.environment import (
16+
ClashDockerEnvironment,
17+
assert_zero_exit_code,
18+
copy_between_containers,
19+
copy_from_container,
20+
)
1621
from codeclash.utils.log import get_logger
1722

1823

@@ -185,7 +190,7 @@ def get_environment(self, branch_name: str | None = None) -> DockerEnvironment:
185190
run_args = ["--rm"]
186191
else:
187192
run_args = []
188-
environment = DockerEnvironment(
193+
environment = ClashDockerEnvironment(
189194
image=self.image_name,
190195
cwd=str(DIR_WORK),
191196
env={

0 commit comments

Comments
 (0)