cogames 0.3.65__py3-none-any.whl → 0.3.69__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cogames/cli/client.py +0 -3
- cogames/cli/docsync/docsync.py +7 -1
- cogames/cli/mission.py +44 -19
- cogames/cli/policy.py +26 -10
- cogames/cli/submit.py +201 -495
- cogames/cli/utils.py +5 -0
- cogames/cogs_vs_clips/clip_difficulty.py +57 -0
- cogames/cogs_vs_clips/clips.py +23 -6
- cogames/cogs_vs_clips/cog.py +16 -5
- cogames/cogs_vs_clips/cogsguard_curriculum.py +122 -0
- cogames/cogs_vs_clips/cogsguard_tutorial.py +5 -5
- cogames/cogs_vs_clips/config.py +1 -1
- cogames/cogs_vs_clips/docs/cogs_vs_clips_mapgen.md +2 -3
- cogames/cogs_vs_clips/evals/README.md +8 -32
- cogames/cogs_vs_clips/evals/diagnostic_evals.py +0 -1
- cogames/cogs_vs_clips/evals/difficulty_variants.py +7 -10
- cogames/cogs_vs_clips/mission.py +38 -10
- cogames/cogs_vs_clips/missions.py +1 -1
- cogames/cogs_vs_clips/reward_variants.py +173 -0
- cogames/cogs_vs_clips/sites.py +6 -5
- cogames/cogs_vs_clips/stations.py +13 -9
- cogames/cogs_vs_clips/team.py +3 -1
- cogames/cogs_vs_clips/terrain.py +2 -2
- cogames/cogs_vs_clips/variants.py +175 -4
- cogames/cogs_vs_clips/weather.py +52 -0
- cogames/docs/SCRIPTED_AGENT.md +3 -3
- cogames/evaluate.py +4 -2
- cogames/main.py +420 -84
- cogames/maps/canidate1_1000.map +1 -1
- cogames/maps/canidate1_1000_stations.map +2 -2
- cogames/maps/canidate1_500.map +1 -1
- cogames/maps/canidate1_500_stations.map +2 -2
- cogames/maps/canidate2_1000.map +1 -1
- cogames/maps/canidate2_1000_stations.map +2 -2
- cogames/maps/canidate2_500.map +1 -1
- cogames/maps/canidate2_500_stations.map +1 -1
- cogames/maps/canidate3_1000.map +1 -1
- cogames/maps/canidate3_1000_stations.map +2 -2
- cogames/maps/canidate3_500.map +1 -1
- cogames/maps/canidate3_500_stations.map +2 -2
- cogames/maps/canidate4_500.map +1 -1
- cogames/maps/canidate4_500_stations.map +2 -2
- cogames/maps/cave_base_50.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_agile.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_agile_hard.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_charge_up.map +6 -6
- cogames/maps/diagnostic_evals/diagnostic_charge_up_hard.map +6 -6
- cogames/maps/diagnostic_evals/diagnostic_chest_navigation1.map +6 -6
- cogames/maps/diagnostic_evals/diagnostic_chest_navigation1_hard.map +6 -6
- cogames/maps/diagnostic_evals/diagnostic_chest_navigation2.map +6 -6
- cogames/maps/diagnostic_evals/diagnostic_chest_navigation2_hard.map +6 -6
- cogames/maps/diagnostic_evals/diagnostic_chest_navigation3.map +6 -6
- cogames/maps/diagnostic_evals/diagnostic_chest_navigation3_hard.map +6 -6
- cogames/maps/diagnostic_evals/diagnostic_chest_near.map +6 -6
- cogames/maps/diagnostic_evals/diagnostic_chest_search.map +6 -6
- cogames/maps/diagnostic_evals/diagnostic_chest_search_hard.map +6 -6
- cogames/maps/diagnostic_evals/diagnostic_extract_lab.map +6 -6
- cogames/maps/diagnostic_evals/diagnostic_extract_lab_hard.map +6 -6
- cogames/maps/diagnostic_evals/diagnostic_memory.map +6 -6
- cogames/maps/diagnostic_evals/diagnostic_memory_hard.map +6 -6
- cogames/maps/diagnostic_evals/diagnostic_radial.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_radial_hard.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_resource_lab.map +6 -6
- cogames/maps/diagnostic_evals/diagnostic_unclip.map +6 -6
- cogames/maps/evals/eval_balanced_spread.map +6 -6
- cogames/maps/evals/eval_clip_oxygen.map +6 -6
- cogames/maps/evals/eval_collect_resources.map +6 -6
- cogames/maps/evals/eval_collect_resources_hard.map +6 -6
- cogames/maps/evals/eval_collect_resources_medium.map +6 -6
- cogames/maps/evals/eval_divide_and_conquer.map +6 -6
- cogames/maps/evals/eval_energy_starved.map +6 -6
- cogames/maps/evals/eval_multi_coordinated_collect_hard.map +6 -6
- cogames/maps/evals/eval_oxygen_bottleneck.map +6 -6
- cogames/maps/evals/eval_single_use_world.map +6 -6
- cogames/maps/evals/extractor_hub_100x100.map +6 -6
- cogames/maps/evals/extractor_hub_30x30.map +6 -6
- cogames/maps/evals/extractor_hub_50x50.map +6 -6
- cogames/maps/evals/extractor_hub_70x70.map +6 -6
- cogames/maps/evals/extractor_hub_80x80.map +6 -6
- cogames/maps/machina_100_stations.map +2 -2
- cogames/maps/machina_200_stations.map +2 -2
- cogames/maps/machina_200_stations_small.map +2 -2
- cogames/maps/machina_eval_exp01.map +2 -2
- cogames/maps/machina_eval_template_large.map +2 -2
- cogames/maps/machinatrainer4agents.map +2 -2
- cogames/maps/machinatrainer4agentsbase.map +2 -2
- cogames/maps/machinatrainerbig.map +2 -2
- cogames/maps/machinatrainersmall.map +2 -2
- cogames/maps/planky_evals/aligner_avoid_aoe.map +6 -6
- cogames/maps/planky_evals/aligner_full_cycle.map +6 -6
- cogames/maps/planky_evals/aligner_gear.map +6 -6
- cogames/maps/planky_evals/aligner_hearts.map +6 -6
- cogames/maps/planky_evals/aligner_junction.map +6 -6
- cogames/maps/planky_evals/exploration_distant.map +6 -6
- cogames/maps/planky_evals/maze.map +6 -6
- cogames/maps/planky_evals/miner_best_resource.map +6 -6
- cogames/maps/planky_evals/miner_deposit.map +6 -6
- cogames/maps/planky_evals/miner_extract.map +6 -6
- cogames/maps/planky_evals/miner_full_cycle.map +6 -6
- cogames/maps/planky_evals/miner_gear.map +6 -6
- cogames/maps/planky_evals/multi_role.map +6 -6
- cogames/maps/planky_evals/resource_chain.map +6 -6
- cogames/maps/planky_evals/scout_explore.map +6 -6
- cogames/maps/planky_evals/scout_gear.map +6 -6
- cogames/maps/planky_evals/scrambler_full_cycle.map +6 -6
- cogames/maps/planky_evals/scrambler_gear.map +6 -6
- cogames/maps/planky_evals/scrambler_target.map +6 -6
- cogames/maps/planky_evals/stuck_corridor.map +6 -6
- cogames/maps/planky_evals/survive_retreat.map +6 -6
- cogames/maps/training_facility_clipped.map +2 -2
- cogames/maps/training_facility_open_1.map +2 -2
- cogames/maps/training_facility_open_2.map +2 -2
- cogames/maps/training_facility_open_3.map +2 -2
- cogames/maps/training_facility_tight_4.map +2 -2
- cogames/maps/training_facility_tight_5.map +2 -2
- cogames/maps/vanilla_large.map +2 -2
- cogames/maps/vanilla_small.map +2 -2
- cogames/pickup.py +6 -5
- cogames/play.py +14 -16
- cogames/policy/nim_agents/__init__.py +0 -2
- cogames/policy/nim_agents/agents.py +0 -11
- cogames/policy/starter_agent.py +4 -1
- {cogames-0.3.65.dist-info → cogames-0.3.69.dist-info}/METADATA +45 -29
- cogames-0.3.69.dist-info/RECORD +160 -0
- metta_alo/scoring.py +7 -7
- cogames-0.3.65.dist-info/RECORD +0 -160
- metta_alo/job_specs.py +0 -17
- metta_alo/policy.py +0 -16
- metta_alo/pure_single_episode_runner.py +0 -75
- metta_alo/rollout.py +0 -322
- {cogames-0.3.65.dist-info → cogames-0.3.69.dist-info}/WHEEL +0 -0
- {cogames-0.3.65.dist-info → cogames-0.3.69.dist-info}/entry_points.txt +0 -0
- {cogames-0.3.65.dist-info → cogames-0.3.69.dist-info}/licenses/LICENSE +0 -0
- {cogames-0.3.65.dist-info → cogames-0.3.69.dist-info}/top_level.txt +0 -0
cogames/main.py
CHANGED
|
@@ -8,6 +8,7 @@ from cogames.cli.utils import suppress_noisy_logs
|
|
|
8
8
|
|
|
9
9
|
suppress_noisy_logs()
|
|
10
10
|
|
|
11
|
+
import importlib
|
|
11
12
|
import importlib.metadata
|
|
12
13
|
import importlib.util
|
|
13
14
|
import json
|
|
@@ -17,6 +18,7 @@ import subprocess
|
|
|
17
18
|
import sys
|
|
18
19
|
import threading
|
|
19
20
|
import time
|
|
21
|
+
from dataclasses import dataclass
|
|
20
22
|
from pathlib import Path
|
|
21
23
|
from typing import Literal, Optional, TypeVar
|
|
22
24
|
|
|
@@ -38,7 +40,6 @@ from cogames import play as play_module
|
|
|
38
40
|
from cogames import train as train_module
|
|
39
41
|
from cogames.cli.base import console
|
|
40
42
|
from cogames.cli.client import SeasonInfo, TournamentServerClient, fetch_default_season, fetch_season_info
|
|
41
|
-
from cogames.cli.docsync import docsync
|
|
42
43
|
from cogames.cli.leaderboard import (
|
|
43
44
|
leaderboard_cmd,
|
|
44
45
|
parse_policy_identifier,
|
|
@@ -62,7 +63,14 @@ from cogames.cli.policy import (
|
|
|
62
63
|
policy_arg_example,
|
|
63
64
|
policy_arg_w_proportion_example,
|
|
64
65
|
)
|
|
65
|
-
from cogames.cli.submit import
|
|
66
|
+
from cogames.cli.submit import (
|
|
67
|
+
DEFAULT_SUBMIT_SERVER,
|
|
68
|
+
RESULTS_URL,
|
|
69
|
+
create_bundle,
|
|
70
|
+
upload_policy,
|
|
71
|
+
validate_bundle,
|
|
72
|
+
)
|
|
73
|
+
from cogames.cogs_vs_clips.mission import CvCMission, NumCogsVariant
|
|
66
74
|
from cogames.curricula import make_rotation
|
|
67
75
|
from cogames.device import resolve_training_device
|
|
68
76
|
from mettagrid.config.mettagrid_config import MettaGridConfig
|
|
@@ -87,6 +95,158 @@ logger = logging.getLogger("cogames.main")
|
|
|
87
95
|
T = TypeVar("T")
|
|
88
96
|
|
|
89
97
|
|
|
98
|
+
@dataclass(frozen=True)
|
|
99
|
+
class DiagnoseCase:
|
|
100
|
+
name: str
|
|
101
|
+
env_cfg: MettaGridConfig
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _load_eval_missions(module_path: str) -> list[CvCMission]:
|
|
105
|
+
module = importlib.import_module(module_path)
|
|
106
|
+
missions = getattr(module, "EVAL_MISSIONS", None)
|
|
107
|
+
if missions is None:
|
|
108
|
+
raise AttributeError(f"Module '{module_path}' does not define EVAL_MISSIONS")
|
|
109
|
+
return list(missions)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _load_diagnose_missions(mission_set: str) -> list[CvCMission]:
|
|
113
|
+
if mission_set == "thinky_evals":
|
|
114
|
+
return []
|
|
115
|
+
|
|
116
|
+
if mission_set == "all":
|
|
117
|
+
from cogames.cogs_vs_clips.evals.cogsguard_evals import COGSGUARD_EVAL_MISSIONS # noqa: PLC0415
|
|
118
|
+
from cogames.cogs_vs_clips.evals.diagnostic_evals import DIAGNOSTIC_EVALS # noqa: PLC0415
|
|
119
|
+
from cogames.cogs_vs_clips.missions import MISSIONS as ALL_MISSIONS # noqa: PLC0415
|
|
120
|
+
|
|
121
|
+
missions_list: list[CvCMission] = []
|
|
122
|
+
missions_list.extend(COGSGUARD_EVAL_MISSIONS)
|
|
123
|
+
missions_list.extend(_load_eval_missions("cogames.cogs_vs_clips.evals.integrated_evals"))
|
|
124
|
+
missions_list.extend(_load_eval_missions("cogames.cogs_vs_clips.evals.spanning_evals"))
|
|
125
|
+
missions_list.extend([mission_cls() for mission_cls in DIAGNOSTIC_EVALS]) # type: ignore[call-arg]
|
|
126
|
+
eval_mission_names = {mission.name for mission in missions_list}
|
|
127
|
+
for mission in ALL_MISSIONS:
|
|
128
|
+
if mission.name not in eval_mission_names:
|
|
129
|
+
missions_list.append(mission)
|
|
130
|
+
return missions_list
|
|
131
|
+
|
|
132
|
+
if mission_set == "cogsguard_evals":
|
|
133
|
+
from cogames.cogs_vs_clips.evals.cogsguard_evals import COGSGUARD_EVAL_MISSIONS # noqa: PLC0415
|
|
134
|
+
|
|
135
|
+
return list(COGSGUARD_EVAL_MISSIONS)
|
|
136
|
+
|
|
137
|
+
if mission_set == "diagnostic_evals":
|
|
138
|
+
from cogames.cogs_vs_clips.evals.diagnostic_evals import DIAGNOSTIC_EVALS # noqa: PLC0415
|
|
139
|
+
|
|
140
|
+
return [mission_cls() for mission_cls in DIAGNOSTIC_EVALS] # type: ignore[call-arg]
|
|
141
|
+
|
|
142
|
+
if mission_set == "tournament":
|
|
143
|
+
from cogames.cogs_vs_clips.evals.diagnostic_evals import DIAGNOSTIC_EVALS # noqa: PLC0415
|
|
144
|
+
|
|
145
|
+
missions_list = []
|
|
146
|
+
missions_list.extend(_load_eval_missions("cogames.cogs_vs_clips.evals.integrated_evals"))
|
|
147
|
+
missions_list.extend([mission_cls() for mission_cls in DIAGNOSTIC_EVALS]) # type: ignore[call-arg]
|
|
148
|
+
return missions_list
|
|
149
|
+
|
|
150
|
+
if mission_set == "integrated_evals":
|
|
151
|
+
return _load_eval_missions("cogames.cogs_vs_clips.evals.integrated_evals")
|
|
152
|
+
|
|
153
|
+
if mission_set == "spanning_evals":
|
|
154
|
+
return _load_eval_missions("cogames.cogs_vs_clips.evals.spanning_evals")
|
|
155
|
+
|
|
156
|
+
raise ValueError(f"Unknown mission set: {mission_set}")
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def _build_thinky_mission_map() -> dict[str, CvCMission]:
|
|
160
|
+
from cogames.cogs_vs_clips.evals.cogsguard_evals import COGSGUARD_EVAL_MISSIONS # noqa: PLC0415
|
|
161
|
+
from cogames.cogs_vs_clips.evals.diagnostic_evals import DIAGNOSTIC_EVALS # noqa: PLC0415
|
|
162
|
+
from cogames.cogs_vs_clips.missions import MISSIONS as ALL_MISSIONS # noqa: PLC0415
|
|
163
|
+
|
|
164
|
+
missions: list[CvCMission] = []
|
|
165
|
+
missions.extend(_load_eval_missions("cogames.cogs_vs_clips.evals.integrated_evals"))
|
|
166
|
+
missions.extend(_load_eval_missions("cogames.cogs_vs_clips.evals.spanning_evals"))
|
|
167
|
+
missions.extend([mission_cls() for mission_cls in DIAGNOSTIC_EVALS]) # type: ignore[call-arg]
|
|
168
|
+
missions.extend(COGSGUARD_EVAL_MISSIONS)
|
|
169
|
+
missions.extend(ALL_MISSIONS)
|
|
170
|
+
|
|
171
|
+
mission_map: dict[str, CvCMission] = {}
|
|
172
|
+
for mission in missions:
|
|
173
|
+
mission_map.setdefault(mission.name, mission)
|
|
174
|
+
return mission_map
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def _matches_experiment(mission_name: str, experiment_filters: set[str]) -> bool:
|
|
178
|
+
if not experiment_filters:
|
|
179
|
+
return True
|
|
180
|
+
if mission_name in experiment_filters:
|
|
181
|
+
return True
|
|
182
|
+
suffix = f".{mission_name}"
|
|
183
|
+
return any(name.endswith(suffix) for name in experiment_filters)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def _cogs_for_mission(mission: CvCMission, cogs_list: list[int], respect_cogs_list: bool) -> list[int]:
|
|
187
|
+
fixed_cogs = getattr(mission, "num_cogs", None)
|
|
188
|
+
if fixed_cogs is not None:
|
|
189
|
+
if respect_cogs_list and fixed_cogs not in cogs_list:
|
|
190
|
+
return []
|
|
191
|
+
return [fixed_cogs]
|
|
192
|
+
site = getattr(mission, "site", None)
|
|
193
|
+
if site is None:
|
|
194
|
+
return list(cogs_list)
|
|
195
|
+
min_cogs = getattr(site, "min_cogs", None)
|
|
196
|
+
max_cogs = getattr(site, "max_cogs", None)
|
|
197
|
+
return [
|
|
198
|
+
num_cogs
|
|
199
|
+
for num_cogs in cogs_list
|
|
200
|
+
if (min_cogs is None or num_cogs >= min_cogs) and (max_cogs is None or num_cogs <= max_cogs)
|
|
201
|
+
]
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def _build_diagnose_case(mission: CvCMission, num_cogs: int, steps: int) -> DiagnoseCase:
|
|
205
|
+
mission_with_cogs = mission.with_variants([NumCogsVariant(num_cogs=num_cogs)])
|
|
206
|
+
env_cfg = mission_with_cogs.make_env()
|
|
207
|
+
env_cfg.game.max_steps = steps
|
|
208
|
+
name = f"{mission.full_name()} (cogs={num_cogs})"
|
|
209
|
+
return DiagnoseCase(name=name, env_cfg=env_cfg)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def _build_diagnose_cases(
|
|
213
|
+
*,
|
|
214
|
+
mission_set: str,
|
|
215
|
+
experiments: Optional[list[str]],
|
|
216
|
+
cogs: Optional[list[int]],
|
|
217
|
+
steps: int,
|
|
218
|
+
) -> list[DiagnoseCase]:
|
|
219
|
+
experiment_filters = set(experiments or [])
|
|
220
|
+
cogs_list = cogs if cogs else [1, 2, 4]
|
|
221
|
+
respect_cogs_list = cogs is not None
|
|
222
|
+
cases: list[DiagnoseCase] = []
|
|
223
|
+
|
|
224
|
+
if mission_set == "thinky_evals":
|
|
225
|
+
from cogames_agents.policy.nim_agents.thinky_eval import EVALS as THINKY_EVALS # noqa: PLC0415
|
|
226
|
+
|
|
227
|
+
mission_map = _build_thinky_mission_map()
|
|
228
|
+
for exp_name, _tag, num_cogs in THINKY_EVALS:
|
|
229
|
+
if not _matches_experiment(exp_name, experiment_filters):
|
|
230
|
+
continue
|
|
231
|
+
if respect_cogs_list and num_cogs not in cogs_list:
|
|
232
|
+
continue
|
|
233
|
+
base_mission = mission_map.get(exp_name)
|
|
234
|
+
if base_mission is None:
|
|
235
|
+
logger.warning("Thinky eval mission '%s' not found; skipping.", exp_name)
|
|
236
|
+
continue
|
|
237
|
+
cases.append(_build_diagnose_case(base_mission, num_cogs, steps))
|
|
238
|
+
return cases
|
|
239
|
+
|
|
240
|
+
missions = _load_diagnose_missions(mission_set)
|
|
241
|
+
for mission in missions:
|
|
242
|
+
if not _matches_experiment(mission.name, experiment_filters):
|
|
243
|
+
continue
|
|
244
|
+
for num_cogs in _cogs_for_mission(mission, cogs_list, respect_cogs_list):
|
|
245
|
+
cases.append(_build_diagnose_case(mission, num_cogs, steps))
|
|
246
|
+
|
|
247
|
+
return cases
|
|
248
|
+
|
|
249
|
+
|
|
90
250
|
def _resolve_mettascope_script() -> Path:
|
|
91
251
|
spec = importlib.util.find_spec("mettagrid")
|
|
92
252
|
if spec is None or spec.origin is None:
|
|
@@ -132,7 +292,18 @@ tutorial_app = typer.Typer(
|
|
|
132
292
|
if register_tribal_cli is not None:
|
|
133
293
|
register_tribal_cli(app)
|
|
134
294
|
|
|
135
|
-
|
|
295
|
+
|
|
296
|
+
@app.command(
|
|
297
|
+
name="docsync",
|
|
298
|
+
hidden=True,
|
|
299
|
+
context_settings={"allow_extra_args": True, "ignore_unknown_options": True},
|
|
300
|
+
add_help_option=False,
|
|
301
|
+
)
|
|
302
|
+
def docsync_cmd(ctx: typer.Context) -> None:
|
|
303
|
+
"""Sync cogames docs between .ipynb, .py, and .md formats (dev-only)."""
|
|
304
|
+
from cogames.cli.docsync import docsync # noqa: PLC0415
|
|
305
|
+
|
|
306
|
+
docsync.app(prog_name="cogames docsync", standalone_mode=False, args=list(ctx.args))
|
|
136
307
|
|
|
137
308
|
|
|
138
309
|
@tutorial_app.command(
|
|
@@ -160,7 +331,7 @@ def tutorial_cmd(
|
|
|
160
331
|
console.print("[dim]Initializing Mettascope...[/dim]")
|
|
161
332
|
|
|
162
333
|
# Load tutorial mission (CogsGuard)
|
|
163
|
-
from cogames.cogs_vs_clips.missions import make_cogsguard_mission
|
|
334
|
+
from cogames.cogs_vs_clips.missions import make_cogsguard_mission # noqa: PLC0415
|
|
164
335
|
|
|
165
336
|
# Create environment config
|
|
166
337
|
env_cfg = make_cogsguard_mission(num_agents=1, max_steps=1000).make_env()
|
|
@@ -310,7 +481,7 @@ def cogsguard_tutorial_cmd(
|
|
|
310
481
|
console.print("[dim]Initializing Mettascope...[/dim]")
|
|
311
482
|
|
|
312
483
|
# Load CogsGuard tutorial mission
|
|
313
|
-
from cogames.cogs_vs_clips.cogsguard_tutorial import CogsGuardTutorialMission
|
|
484
|
+
from cogames.cogs_vs_clips.cogsguard_tutorial import CogsGuardTutorialMission # noqa: PLC0415
|
|
314
485
|
|
|
315
486
|
# Create environment config
|
|
316
487
|
env_cfg = CogsGuardTutorialMission.make_env()
|
|
@@ -526,6 +697,13 @@ def games_cmd(
|
|
|
526
697
|
help="Apply variant (requires -m, repeatable)",
|
|
527
698
|
rich_help_panel="Describe",
|
|
528
699
|
),
|
|
700
|
+
difficulty: Optional[str] = typer.Option(
|
|
701
|
+
None,
|
|
702
|
+
"--difficulty",
|
|
703
|
+
metavar="LEVEL",
|
|
704
|
+
help="Difficulty (easy, medium, hard) controlling clips events (requires -m)",
|
|
705
|
+
rich_help_panel="Describe",
|
|
706
|
+
),
|
|
529
707
|
format_: Optional[Literal["yaml", "json"]] = typer.Option(
|
|
530
708
|
None,
|
|
531
709
|
"--format",
|
|
@@ -569,7 +747,13 @@ def games_cmd(
|
|
|
569
747
|
return
|
|
570
748
|
|
|
571
749
|
try:
|
|
572
|
-
resolved_mission, env_cfg, mission_cfg = get_mission_name_and_config(
|
|
750
|
+
resolved_mission, env_cfg, mission_cfg = get_mission_name_and_config(
|
|
751
|
+
ctx,
|
|
752
|
+
mission,
|
|
753
|
+
variants_arg=variant,
|
|
754
|
+
cogs=cogs,
|
|
755
|
+
difficulty=difficulty,
|
|
756
|
+
)
|
|
573
757
|
except typer.Exit as exc:
|
|
574
758
|
if exc.exit_code != 1:
|
|
575
759
|
raise
|
|
@@ -653,6 +837,13 @@ def describe_cmd(
|
|
|
653
837
|
help="Apply variant (repeatable)",
|
|
654
838
|
rich_help_panel="Configuration",
|
|
655
839
|
),
|
|
840
|
+
difficulty: Optional[str] = typer.Option(
|
|
841
|
+
None,
|
|
842
|
+
"--difficulty",
|
|
843
|
+
metavar="LEVEL",
|
|
844
|
+
help="Difficulty (easy, medium, hard) controlling clips events",
|
|
845
|
+
rich_help_panel="Configuration",
|
|
846
|
+
),
|
|
656
847
|
_help: bool = typer.Option(
|
|
657
848
|
False,
|
|
658
849
|
"--help",
|
|
@@ -663,7 +854,13 @@ def describe_cmd(
|
|
|
663
854
|
rich_help_panel="Other",
|
|
664
855
|
),
|
|
665
856
|
) -> None:
|
|
666
|
-
resolved_mission, env_cfg, mission_cfg = get_mission_name_and_config(
|
|
857
|
+
resolved_mission, env_cfg, mission_cfg = get_mission_name_and_config(
|
|
858
|
+
ctx,
|
|
859
|
+
mission,
|
|
860
|
+
variants_arg=variant,
|
|
861
|
+
cogs=cogs,
|
|
862
|
+
difficulty=difficulty,
|
|
863
|
+
)
|
|
667
864
|
describe_mission(resolved_mission, env_cfg, mission_cfg)
|
|
668
865
|
|
|
669
866
|
|
|
@@ -711,6 +908,13 @@ def play_cmd(
|
|
|
711
908
|
help="Apply variant modifier (repeatable)",
|
|
712
909
|
rich_help_panel="Game Setup",
|
|
713
910
|
),
|
|
911
|
+
difficulty: Optional[str] = typer.Option(
|
|
912
|
+
None,
|
|
913
|
+
"--difficulty",
|
|
914
|
+
metavar="LEVEL",
|
|
915
|
+
help="Difficulty (easy, medium, hard) controlling clips events",
|
|
916
|
+
rich_help_panel="Game Setup",
|
|
917
|
+
),
|
|
714
918
|
cogs: Optional[int] = typer.Option(
|
|
715
919
|
None,
|
|
716
920
|
"--cogs",
|
|
@@ -729,6 +933,13 @@ def play_cmd(
|
|
|
729
933
|
help="Policy controlling cogs ([bold]noop[/bold], [bold]random[/bold], [bold]lstm[/bold], or path)",
|
|
730
934
|
rich_help_panel="Policy",
|
|
731
935
|
),
|
|
936
|
+
device: str = typer.Option(
|
|
937
|
+
"auto",
|
|
938
|
+
"--device",
|
|
939
|
+
metavar="DEVICE",
|
|
940
|
+
help="Policy device (auto, cpu, cuda, cuda:0, etc.)",
|
|
941
|
+
rich_help_panel="Policy",
|
|
942
|
+
),
|
|
732
943
|
# --- Simulation ---
|
|
733
944
|
steps: int = typer.Option(
|
|
734
945
|
1000,
|
|
@@ -762,6 +973,12 @@ def play_cmd(
|
|
|
762
973
|
show_default="same as --seed",
|
|
763
974
|
rich_help_panel="Simulation",
|
|
764
975
|
),
|
|
976
|
+
autostart: bool = typer.Option(
|
|
977
|
+
False,
|
|
978
|
+
"--autostart",
|
|
979
|
+
help="Start simulation immediately without waiting for user input",
|
|
980
|
+
rich_help_panel="Simulation",
|
|
981
|
+
),
|
|
765
982
|
# --- Output ---
|
|
766
983
|
save_replay_dir: Optional[Path] = typer.Option( # noqa: B008
|
|
767
984
|
None,
|
|
@@ -796,7 +1013,13 @@ def play_cmd(
|
|
|
796
1013
|
rich_help_panel="Other",
|
|
797
1014
|
),
|
|
798
1015
|
) -> None:
|
|
799
|
-
resolved_mission, env_cfg, mission_cfg = get_mission_name_and_config(
|
|
1016
|
+
resolved_mission, env_cfg, mission_cfg = get_mission_name_and_config(
|
|
1017
|
+
ctx,
|
|
1018
|
+
mission,
|
|
1019
|
+
variants_arg=variant,
|
|
1020
|
+
cogs=cogs,
|
|
1021
|
+
difficulty=difficulty,
|
|
1022
|
+
)
|
|
800
1023
|
|
|
801
1024
|
if print_cvc_config or print_mg_config:
|
|
802
1025
|
try:
|
|
@@ -811,9 +1034,8 @@ def play_cmd(
|
|
|
811
1034
|
if isinstance(map_builder, MapGen.Config):
|
|
812
1035
|
map_builder.seed = map_seed
|
|
813
1036
|
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
console.print(f"Max Steps: {steps}, Render: {render}")
|
|
1037
|
+
resolved_device = resolve_training_device(console, device)
|
|
1038
|
+
policy_spec = get_policy_spec(ctx, policy, device=str(resolved_device))
|
|
817
1039
|
|
|
818
1040
|
if ctx.get_parameter_source("steps") in (
|
|
819
1041
|
ParameterSource.COMMANDLINE,
|
|
@@ -822,14 +1044,19 @@ def play_cmd(
|
|
|
822
1044
|
):
|
|
823
1045
|
env_cfg.game.max_steps = steps
|
|
824
1046
|
|
|
1047
|
+
console.print(f"[cyan]Playing {resolved_mission}[/cyan]")
|
|
1048
|
+
console.print(f"Max Steps: {env_cfg.game.max_steps}, Render: {render}")
|
|
1049
|
+
|
|
825
1050
|
play_module.play(
|
|
826
1051
|
console,
|
|
827
1052
|
env_cfg=env_cfg,
|
|
828
1053
|
policy_spec=policy_spec,
|
|
829
1054
|
seed=seed,
|
|
1055
|
+
device=str(resolved_device),
|
|
830
1056
|
render_mode=render,
|
|
831
1057
|
game_name=resolved_mission,
|
|
832
1058
|
save_replay=save_replay_dir,
|
|
1059
|
+
autostart=autostart,
|
|
833
1060
|
)
|
|
834
1061
|
|
|
835
1062
|
|
|
@@ -1151,6 +1378,13 @@ def train_cmd(
|
|
|
1151
1378
|
help="Mission variant (repeatable)",
|
|
1152
1379
|
rich_help_panel="Mission Setup",
|
|
1153
1380
|
),
|
|
1381
|
+
difficulty: Optional[str] = typer.Option(
|
|
1382
|
+
None,
|
|
1383
|
+
"--difficulty",
|
|
1384
|
+
metavar="LEVEL",
|
|
1385
|
+
help="Difficulty (easy, medium, hard) controlling clips events",
|
|
1386
|
+
rich_help_panel="Mission Setup",
|
|
1387
|
+
),
|
|
1154
1388
|
# --- Policy ---
|
|
1155
1389
|
policy: str = typer.Option(
|
|
1156
1390
|
"class=lstm",
|
|
@@ -1261,7 +1495,13 @@ def train_cmd(
|
|
|
1261
1495
|
rich_help_panel="Other",
|
|
1262
1496
|
),
|
|
1263
1497
|
) -> None:
|
|
1264
|
-
selected_missions = get_mission_names_and_configs(
|
|
1498
|
+
selected_missions = get_mission_names_and_configs(
|
|
1499
|
+
ctx,
|
|
1500
|
+
missions,
|
|
1501
|
+
variants_arg=variant,
|
|
1502
|
+
cogs=cogs,
|
|
1503
|
+
difficulty=difficulty,
|
|
1504
|
+
)
|
|
1265
1505
|
if len(selected_missions) == 1:
|
|
1266
1506
|
mission_name, env_cfg = selected_missions[0]
|
|
1267
1507
|
supplier = None
|
|
@@ -1380,6 +1620,13 @@ def run_cmd(
|
|
|
1380
1620
|
help="Mission variant (repeatable)",
|
|
1381
1621
|
rich_help_panel="Mission",
|
|
1382
1622
|
),
|
|
1623
|
+
difficulty: Optional[str] = typer.Option(
|
|
1624
|
+
None,
|
|
1625
|
+
"--difficulty",
|
|
1626
|
+
metavar="LEVEL",
|
|
1627
|
+
help="Difficulty (easy, medium, hard) controlling clips events",
|
|
1628
|
+
rich_help_panel="Mission",
|
|
1629
|
+
),
|
|
1383
1630
|
# --- Policy ---
|
|
1384
1631
|
policies: Optional[list[str]] = typer.Option( # noqa: B008
|
|
1385
1632
|
None,
|
|
@@ -1389,6 +1636,13 @@ def run_cmd(
|
|
|
1389
1636
|
help=f"Policies to evaluate: ({policy_arg_w_proportion_example}...)",
|
|
1390
1637
|
rich_help_panel="Policy",
|
|
1391
1638
|
),
|
|
1639
|
+
device: str = typer.Option(
|
|
1640
|
+
"auto",
|
|
1641
|
+
"--device",
|
|
1642
|
+
metavar="DEVICE",
|
|
1643
|
+
help="Policy device (auto, cpu, cuda, cuda:0, etc.)",
|
|
1644
|
+
rich_help_panel="Policy",
|
|
1645
|
+
),
|
|
1392
1646
|
# --- Simulation ---
|
|
1393
1647
|
episodes: int = typer.Option(
|
|
1394
1648
|
10,
|
|
@@ -1400,12 +1654,13 @@ def run_cmd(
|
|
|
1400
1654
|
rich_help_panel="Simulation",
|
|
1401
1655
|
),
|
|
1402
1656
|
steps: Optional[int] = typer.Option(
|
|
1403
|
-
|
|
1657
|
+
None,
|
|
1404
1658
|
"--steps",
|
|
1405
1659
|
"-s",
|
|
1406
1660
|
metavar="N",
|
|
1407
1661
|
help="Max steps per episode",
|
|
1408
1662
|
min=1,
|
|
1663
|
+
show_default="from mission",
|
|
1409
1664
|
rich_help_panel="Simulation",
|
|
1410
1665
|
),
|
|
1411
1666
|
seed: int = typer.Option(
|
|
@@ -1465,7 +1720,7 @@ def run_cmd(
|
|
|
1465
1720
|
raise typer.Exit(1)
|
|
1466
1721
|
|
|
1467
1722
|
if mission_set:
|
|
1468
|
-
from cogames.cli.mission import load_mission_set
|
|
1723
|
+
from cogames.cli.mission import load_mission_set # noqa: PLC0415
|
|
1469
1724
|
|
|
1470
1725
|
try:
|
|
1471
1726
|
mission_objs = load_mission_set(mission_set)
|
|
@@ -1479,7 +1734,14 @@ def run_cmd(
|
|
|
1479
1734
|
if cogs is None:
|
|
1480
1735
|
cogs = 4
|
|
1481
1736
|
|
|
1482
|
-
selected_missions = get_mission_names_and_configs(
|
|
1737
|
+
selected_missions = get_mission_names_and_configs(
|
|
1738
|
+
ctx,
|
|
1739
|
+
missions,
|
|
1740
|
+
variants_arg=variant,
|
|
1741
|
+
cogs=cogs,
|
|
1742
|
+
steps=steps,
|
|
1743
|
+
difficulty=difficulty,
|
|
1744
|
+
)
|
|
1483
1745
|
|
|
1484
1746
|
# Optional MapGen seed override for procedural maps.
|
|
1485
1747
|
if map_seed is not None:
|
|
@@ -1488,7 +1750,8 @@ def run_cmd(
|
|
|
1488
1750
|
if isinstance(map_builder, MapGen.Config):
|
|
1489
1751
|
map_builder.seed = map_seed
|
|
1490
1752
|
|
|
1491
|
-
|
|
1753
|
+
resolved_device = resolve_training_device(console, device)
|
|
1754
|
+
policy_specs = get_policy_specs_with_proportions(ctx, policies, device=str(resolved_device))
|
|
1492
1755
|
|
|
1493
1756
|
if ctx.info_name == "scrimmage":
|
|
1494
1757
|
if len(policy_specs) != 1:
|
|
@@ -1510,6 +1773,7 @@ def run_cmd(
|
|
|
1510
1773
|
action_timeout_ms=action_timeout_ms,
|
|
1511
1774
|
episodes=episodes,
|
|
1512
1775
|
seed=seed,
|
|
1776
|
+
device=str(resolved_device),
|
|
1513
1777
|
output_format=format_,
|
|
1514
1778
|
save_replay=str(save_replay_dir) if save_replay_dir else None,
|
|
1515
1779
|
)
|
|
@@ -1552,6 +1816,13 @@ def pickup_cmd(
|
|
|
1552
1816
|
help="Mission variant (repeatable)",
|
|
1553
1817
|
rich_help_panel="Mission",
|
|
1554
1818
|
),
|
|
1819
|
+
difficulty: Optional[str] = typer.Option(
|
|
1820
|
+
None,
|
|
1821
|
+
"--difficulty",
|
|
1822
|
+
metavar="LEVEL",
|
|
1823
|
+
help="Difficulty (easy, medium, hard) controlling clips events",
|
|
1824
|
+
rich_help_panel="Mission",
|
|
1825
|
+
),
|
|
1555
1826
|
# --- Policy ---
|
|
1556
1827
|
policy: Optional[str] = typer.Option(
|
|
1557
1828
|
None,
|
|
@@ -1568,6 +1839,13 @@ def pickup_cmd(
|
|
|
1568
1839
|
help="Pool policy (repeatable)",
|
|
1569
1840
|
rich_help_panel="Policy",
|
|
1570
1841
|
),
|
|
1842
|
+
device: str = typer.Option(
|
|
1843
|
+
"auto",
|
|
1844
|
+
"--device",
|
|
1845
|
+
metavar="DEVICE",
|
|
1846
|
+
help="Policy device (auto, cpu, cuda, cuda:0, etc.)",
|
|
1847
|
+
rich_help_panel="Policy",
|
|
1848
|
+
),
|
|
1571
1849
|
# --- Simulation ---
|
|
1572
1850
|
episodes: int = typer.Option(
|
|
1573
1851
|
1,
|
|
@@ -1631,7 +1909,7 @@ def pickup_cmd(
|
|
|
1631
1909
|
rich_help_panel="Other",
|
|
1632
1910
|
),
|
|
1633
1911
|
) -> None:
|
|
1634
|
-
import httpx
|
|
1912
|
+
import httpx # noqa: PLC0415
|
|
1635
1913
|
|
|
1636
1914
|
if policy is None:
|
|
1637
1915
|
console.print(ctx.get_help())
|
|
@@ -1644,15 +1922,22 @@ def pickup_cmd(
|
|
|
1644
1922
|
raise typer.Exit(1)
|
|
1645
1923
|
|
|
1646
1924
|
# Resolve mission
|
|
1647
|
-
resolved_mission, env_cfg, _ = get_mission_name_and_config(
|
|
1925
|
+
resolved_mission, env_cfg, _ = get_mission_name_and_config(
|
|
1926
|
+
ctx,
|
|
1927
|
+
mission,
|
|
1928
|
+
variants_arg=variant,
|
|
1929
|
+
cogs=cogs,
|
|
1930
|
+
difficulty=difficulty,
|
|
1931
|
+
)
|
|
1648
1932
|
if steps is not None:
|
|
1649
1933
|
env_cfg.game.max_steps = steps
|
|
1650
1934
|
|
|
1651
1935
|
candidate_label = policy
|
|
1652
1936
|
pool_labels = pool
|
|
1653
|
-
|
|
1937
|
+
resolved_device = resolve_training_device(console, device)
|
|
1938
|
+
candidate_spec = get_policy_spec(ctx, policy, device=str(resolved_device))
|
|
1654
1939
|
try:
|
|
1655
|
-
pool_specs = [parse_policy_spec(spec).to_policy_spec() for spec in pool]
|
|
1940
|
+
pool_specs = [parse_policy_spec(spec, device=str(resolved_device)).to_policy_spec() for spec in pool]
|
|
1656
1941
|
except (ValueError, ModuleNotFoundError, httpx.HTTPError) as exc:
|
|
1657
1942
|
translated = _translate_error(exc)
|
|
1658
1943
|
console.print(f"[yellow]Error parsing pool policy: {translated}[/yellow]\n")
|
|
@@ -1669,6 +1954,7 @@ def pickup_cmd(
|
|
|
1669
1954
|
map_seed=map_seed,
|
|
1670
1955
|
action_timeout_ms=action_timeout_ms,
|
|
1671
1956
|
save_replay_dir=save_replay_dir,
|
|
1957
|
+
device=str(resolved_device),
|
|
1672
1958
|
candidate_label=candidate_label,
|
|
1673
1959
|
pool_labels=pool_labels,
|
|
1674
1960
|
)
|
|
@@ -1762,10 +2048,10 @@ def login_cmd(
|
|
|
1762
2048
|
rich_help_panel="Other",
|
|
1763
2049
|
),
|
|
1764
2050
|
) -> None:
|
|
1765
|
-
from urllib.parse import urlparse
|
|
2051
|
+
from urllib.parse import urlparse # noqa: PLC0415
|
|
1766
2052
|
|
|
1767
2053
|
# Check if we already have a token
|
|
1768
|
-
from cogames.auth import BaseCLIAuthenticator
|
|
2054
|
+
from cogames.auth import BaseCLIAuthenticator # noqa: PLC0415
|
|
1769
2055
|
|
|
1770
2056
|
temp_auth = BaseCLIAuthenticator(
|
|
1771
2057
|
token_file_name="cogames.yaml",
|
|
@@ -1823,7 +2109,9 @@ app.command(
|
|
|
1823
2109
|
rich_help_panel="Evaluate",
|
|
1824
2110
|
epilog="""[dim]Examples:[/dim]
|
|
1825
2111
|
|
|
1826
|
-
[cyan]cogames diagnose ./train_dir/my_run[/cyan] Default
|
|
2112
|
+
[cyan]cogames diagnose ./train_dir/my_run[/cyan] Default CogsGuard evals
|
|
2113
|
+
|
|
2114
|
+
[cyan]cogames diagnose lstm -S diagnostic_evals[/cyan] Diagnostic evals (non-CogsGuard)
|
|
1827
2115
|
|
|
1828
2116
|
[cyan]cogames diagnose lstm -S tournament[/cyan] Tournament suite
|
|
1829
2117
|
|
|
@@ -1831,6 +2119,7 @@ app.command(
|
|
|
1831
2119
|
add_help_option=False,
|
|
1832
2120
|
)
|
|
1833
2121
|
def diagnose_cmd(
|
|
2122
|
+
ctx: typer.Context,
|
|
1834
2123
|
policy: str = typer.Argument(
|
|
1835
2124
|
...,
|
|
1836
2125
|
metavar="POLICY",
|
|
@@ -1838,6 +2127,7 @@ def diagnose_cmd(
|
|
|
1838
2127
|
),
|
|
1839
2128
|
# --- Evaluation ---
|
|
1840
2129
|
mission_set: Literal[
|
|
2130
|
+
"cogsguard_evals",
|
|
1841
2131
|
"diagnostic_evals",
|
|
1842
2132
|
"integrated_evals",
|
|
1843
2133
|
"spanning_evals",
|
|
@@ -1845,7 +2135,7 @@ def diagnose_cmd(
|
|
|
1845
2135
|
"tournament",
|
|
1846
2136
|
"all",
|
|
1847
2137
|
] = typer.Option(
|
|
1848
|
-
"
|
|
2138
|
+
"cogsguard_evals",
|
|
1849
2139
|
"--mission-set",
|
|
1850
2140
|
"-S",
|
|
1851
2141
|
metavar="SET",
|
|
@@ -1867,6 +2157,13 @@ def diagnose_cmd(
|
|
|
1867
2157
|
help="Agent counts to test (repeatable)",
|
|
1868
2158
|
rich_help_panel="Evaluation",
|
|
1869
2159
|
),
|
|
2160
|
+
device: str = typer.Option(
|
|
2161
|
+
"auto",
|
|
2162
|
+
"--device",
|
|
2163
|
+
metavar="DEVICE",
|
|
2164
|
+
help="Policy device (auto, cpu, cuda, cuda:0, etc.)",
|
|
2165
|
+
rich_help_panel="Evaluation",
|
|
2166
|
+
),
|
|
1870
2167
|
# --- Simulation ---
|
|
1871
2168
|
steps: int = typer.Option(
|
|
1872
2169
|
1000,
|
|
@@ -1895,28 +2192,30 @@ def diagnose_cmd(
|
|
|
1895
2192
|
rich_help_panel="Other",
|
|
1896
2193
|
),
|
|
1897
2194
|
) -> None:
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
if
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
cmd.extend(["--steps", str(steps)])
|
|
1912
|
-
cmd.extend(["--repeats", str(episodes)])
|
|
1913
|
-
cmd.append("--no-plots")
|
|
1914
|
-
|
|
1915
|
-
cmd.extend(["--policy", policy])
|
|
2195
|
+
resolved_device = resolve_training_device(console, device)
|
|
2196
|
+
policy_spec = get_policy_spec(ctx, policy, device=str(resolved_device))
|
|
2197
|
+
|
|
2198
|
+
cases = _build_diagnose_cases(
|
|
2199
|
+
mission_set=mission_set,
|
|
2200
|
+
experiments=experiments,
|
|
2201
|
+
cogs=cogs,
|
|
2202
|
+
steps=steps,
|
|
2203
|
+
)
|
|
2204
|
+
if not cases:
|
|
2205
|
+
console.print("[red]No evaluation cases matched your filters.[/red]")
|
|
2206
|
+
raise typer.Exit(1)
|
|
1916
2207
|
|
|
1917
|
-
console.print("[cyan]Running diagnostic evaluation...[/cyan]")
|
|
1918
|
-
|
|
1919
|
-
|
|
2208
|
+
console.print(f"[cyan]Running diagnostic evaluation ({len(cases)} cases)...[/cyan]")
|
|
2209
|
+
evaluate_module.evaluate(
|
|
2210
|
+
console,
|
|
2211
|
+
missions=[(case.name, case.env_cfg) for case in cases],
|
|
2212
|
+
policy_specs=[policy_spec],
|
|
2213
|
+
proportions=[1.0],
|
|
2214
|
+
action_timeout_ms=10000,
|
|
2215
|
+
episodes=episodes,
|
|
2216
|
+
seed=42,
|
|
2217
|
+
device=str(resolved_device),
|
|
2218
|
+
)
|
|
1920
2219
|
|
|
1921
2220
|
|
|
1922
2221
|
def _resolve_season(server: str, season_name: str | None = None) -> SeasonInfo:
|
|
@@ -1935,12 +2234,12 @@ def _resolve_season(server: str, season_name: str | None = None) -> SeasonInfo:
|
|
|
1935
2234
|
|
|
1936
2235
|
|
|
1937
2236
|
@app.command(
|
|
1938
|
-
name="
|
|
1939
|
-
help="
|
|
2237
|
+
name="create-bundle",
|
|
2238
|
+
help="Create a submission bundle zip from a policy",
|
|
1940
2239
|
rich_help_panel="Policies",
|
|
1941
2240
|
add_help_option=False,
|
|
1942
2241
|
)
|
|
1943
|
-
def
|
|
2242
|
+
def create_bundle_cmd(
|
|
1944
2243
|
ctx: typer.Context,
|
|
1945
2244
|
policy: str = typer.Option(
|
|
1946
2245
|
...,
|
|
@@ -1950,11 +2249,77 @@ def validate_policy_cmd(
|
|
|
1950
2249
|
help=f"Policy specification: {policy_arg_example}",
|
|
1951
2250
|
rich_help_panel="Policy",
|
|
1952
2251
|
),
|
|
2252
|
+
output: Path = typer.Option( # noqa: B008
|
|
2253
|
+
Path("submission.zip"),
|
|
2254
|
+
"--output",
|
|
2255
|
+
"-o",
|
|
2256
|
+
metavar="PATH",
|
|
2257
|
+
help="Output path for the bundle zip",
|
|
2258
|
+
rich_help_panel="Output",
|
|
2259
|
+
),
|
|
2260
|
+
init_kwarg: Optional[list[str]] = typer.Option( # noqa: B008
|
|
2261
|
+
None,
|
|
2262
|
+
"--init-kwarg",
|
|
2263
|
+
"-k",
|
|
2264
|
+
metavar="KEY=VAL",
|
|
2265
|
+
help="Policy init kwargs (can be repeated)",
|
|
2266
|
+
rich_help_panel="Policy",
|
|
2267
|
+
),
|
|
2268
|
+
include_files: Optional[list[str]] = typer.Option( # noqa: B008
|
|
2269
|
+
None,
|
|
2270
|
+
"--include-files",
|
|
2271
|
+
"-f",
|
|
2272
|
+
metavar="PATH",
|
|
2273
|
+
help="Files or directories to include (can be repeated)",
|
|
2274
|
+
rich_help_panel="Files",
|
|
2275
|
+
),
|
|
1953
2276
|
setup_script: Optional[str] = typer.Option(
|
|
1954
2277
|
None,
|
|
1955
2278
|
"--setup-script",
|
|
1956
|
-
|
|
1957
|
-
|
|
2279
|
+
metavar="PATH",
|
|
2280
|
+
help="Python setup script to include in the bundle",
|
|
2281
|
+
rich_help_panel="Files",
|
|
2282
|
+
),
|
|
2283
|
+
_help: bool = typer.Option(
|
|
2284
|
+
False,
|
|
2285
|
+
"--help",
|
|
2286
|
+
"-h",
|
|
2287
|
+
help="Show this message and exit",
|
|
2288
|
+
is_eager=True,
|
|
2289
|
+
callback=_help_callback,
|
|
2290
|
+
rich_help_panel="Other",
|
|
2291
|
+
),
|
|
2292
|
+
) -> None:
|
|
2293
|
+
init_kwargs: dict[str, str] = {}
|
|
2294
|
+
if init_kwarg:
|
|
2295
|
+
for kv in init_kwarg:
|
|
2296
|
+
key, val = _parse_init_kwarg(kv)
|
|
2297
|
+
init_kwargs[key] = val
|
|
2298
|
+
|
|
2299
|
+
result_path = create_bundle(
|
|
2300
|
+
ctx=ctx,
|
|
2301
|
+
policy=policy,
|
|
2302
|
+
output=output.resolve(),
|
|
2303
|
+
include_files=include_files,
|
|
2304
|
+
init_kwargs=init_kwargs if init_kwargs else None,
|
|
2305
|
+
setup_script=setup_script,
|
|
2306
|
+
)
|
|
2307
|
+
console.print(f"[green]Bundle created:[/green] {result_path}")
|
|
2308
|
+
|
|
2309
|
+
|
|
2310
|
+
@app.command(
|
|
2311
|
+
name="validate-bundle",
|
|
2312
|
+
help="Validate a policy bundle runs correctly in process isolation",
|
|
2313
|
+
rich_help_panel="Policies",
|
|
2314
|
+
add_help_option=False,
|
|
2315
|
+
)
|
|
2316
|
+
def validate_bundle_cmd(
|
|
2317
|
+
policy: str = typer.Option(
|
|
2318
|
+
...,
|
|
2319
|
+
"--policy",
|
|
2320
|
+
"-p",
|
|
2321
|
+
metavar="URI",
|
|
2322
|
+
help="Bundle URI (file://, s3://, or local path to .zip or directory)",
|
|
1958
2323
|
),
|
|
1959
2324
|
season: Optional[str] = typer.Option(
|
|
1960
2325
|
None,
|
|
@@ -1989,31 +2354,8 @@ def validate_policy_cmd(
|
|
|
1989
2354
|
with TournamentServerClient(server_url=server) as client:
|
|
1990
2355
|
config_data = client.get_config(entry_pool_info.config_id)
|
|
1991
2356
|
env_cfg = MettaGridConfig.model_validate(config_data)
|
|
2357
|
+
validate_bundle(policy, env_cfg)
|
|
1992
2358
|
|
|
1993
|
-
if setup_script:
|
|
1994
|
-
import subprocess
|
|
1995
|
-
import sys
|
|
1996
|
-
from pathlib import Path
|
|
1997
|
-
|
|
1998
|
-
script_path = Path(setup_script)
|
|
1999
|
-
if not script_path.exists():
|
|
2000
|
-
console.print(f"[red]Setup script not found: {setup_script}[/red]")
|
|
2001
|
-
raise typer.Exit(1)
|
|
2002
|
-
console.print(f"[yellow]Running setup script: {setup_script}[/yellow]")
|
|
2003
|
-
result = subprocess.run(
|
|
2004
|
-
[sys.executable, str(script_path)],
|
|
2005
|
-
cwd=Path.cwd(),
|
|
2006
|
-
capture_output=True,
|
|
2007
|
-
text=True,
|
|
2008
|
-
timeout=300,
|
|
2009
|
-
)
|
|
2010
|
-
if result.returncode != 0:
|
|
2011
|
-
console.print(f"[red]Setup script failed:[/red]\n{result.stderr}")
|
|
2012
|
-
raise typer.Exit(1)
|
|
2013
|
-
console.print("[green]Setup script completed[/green]")
|
|
2014
|
-
|
|
2015
|
-
policy_spec = get_policy_spec(ctx, policy)
|
|
2016
|
-
validate_policy_spec(policy_spec, env_cfg)
|
|
2017
2359
|
console.print("[green]Policy validated successfully[/green]")
|
|
2018
2360
|
raise typer.Exit(0)
|
|
2019
2361
|
|
|
@@ -2140,11 +2482,6 @@ def upload_cmd(
|
|
|
2140
2482
|
) -> None:
|
|
2141
2483
|
season_info = _resolve_season(server, season)
|
|
2142
2484
|
|
|
2143
|
-
has_entry_config = any(p.config_id for p in season_info.pools if p.name == season_info.entry_pool)
|
|
2144
|
-
if not has_entry_config and not skip_validation:
|
|
2145
|
-
console.print("[yellow]Warning: No entry config found for season. Skipping validation.[/yellow]")
|
|
2146
|
-
skip_validation = True
|
|
2147
|
-
|
|
2148
2485
|
init_kwargs: dict[str, str] = {}
|
|
2149
2486
|
if init_kwarg:
|
|
2150
2487
|
for kv in init_kwarg:
|
|
@@ -2162,7 +2499,6 @@ def upload_cmd(
|
|
|
2162
2499
|
skip_validation=skip_validation,
|
|
2163
2500
|
init_kwargs=init_kwargs if init_kwargs else None,
|
|
2164
2501
|
setup_script=setup_script,
|
|
2165
|
-
validation_season=season_info.name,
|
|
2166
2502
|
season=season_info.name if not no_submit else None,
|
|
2167
2503
|
)
|
|
2168
2504
|
|
|
@@ -2170,7 +2506,7 @@ def upload_cmd(
|
|
|
2170
2506
|
console.print(f"[green]Upload complete: {result.name}:v{result.version}[/green]")
|
|
2171
2507
|
if result.pools:
|
|
2172
2508
|
console.print(f"[dim]Added to pools: {', '.join(result.pools)}[/dim]")
|
|
2173
|
-
console.print(f"[dim]Results:[/dim] {
|
|
2509
|
+
console.print(f"[dim]Results:[/dim] {RESULTS_URL}")
|
|
2174
2510
|
elif no_submit:
|
|
2175
2511
|
console.print(f"\nTo submit to a tournament: cogames submit {result.name}:v{result.version}")
|
|
2176
2512
|
|
|
@@ -2224,7 +2560,7 @@ def submit_cmd(
|
|
|
2224
2560
|
rich_help_panel="Other",
|
|
2225
2561
|
),
|
|
2226
2562
|
) -> None:
|
|
2227
|
-
import httpx
|
|
2563
|
+
import httpx # noqa: PLC0415
|
|
2228
2564
|
|
|
2229
2565
|
season_info = _resolve_season(server, season)
|
|
2230
2566
|
season_name = season_info.name
|
|
@@ -2268,7 +2604,7 @@ def submit_cmd(
|
|
|
2268
2604
|
console.print(f"\n[bold green]Submitted to season '{season_name}'[/bold green]")
|
|
2269
2605
|
if result.pools:
|
|
2270
2606
|
console.print(f"[dim]Added to pools: {', '.join(result.pools)}[/dim]")
|
|
2271
|
-
console.print(f"[dim]Results:[/dim] {
|
|
2607
|
+
console.print(f"[dim]Results:[/dim] {RESULTS_URL}")
|
|
2272
2608
|
console.print(f"[dim]CLI:[/dim] cogames leaderboard --season {season_name}")
|
|
2273
2609
|
|
|
2274
2610
|
|
|
@@ -2322,7 +2658,7 @@ def docs_cmd(
|
|
|
2322
2658
|
|
|
2323
2659
|
# If no argument provided, show available documents
|
|
2324
2660
|
if doc_name is None:
|
|
2325
|
-
from rich.table import Table
|
|
2661
|
+
from rich.table import Table # noqa: PLC0415
|
|
2326
2662
|
|
|
2327
2663
|
console.print("\n[bold cyan]Available Documents:[/bold cyan]\n")
|
|
2328
2664
|
table = Table(show_header=True, header_style="bold magenta", box=box.ROUNDED, padding=(0, 1))
|