Spaces:
Sleeping
Sleeping
| # Multi-Agent System Plugins | |
| This package provides an extensible **multi-agent system plugin** layer. Each plugin simulates a game or scenario with multiple agents; the primitive is a **step** (each step can have multiple agent turns). Plugins are used to generate steps based on **state history** and optional **config**. | |
| ## Quick start | |
| - **List games**: `from watchdog_env.plugins import list_game_ids; list_game_ids()` → e.g. `['cicero']` | |
| - **Get a plugin**: `from watchdog_env.plugins import get_plugin; plugin = get_plugin('cicero')` | |
| - **Run a scenario**: `plugin.reset(seed=42)` then `plugin.generate_step(seed, 0)`, `generate_step(seed, 1)`, … until `step.done` is True. | |
| ## API | |
| - **MultiAgentConfig** — Base config class; subclass for your game (e.g. Avalon uses `AvalonConfig`). | |
| - **MultiAgentState** — Tracks system behaviour (step_index, turns_so_far, done); used when generating each step. | |
| - **MultiAgentStep** — One step: list of **AgentTurn** (agent_id, action_text), plus `done`, optional `state` snapshot. | |
| - **MultiAgentSystemPlugin** — Abstract base. Implement: `get_game_id`, `reset(seed, config)`, `generate_step(seed, step_index)`, `get_state`, `get_display_name`, `list_agent_ids`. | |
| ## Cicero plugin | |
| - **Game ID**: `cicero` | |
| - **Config**: None. Uses constants from `diplomacy_constants` (num_steps=5, all 7 powers). | |
| - **API key**: Set `GEMINI_API_KEY` or `GOOGLE_API_KEY` for live Gemini calls. No template fallback; LLM is required. | |
| - **Optional deps**: `pip install langchain-google-genai langchain-core` (or `pip install -e ".[plugins]"` from `watchdog_env`). | |
| ## Tests | |
| - **Base and registry** (no API key): | |
| `pytest watchdog_env/plugins/tests/test_base_and_registry.py -v` | |
| - **Cicero** (requires API key; skipped if unset): | |
| Set `GEMINI_API_KEY` or `GOOGLE_API_KEY`, then: | |
| `pytest watchdog_env/plugins/tests/test_cicero_plugin.py -v` | |
| Run from repo root with `PYTHONPATH=<repo_root>`. | |
| --- | |
| # Guide: Adding Additional Plugins | |
| Follow these steps to add a new multi-agent system plugin (e.g. a new game or scenario). | |
| ## 1. Create a plugin folder | |
| Create a new directory under `watchdog_env/plugins/`, for example: | |
| ``` | |
| watchdog_env/plugins/ | |
| my_game/ | |
| __init__.py | |
| my_game_config.py # optional: your config class | |
| my_game_plugin.py # your plugin implementation | |
| ``` | |
| ## 2. Define your config (optional but recommended) | |
| Subclass **MultiAgentConfig** with your game-specific fields: | |
| ```python | |
| # my_game_config.py | |
| from dataclasses import dataclass | |
| from watchdog_env.plugins.base import MultiAgentConfig | |
| @dataclass | |
| class MyGameConfig(MultiAgentConfig): | |
| num_rounds: int = 5 | |
| agent_names: list[str] | None = None | |
| difficulty: str = "medium" | |
| ``` | |
| ## 3. Implement the plugin | |
| Create a class that implements **all** methods of **MultiAgentSystemPlugin**: | |
| ```python | |
| # my_game_plugin.py | |
| from watchdog_env.plugins.base import ( | |
| AgentTurn, | |
| MultiAgentConfig, | |
| MultiAgentState, | |
| MultiAgentStep, | |
| MultiAgentSystemPlugin, | |
| ) | |
| class MyGamePlugin(MultiAgentSystemPlugin): | |
| def __init__(self) -> None: | |
| self._state = MultiAgentState() | |
| def get_game_id(self) -> str: | |
| return "my_game" | |
| def reset(self, seed: int | None = None, config: MultiAgentConfig | None = None) -> None: | |
| # Initialize self._state (step_index=0, turns_so_far=[], config, done=False). | |
| ... | |
| def generate_step(self, seed: int | None, step_index: int) -> MultiAgentStep: | |
| # 1. Use self._state (e.g. turns_so_far) to build context for this step. | |
| # 2. Produce one or more AgentTurn(s); append to state.turns_so_far. | |
| # 3. Update state (step_index, done if last step). | |
| # 4. Return MultiAgentStep(turns=..., done=..., state=snapshot of state). | |
| ... | |
| def get_state(self) -> MultiAgentState: | |
| return self._state | |
| def get_display_name(self) -> str: | |
| return "My Game" | |
| def list_agent_ids(self) -> list[str]: | |
| return ["agent_a", "agent_b"] | |
| ``` | |
| Important: | |
| - **generate_step must be based on state history**: use `self._state.turns_so_far` (and other fields) when producing the next step (e.g. for LLM context or game logic), then update `self._state` after the step. | |
| - Use **MultiAgentConfig** (or your subclass) in **reset(seed, config=...)**; do not rely on kwargs for config. | |
| - Set **step.done = True** on the last step so consumers know the scenario is finished. | |
| ## 4. Export and register | |
| In `my_game/__init__.py`: | |
| ```python | |
| from watchdog_env.plugins.my_game.my_game_plugin import MyGamePlugin | |
| from watchdog_env.plugins.my_game.my_game_config import MyGameConfig # if you have one | |
| __all__ = ["MyGamePlugin", "MyGameConfig"] | |
| ``` | |
| In **watchdog_env/plugins/__init__.py**, register your plugin so it is available by game_id: | |
| ```python | |
| try: | |
| from watchdog_env.plugins.my_game import MyGamePlugin | |
| register(MyGamePlugin()) | |
| except Exception: | |
| MyGamePlugin = None # optional dependency | |
| ``` | |
| Add `"watchdog_env.plugins.my_game"` to **packages** and **package_dir** in `watchdog_env/pyproject.toml` if you added a new top-level plugin package. | |
| ## 5. Add tests | |
| Create tests that: | |
| - Call **get_game_id**, **reset(seed, config)**, **generate_step(seed, 0)**, … **get_state**, **get_display_name**, **list_agent_ids**. | |
| - Assert step content (turns, done) and state updates. | |
| - If your plugin uses an API (e.g. Gemini), require the API key and skip tests when it is unset (see `test_cicero_plugin.py`). | |
| Example: | |
| ```python | |
| # plugins/tests/test_my_game_plugin.py | |
| import pytest | |
| from watchdog_env.plugins.my_game import MyGamePlugin, MyGameConfig | |
| from watchdog_env.plugins.registry import get_plugin | |
| def test_get_game_id(): | |
| plugin = MyGamePlugin() | |
| assert plugin.get_game_id() == "my_game" | |
| def test_reset_and_generate_step(): | |
| plugin = MyGamePlugin() | |
| plugin.reset(seed=1, config=MyGameConfig(num_rounds=2)) | |
| step0 = plugin.generate_step(1, 0) | |
| assert len(step0.turns) >= 1 | |
| assert step0.done is False | |
| step1 = plugin.generate_step(1, 1) | |
| assert step1.done is True | |
| def test_registered(): | |
| assert get_plugin("my_game") is not None | |
| ``` | |
| ## 6. Document config and usage | |
| In your plugin module or in this README, document: | |
| - Supported **config** fields (your MultiAgentConfig subclass). | |
| - Any **env vars** (e.g. API keys) and optional dependencies. | |
| - How to run your plugin’s tests (e.g. “Set MY_API_KEY and run pytest …”). | |
| --- | |
| ## Summary checklist | |
| - [ ] New folder under `watchdog_env/plugins/<your_game>/` | |
| - [ ] Config class (subclass of MultiAgentConfig) if needed | |
| - [ ] Plugin class implementing all 6 methods of MultiAgentSystemPlugin | |
| - [ ] generate_step uses state history (e.g. turns_so_far) and updates state | |
| - [ ] Export in `<your_game>/__init__.py` and register in `plugins/__init__.py` | |
| - [ ] Update pyproject.toml packages if adding a new plugin package | |
| - [ ] Tests for all methods; skip or require API key as appropriate | |
| - [ ] Short doc for config and how to run tests | |