Spaces:
Configuration error
Configuration error
| # ๐ AI System Refactoring Plan | |
| ## ืชืืื ืืช ืจืืคืงืืืจ ืืขืจืืช ื-AI | |
| **ืชืืจืื:** January 2026 | |
| **ืกืืืืก:** ๐ Planning | |
| **ืืจืกื:** 1.0 | |
| --- | |
| ## ๐ ืชืืื ืขื ืืื ืื | |
| 1. [ืกืงืืจืช ืืืฆื ืื ืืืื](#-ืกืงืืจืช-ืืืฆื-ืื ืืืื) | |
| 2. [ืืืขืืืช ืฉืฆืจืื ืืคืชืืจ](#-ืืืขืืืช-ืฉืฆืจืื-ืืคืชืืจ) | |
| 3. [ืืืจืืืืงืืืจื ืืืืฉื](#-ืืืจืืืืงืืืจื-ืืืืฉื) | |
| 4. [ืคืืจืื ืืจืืืืื](#-ืคืืจืื-ืืจืืืืื) | |
| 5. [ืชืืื ืืช ืืืืืฉ](#-ืชืืื ืืช-ืืืืืฉ) | |
| 6. [ืืืืจืฆืื ืืืืืจื](#-ืืืืจืฆืื-ืืืืืจื) | |
| 7. [ืืืืงืืช](#-ืืืืงืืช) | |
| --- | |
| ## ๐ด ืกืงืืจืช ืืืฆื ืื ืืืื | |
| ### ืืื ื ืงืืื | |
| ``` | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| โ ืืืฆื ืื ืืืื (ืืืืื) โ | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค | |
| โ โ | |
| โ GameManager โ | |
| โ โ โ | |
| โ โผ saves state to file โ | |
| โ current_state.json โ | |
| โ โ โ | |
| โ โผ watches file changes โ | |
| โ play_with_prompts.py (background thread) โ | |
| โ โ โ | |
| โ โผ calls โ | |
| โ generate_prompts_from_state.py โ | |
| โ โ โ | |
| โ โโโโบ generate_what_happened_message() (guesses from state!) โ | |
| โ โ โ | |
| โ โผ saves โ | |
| โ prompt_N.json files โ | |
| โ โ โ | |
| โ โผ watches files โ | |
| โ test_ai_live.py โ | |
| โ โ โ | |
| โ โผ sends to โ | |
| โ LLM (Gemini) โ | |
| โ โ โ | |
| โ โผ ??? โ | |
| โ How do responses get back to game? โ ๐จ BROKEN โ | |
| โ โ | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| ``` | |
| ### ืงืืฆืื ืงืืืืื | |
| | ืงืืืฅ | ืืืงืื | ืชืคืงืื | | |
| |------|-------|-------| | |
| | `prompt_manager.py` | `pycatan/ai/` | ืืฆืืจืช ืคืจืืืคืืื | | |
| | `llm_client.py` | `pycatan/ai/` | ืชืงืฉืืจืช ืขื Gemini | | |
| | `state_filter.py` | `pycatan/ai/` | ืกืื ืื state ืืฉืืงื | | |
| | `prompt_templates.py` | `pycatan/ai/` | ืชืื ืืืช ื-schemas | | |
| | `config.py` | `pycatan/ai/` | ืงืื ืคืืืืจืฆืื | | |
| | `generate_prompts_from_state.py` | `examples/ai_testing/` | ืืฆืืจืช ืคืจืืืคืืื ืืงืืืฅ | | |
| | `test_ai_live.py` | `examples/ai_testing/` | ืฉืืืื ื-LLM | | |
| | `play_with_prompts.py` | `examples/ai_testing/` | ืืจืฆืช ืืฉืืง ืขื AI | | |
| | `web_viewer.py` | `examples/ai_testing/` | ืฆืคืืื ืืคืจืืืคืืื | | |
| | `user.py` | `pycatan/players/` | ืืืฉืง User ืืืคืฉื | | |
| | `human_user.py` | `pycatan/players/` | ืืืืืฉ ืืฉืืงื ืื ืืฉื | | |
| --- | |
| ## ๐จ ืืืขืืืช ืฉืฆืจืื ืืคืชืืจ | |
| ### ืืขืื 1: ืืคืจืืช ืืืจืืืช ืืกืจื | |
| ``` | |
| โ GameManager ืื ืฆืจืื ืืืขืช ืขื AI/ืคืจืืืคืืื | |
| โ ืืฆืืจืช ืคืจืืืคืืื ืืคืืืจืช ืืืกืคืจ ืืงืืืืช | |
| โ ืืื ืืงืื ืืจืืื ืื ืืืื ืกืืื ื AI | |
| ``` | |
| ### ืืขืื 2: "ืื ืงืจื" ืืืืกืก ืขื ื ืืืืฉืื | |
| ``` | |
| โ generate_what_happened_message() ืื ืกื ืืฉืืืจ ืื ืงืจื ืืชืื state | |
| โ ืื ืืืืืง - ืืกืจ ืืืืข ืขื ืื ืืืืช ืืชืจืืฉ | |
| โ GameManager ืืืืข ืืืืืง ืื ืงืจื ืืื ืืืืืข ืื ืืืขืืจ | |
| ``` | |
| ### ืืขืื 3: ืืื ืฉืืืื ืขื ืืชื ืืฉืืื ืคืจืืืคืืื | |
| ``` | |
| โ ืคืจืืืคืืื ื ืฉืืืื ืขื ืื ืฉืื ืื ืงืืืฅ | |
| โ ืืื ืืืืงื ืื ืืืจ ืืืชืื ืื ืืชืฉืืื (pending) | |
| โ ืฆ'ืื ืื ืืขืืจืจ ืฉืืืืช ืคืจืืืคืืื | |
| ``` | |
| ### ืืขืื 4: ืชืฉืืืืช ืื ืืืืจืืช ืืืฉืืง | |
| ``` | |
| โ ืืื ืืกืืื ืืจืืจ ืืชืฉืืืืช ืืืืืจ ื-GameManager | |
| โ ืืื ืขืืื ืืจื ืงืืฆืื - ืื real-time | |
| ``` | |
| ### ืืขืื 5: ืืืืจืื ืืคืืืจ | |
| ``` | |
| โ note_to_self ื ืฉืืจ ืืงืืฆืื, ืื ืืืงืื ืืจืืื | |
| โ ืืืจืืขืื (events) ืื ื ืฉืืจืื ืืื ืกืืื | |
| โ ืกืืืืื ืฆ'ืื ืื ืงืืืืื | |
| ``` | |
| --- | |
| ## ๐ข ืืืจืืืืงืืืจื ืืืืฉื | |
| ### ืชืจืฉืื ืืื ื | |
| ``` | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| โ ืืจืืืืงืืืจื ืืืฉื โ | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค | |
| โ โ | |
| โ โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโ โ | |
| โ โ โ โ โ โ | |
| โ โ GameManager โโโโโโ Actions โโโโโโโ AIManager โ โ | |
| โ โ โ โ โ โ | |
| โ โ โข Game Loop โ โ โข Creates Prompts โ โ | |
| โ โ โข Rules โโโโโ Events โโโโโโโโบโ โข Manages Agents โ โ | |
| โ โ โข State โ (notify_all) โ โข Handles Chat โ โ | |
| โ โ โข Turn Flow โ โ โข Tracks Pending โ โ | |
| โ โ โ โ โข Sends to LLM โ โ | |
| โ โโโโโโโโโโฌโโโโโโโโโโ โโโโโโโโโโโโฌโโโโโโโโโโโโ โ | |
| โ โ โ โ | |
| โ โ get_input() โ โ | |
| โ โผ โผ โ | |
| โ โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโ โ | |
| โ โ โ โ โ โ | |
| โ โ HumanUser โ โ AIUser (Wrapper) โ โ | |
| โ โ (CLI) โ โ โ โ | |
| โ โ โ โ โข Delegates to โ โ | |
| โ โ โ โ AIManager โ โ | |
| โ โโโโโโโโโโโโโโโโโโโโ โ โ โ | |
| โ โโโโโโโโโโโโฌโโโโโโโโโโโโ โ | |
| โ โ โ | |
| โ โผ โ | |
| โ โโโโโโโโโโโโโโโโโโโโโโโโ โ | |
| โ โ โ โ | |
| โ โ AILogger โ โ | |
| โ โ โ โ | |
| โ โ โข MD logs โ โ | |
| โ โ โข JSON files โ โ | |
| โ โ โข Web Viewer โ โ | |
| โ โ โ โ | |
| โ โโโโโโโโโโโโโโโโโโโโโโโโ โ | |
| โ โ | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| ``` | |
| ### ืขืงืจืื ืืช ืื ืืื | |
| | ืขืืงืจืื | ืคืืจืื | | |
| |--------|-------| | |
| | **ืืคืจืืช ืืืจืืืช** | GameManager ืื ืืืืข ืขื AI, AIManager ืื ืืืืข ืขื ืืืงื ืืืฉืืง | | |
| | **ืืงืื ืืื ืืคืจืืืคืืื** | ืื ืืฆืืจืช ืืคืจืืืคืืื ืืจื AIManager | | |
| | **ืฉืืืื ืืจืืืืช** | `should_send_prompt()` ืืืืื ืืชื ืืฉืืื | | |
| | **"ืื ืงืจื" ืืืืืง** | Events ืืืืขืื ืืฉืืจืืช ื-GameManager | | |
| | **ืืืืื ืชืืืืื** | AILogger ืฉืืืจ ืขื ืืืชื ืคืืจืื ืงืืฆืื | | |
| --- | |
| ## ๐ฆ ืคืืจืื ืืจืืืืื | |
| ### 1. AgentState - ืืฆื ืกืืื ืืืื | |
| ```python | |
| @dataclass | |
| class AgentState: | |
| """ | |
| ืืฆื ืฉื ืกืืื AI ืืืื. | |
| ืื ืืืืืจืื ืืืืฆื ืฉื ืกืืื ืกืคืฆืืคื ืื ืืื ืืื. | |
| """ | |
| # === ืืืืื === | |
| player_name: str # ืฉื ืืฉืืงื ("dudu", "shon") | |
| player_id: int # ืืกืคืจ ืฉืืงื (0, 1, 2...) | |
| player_color: str # ืฆืืข ("Red", "Blue") | |
| # === ืกืืืืก ืืงืฉื === | |
| pending_request: bool = False # ืืื ืืืชืื ืืชืฉืืื ื-LLM? | |
| last_request_time: Optional[float] = None | |
| # === ืืืืจืื ืคืจืื === | |
| memory: Optional[str] = None # note_to_self ืืชืฉืืื ืืืจืื ื | |
| # === ืกืืืืื ืฆ'ืื (ืืขืชืื) === | |
| chat_summaries: List[str] = field(default_factory=list) | |
| # ืืืืื: ["Turn 5: Dana agreed to trade wood for brick"] | |
| # === ืืืจืืขืื ืฉืงืจื ืืื ืืคืจืืืคื ืืืืจืื === | |
| recent_events: List[Dict[str, Any]] = field(default_factory=list) | |
| # ืืืืื: [{"type": "dice_roll", "message": "Rolled 6", "timestamp": 123}] | |
| # === ืืขืงื ืฉืื ืืืื === | |
| last_state_hash: Optional[str] = None | |
| last_prompt_time: Optional[float] = None | |
| # === ืกืืืืกืืืงืืช === | |
| total_requests: int = 0 | |
| total_tokens_used: int = 0 | |
| ``` | |
| **ืืืงืื:** `pycatan/ai/agent_state.py` | |
| --- | |
| ### 2. AIManager - ืืื ืื ืืืจืืื | |
| ```python | |
| class AIManager: | |
| """ | |
| ืื ืื ืืจืืื ืืื ืกืืื ื ื-AI. | |
| ืืืจืืืช: | |
| - ื ืืืื ืืฆื ืื ืืกืืื ืื | |
| - ืืฆืืจืช ืืฉืืืืช ืคืจืืืคืืื | |
| - ืงืืืช ืชืฉืืืืช ืืืืจื ืืคืขืืืืช | |
| - ื ืืืื ืฆ'ืื ืืืืกืืืจืื | |
| - ืืืืื ืืชื ืืฉืืื ืคืจืืืคืืื | |
| """ | |
| def __init__( | |
| self, | |
| game_manager: GameManager, | |
| config: AIConfig = None, | |
| session_dir: Path = None | |
| ): | |
| """ | |
| Args: | |
| game_manager: ืืคื ืื ื-GameManager ืืงืจืืืช state | |
| config: ืงืื ืคืืืืจืฆืื (ืืจืืจืช ืืืื ืื None) | |
| session_dir: ืชืืงืืืช session ืืืืืื | |
| """ | |
| self.game_manager = game_manager | |
| self.config = config or AIConfig() | |
| # ืจืืืืื ืคื ืืืืื | |
| self.prompt_manager = PromptManager(self.config) | |
| self.llm_client = self._create_llm_client() | |
| self.logger = AILogger(session_dir) | |
| # ืืฆื | |
| self.agents: Dict[str, AgentState] = {} | |
| self.chat_history: List[Dict] = [] | |
| self.max_chat_history: int = 20 | |
| # === ื ืืืื ืกืืื ืื === | |
| def register_agent(self, player_name: str, player_id: int, player_color: str = ""): | |
| """ืจืืฉื ืกืืื AI ืืืฉ""" | |
| def unregister_agent(self, player_name: str): | |
| """ืืกืืจ ืกืืื (ืื ืฉืืงื ืขืื)""" | |
| # === ื ืงืืืช ืืื ืืกื ืืจืืฉืืช === | |
| def process_agent_turn(self, player_name: str) -> Action: | |
| """ | |
| ืืขืื ืชืืจ ืฉื ืกืืื AI. | |
| ืื ืืคืื ืงืฆืื ืฉื ืงืจืืช ื-AIUser.get_input() | |
| Returns: | |
| Action: ืืคืขืืื ืฉืืกืืื ืืืจ ืืืฆืข | |
| """ | |
| # === ืงืืืช ืืืจืืขืื === | |
| def on_game_event(self, event_type: str, message: str, affected_players: List[int] = None): | |
| """ | |
| ื ืงืจื ืืฉืืชืจืืฉ ืืืจืืข ืืืฉืืง. | |
| ื ืงืจื ื-AIUser.notify_game_event() ืขืืืจ ืื ืกืืื. | |
| """ | |
| def on_chat_message(self, from_player: str, message: str): | |
| """ | |
| ื ืงืจื ืืฉืกืืื ืฉืืื ืืืืขืช ืฆ'ืื. | |
| ืืืกืืฃ ืืืืกืืืจืื ืืฉืืื ืคืจืืืคืืื ืืกืืื ืื ืืืจืื. | |
| """ | |
| # === ืืืืืงืช ืฉืืืื === | |
| def should_send_prompt(self, player_name: str) -> bool: | |
| """ | |
| ืืืืื ืื ืืฉืืื ืคืจืืืคื ืืกืืื. | |
| ืืืืื: | |
| 1. ืืื ืืงืฉื ืชืืืื (pending_request == False) | |
| 2. ืืื ืืื ืืืื: | |
| - ืืฆื ืืืฉืืง ืืฉืชื ื (state_hash ืฉืื ื) | |
| - ืืืืขื ืืืืขืช ืฆ'ืื ืืืฉื | |
| """ | |
| # === ืคืื ืงืฆืืืช ืคื ืืืืืช === | |
| def _create_prompt(self, agent: AgentState, is_active_turn: bool) -> Dict: | |
| """ืืืฆืจ ืคืจืืืคื ืืื ืืกืืื""" | |
| def _build_what_happened(self, agent: AgentState) -> str: | |
| """ืืื ื ืชืืืืจ 'ืื ืงืจื' ืืืืืจืืขืื ืืืืจืื ืื""" | |
| def _get_optimized_state(self) -> Dict: | |
| """ืืืืืจ state ืืืืื ืืฉืืืื ื-LLM""" | |
| def _hash_state(self) -> str: | |
| """ืืืฆืจ hash ืฉื ื-state ืืืืืื ืฉืื ืืืื""" | |
| def _convert_to_action(self, parsed_response: Dict, player_id: int) -> Action: | |
| """ืืืืจ ืชืฉืืืช LLM ืืืืืืืงื Action""" | |
| def _broadcast_chat(self, from_player: str, message: str): | |
| """ืืฉืืจ ืืืืขืช ืฆ'ืื ืืื ืืกืืื ืื""" | |
| ``` | |
| **ืืืงืื:** `pycatan/ai/ai_manager.py` | |
| --- | |
| ### 3. AIUser - Wrapper ืืืืฉืง User | |
| ```python | |
| class AIUser(User): | |
| """ | |
| Wrapper ืฉืืืืจ ืืื GameManager ื-AIManager. | |
| GameManager ืจืืื ืืช ืื ื-User ืจืืื ืืืชืงืฉืจ ืืืชื | |
| ืืจื get_input() ื-notify_game_event(). | |
| """ | |
| def __init__(self, name: str, user_id: int, ai_manager: AIManager, color: str = ""): | |
| """ | |
| Args: | |
| name: ืฉื ืืฉืืงื | |
| user_id: ืืกืคืจ ืฉืืงื (0-based) | |
| ai_manager: ืืคื ืื ื-AIManager | |
| color: ืฆืืข ืืฉืืงื | |
| """ | |
| super().__init__(name, user_id) | |
| self.ai_manager = ai_manager | |
| self.color = color | |
| # ืจืืฉื ืืช ืขืฆืื ื-AIManager | |
| ai_manager.register_agent(name, user_id, color) | |
| def get_input( | |
| self, | |
| game_state: GameState, | |
| prompt_message: str, | |
| allowed_actions: Optional[List[str]] = None | |
| ) -> Action: | |
| """ | |
| GameManager ืงืืจื ืืื ืืฉืฆืจืื ืคืขืืื. | |
| ืืขืืืจ ืืช ืืืงืฉื ื-AIManager ืืืืคืื. | |
| """ | |
| return self.ai_manager.process_agent_turn(self.name) | |
| def notify_game_event( | |
| self, | |
| event_type: str, | |
| message: str, | |
| affected_players: Optional[List[int]] = None | |
| ): | |
| """ | |
| GameManager ืงืืจื ืืื ืืฉืืชืจืืฉ ืืืจืืข. | |
| ืืขืืืจ ื-AIManager ืืฉืืืจื. | |
| """ | |
| self.ai_manager.on_game_event(event_type, message, affected_players) | |
| def notify_action(self, action: Action, success: bool, message: str = ""): | |
| """ | |
| GameManager ืงืืจื ืืื ืืืจื ืืืฆืืข ืคืขืืื. | |
| """ | |
| # ืืคืฉืจ ืืืืกืืฃ ืืืืืงื ืื ืฆืจืื | |
| pass | |
| ``` | |
| **ืืืงืื:** `pycatan/ai/ai_user.py` | |
| --- | |
| ### 4. AILogger - ื ืืืื ืืืืื | |
| ```python | |
| class AILogger: | |
| """ | |
| ืื ืื ืืืืื ืขืืืจ ืืขืจืืช ื-AI. | |
| ืฉืืืจ ืขื ืชืืืืืช ืืคืืจืื ืืงืืื: | |
| - player_X.md (ืืืืื ืงืจืืืื) | |
| - prompt_N.json (ืคืจืืืคืืื) | |
| - response_N.json (ืชืฉืืืืช) | |
| ืื ืชืืื ื-Web Viewer (ืืขืชืื). | |
| """ | |
| def __init__(self, session_dir: Path = None): | |
| """ | |
| Args: | |
| session_dir: ืชืืงืืืช session. ืื None, ืืืฆืจ ืืืืืืืืช. | |
| """ | |
| if session_dir is None: | |
| session_dir = self._create_session_dir() | |
| self.session_dir = session_dir | |
| self.session_dir.mkdir(parents=True, exist_ok=True) | |
| self.request_counters: Dict[str, int] = {} | |
| self.start_time = datetime.now() | |
| # ืืฆืืจืช header ืืืืืื | |
| self._init_session() | |
| # === Logging === | |
| def log_prompt( | |
| self, | |
| player_name: str, | |
| prompt: Dict, | |
| schema: Dict, | |
| is_active: bool = True | |
| ) -> Path: | |
| """ | |
| ืฉืืืจ ืคืจืืืคื ืืงืืืฅ. | |
| ืืืฆืจ: | |
| - session/player_name/prompts/prompt_N.json | |
| - session/player_name/prompts/prompt_N.txt | |
| Returns: | |
| Path: ื ืชืื ืืงืืืฅ JSON | |
| """ | |
| def log_response( | |
| self, | |
| player_name: str, | |
| response: LLMResponse, | |
| parsed: Dict | |
| ): | |
| """ | |
| ืฉืืืจ ืชืฉืืื ืืืขืืื MD log. | |
| ืืืฆืจ: | |
| - session/player_name/responses/response_N.json | |
| - ืืขืืื session/player_name.md | |
| """ | |
| def log_chat(self, from_player: str, message: str): | |
| """ืฉืืืจ ืืืืขืช ืฆ'ืื ืืืื""" | |
| def log_error(self, player_name: str, error: str): | |
| """ืฉืืืจ ืฉืืืื ืืืื""" | |
| # === MD Generation === | |
| def _init_player_md(self, player_name: str, model: str): | |
| """ืืืฆืจ header ืืงืืืฅ MD ืฉื ืฉืืงื""" | |
| def _append_request_to_md( | |
| self, | |
| player_name: str, | |
| num: int, | |
| prompt: Dict | |
| ): | |
| """ืืืกืืฃ request section ื-MD""" | |
| def _append_response_to_md( | |
| self, | |
| player_name: str, | |
| num: int, | |
| response: LLMResponse, | |
| parsed: Dict | |
| ): | |
| """ืืืกืืฃ response section ื-MD""" | |
| # === Utilities === | |
| def _create_session_dir(self) -> Path: | |
| """ืืืฆืจ ืชืืงืืืช session ืขื timestamp""" | |
| def get_session_path(self) -> Path: | |
| """ืืืืืจ ื ืชืื ื-session""" | |
| def save_agent_memories(self, agents: Dict[str, AgentState]): | |
| """ืฉืืืจ ืืช ืืืืืจืื ืืช ืฉื ืื ืืกืืื ืื ืืงืืืฅ""" | |
| def save_chat_history(self, chat_history: List[Dict]): | |
| """ืฉืืืจ ืืืกืืืจืืืช ืฆ'ืื ืืงืืืฅ""" | |
| ``` | |
| **ืืืงืื:** `pycatan/ai/ai_logger.py` | |
| --- | |
| ## ๐ ืืจืืืืช ืขืืืื | |
| ### ืืจืืื 1: ืชืืจ ืฉื ืกืืื AI | |
| ``` | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| โ AGENT TURN FLOW โ | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค | |
| โ โ | |
| โ 1. GameManager._process_user_action() โ | |
| โ โ โ | |
| โ โ calls โ | |
| โ โผ โ | |
| โ 2. AIUser.get_input(game_state, prompt_message, allowed_actions) โ | |
| โ โ โ | |
| โ โ delegates to โ | |
| โ โผ โ | |
| โ 3. AIManager.process_agent_turn(player_name) โ | |
| โ โ โ | |
| โ โโโบ Get agent state โ | |
| โ โ โ | |
| โ โโโบ Build "what_happened" from recent_events โ | |
| โ โ โ | |
| โ โโโบ Create prompt via PromptManager โ | |
| โ โ โ | |
| โ โโโบ AILogger.log_prompt() โ saves files โ | |
| โ โ โ | |
| โ โโโบ Mark agent.pending_request = True โ | |
| โ โ โ | |
| โ โโโบ LLMClient.generate(prompt) โโโโโโโบ ๐ค Gemini โ | |
| โ โ โ โ | |
| โ โโโโโ Response โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ | |
| โ โ โ | |
| โ โโโบ Mark agent.pending_request = False โ | |
| โ โ โ | |
| โ โโโบ Parse response โ | |
| โ โ โ | |
| โ โโโบ AILogger.log_response() โ saves files + MD โ | |
| โ โ โ | |
| โ โโโบ Update agent.memory (note_to_self) โ | |
| โ โ โ | |
| โ โโโบ Clear agent.recent_events โ | |
| โ โ โ | |
| โ โโโบ Handle chat_message if present โ | |
| โ โ โ | |
| โ โผ โ | |
| โ 4. Return Action โ | |
| โ โ โ | |
| โ โผ โ | |
| โ 5. GameManager.execute_action() โ | |
| โ โ โ | |
| โ โผ โ | |
| โ 6. GameManager._notify_all_users() โโโบ AIUser.notify_game_event() โ | |
| โ โ โ | |
| โ โผ โ | |
| โ AIManager.on_game_event() โ | |
| โ โ โ | |
| โ โผ โ | |
| โ Save to agent.recent_eventsโ | |
| โ โ | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| ``` | |
| ### ืืจืืื 2: ืืืืขืช ืฆ'ืื | |
| ``` | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| โ CHAT MESSAGE FLOW โ | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค | |
| โ โ | |
| โ 1. Agent A response includes chat_message: "Anyone want sheep?" โ | |
| โ โ โ | |
| โ โผ โ | |
| โ 2. AIManager._broadcast_chat("A", "Anyone want sheep?") โ | |
| โ โ โ | |
| โ โโโบ Add to chat_history (shared) โ | |
| โ โ โ | |
| โ โโโบ AILogger.log_chat() โ | |
| โ โ โ | |
| โ โผ โ | |
| โ 3. For each other agent (B, C, D): โ | |
| โ โ โ | |
| โ โโโบ Check should_send_prompt(agent) โ | |
| โ โ โ โ | |
| โ โ โโโบ if pending_request: SKIP (don't queue!) โ | |
| โ โ โ โ | |
| โ โ โโโบ if not pending: Send spectator prompt โ | |
| โ โ โ | |
| โ โโโบ Agents see chat in their next prompt โ | |
| โ โ | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| ``` | |
| ### ืืจืืื 3: ืืืจืืข ืืืฉืืง (Event) | |
| ``` | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| โ GAME EVENT FLOW โ | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค | |
| โ โ | |
| โ 1. GameManager: Something happens (dice roll, build, trade...) โ | |
| โ โ โ | |
| โ โผ โ | |
| โ 2. GameManager._notify_all_users("dice_roll", "Rolled 6 (3+3)") โ | |
| โ โ โ | |
| โ โ For each user: โ | |
| โ โผ โ | |
| โ 3. User.notify_game_event("dice_roll", "Rolled 6 (3+3)") โ | |
| โ โ โ | |
| โ โโโบ HumanUser: prints to console โ | |
| โ โ โ | |
| โ โโโบ AIUser: delegates to AIManager โ | |
| โ โ โ | |
| โ โผ โ | |
| โ 4. AIManager.on_game_event("dice_roll", "Rolled 6 (3+3)") โ | |
| โ โ โ | |
| โ โผ โ | |
| โ 5. For each agent: โ | |
| โ โ โ | |
| โ โโโบ agent.recent_events.append({ โ | |
| โ "type": "dice_roll", โ | |
| โ "message": "Rolled 6 (3+3)", โ | |
| โ "timestamp": time.time() โ | |
| โ }) โ | |
| โ โ | |
| โ 6. When agent's turn comes, recent_events โ "what_happened" โ | |
| โ โ | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| ``` | |
| --- | |
| ## ๐ ืืื ื ืงืืฆืื ืืืฉ | |
| ``` | |
| pycatan/ | |
| โโโ ai/ | |
| โ โโโ __init__.py # exports | |
| โ โ | |
| โ โ # === NEW FILES === | |
| โ โโโ ai_manager.py # ๐ AIManager class | |
| โ โโโ ai_user.py # ๐ AIUser class (wrapper) | |
| โ โโโ ai_logger.py # ๐ AILogger class | |
| โ โโโ agent_state.py # ๐ AgentState dataclass | |
| โ โ | |
| โ โ # === EXISTING (minimal changes) === | |
| โ โโโ prompt_manager.py # โ Keep as-is | |
| โ โโโ llm_client.py # โ Keep as-is | |
| โ โโโ state_filter.py # โ Keep as-is | |
| โ โโโ prompt_templates.py # โ Keep as-is | |
| โ โโโ response_parser.py # โ Keep as-is | |
| โ โโโ schemas.py # โ Keep as-is | |
| โ โโโ config.py # โ Keep as-is | |
| โ | |
| โโโ players/ | |
| โ โโโ __init__.py | |
| โ โโโ user.py # โ Keep as-is (abstract interface) | |
| โ โโโ human_user.py # โ Keep as-is | |
| โ | |
| โโโ management/ | |
| โ โโโ game_manager.py # โ Keep as-is (no changes!) | |
| โ | |
| examples/ | |
| โโโ ai_testing/ | |
| โ โ # === DEPRECATED (will be replaced) === | |
| โ โโโ generate_prompts_from_state.py # โ ๏ธ DEPRECATED | |
| โ โโโ test_ai_live.py # โ ๏ธ DEPRECATED | |
| โ โโโ play_with_prompts.py # โ ๏ธ DEPRECATED | |
| โ โ | |
| โ โ # === NEW === | |
| โ โโโ play_with_ai.py # ๐ New unified entry point | |
| โ โ | |
| โ โ # === KEEP === | |
| โ โโโ web_viewer.py # โ Keep (works with new log format) | |
| โ โโโ my_games/ # โ Keep (session storage) | |
| ``` | |
| --- | |
| ## ๐ ืชืืื ืืช ืืืืืฉ | |
| ### Phase 1: ืืฆืืจืช ืจืืืืื ืืืฉืื (ืื ืฉืืืจืื ืงืื ืงืืื) | |
| #### Step 1.1: AgentState | |
| ``` | |
| ๐ Create: pycatan/ai/agent_state.py | |
| โฑ๏ธ Estimated: 15 min | |
| ๐ Contents: | |
| - AgentState dataclass | |
| - Helper methods | |
| ``` | |
| #### Step 1.2: AILogger | |
| ``` | |
| ๐ Create: pycatan/ai/ai_logger.py | |
| โฑ๏ธ Estimated: 45 min | |
| ๐ Contents: | |
| - AILogger class | |
| - log_prompt() - saves JSON + TXT | |
| - log_response() - saves JSON + updates MD | |
| - MD format matching existing player_X.md | |
| ``` | |
| #### Step 1.3: AIManager | |
| ``` | |
| ๐ Create: pycatan/ai/ai_manager.py | |
| โฑ๏ธ Estimated: 1.5 hours | |
| ๐ Contents: | |
| - AIManager class | |
| - process_agent_turn() | |
| - on_game_event() | |
| - on_chat_message() | |
| - should_send_prompt() | |
| - _broadcast_chat() | |
| ``` | |
| #### Step 1.4: AIUser | |
| ``` | |
| ๐ Create: pycatan/ai/ai_user.py | |
| โฑ๏ธ Estimated: 30 min | |
| ๐ Contents: | |
| - AIUser class extending User | |
| - get_input() delegation | |
| - notify_game_event() delegation | |
| ``` | |
| #### Step 1.5: Update __init__.py | |
| ``` | |
| ๐ Modify: pycatan/ai/__init__.py | |
| โฑ๏ธ Estimated: 5 min | |
| ๐ Add exports for new classes | |
| ``` | |
| --- | |
| ### Phase 2: Entry Point ืืืฉ | |
| #### Step 2.1: Create play_with_ai.py | |
| ``` | |
| ๐ Create: examples/ai_testing/play_with_ai.py | |
| โฑ๏ธ Estimated: 45 min | |
| ๐ Contents: | |
| - Creates GameManager with AIUsers | |
| - Creates AIManager | |
| - Runs game loop | |
| ``` | |
| --- | |
| ### Phase 3: ืืืืงืืช ืืืืืื | |
| #### Step 3.1: Test basic flow | |
| ``` | |
| โฑ๏ธ Estimated: 30 min | |
| ๐ Run play_with_ai.py | |
| - Verify prompts generated | |
| - Verify responses logged | |
| - Verify MD files created | |
| - Verify actions returned to GameManager | |
| ``` | |
| #### Step 3.2: Test chat flow | |
| ``` | |
| โฑ๏ธ Estimated: 20 min | |
| ๐ Test chat messages | |
| - Agent sends chat | |
| - Other agents receive in next prompt | |
| - Chat history saved | |
| ``` | |
| #### Step 3.3: Test Web Viewer | |
| ``` | |
| โฑ๏ธ Estimated: 15 min | |
| ๐ Verify web_viewer.py works with new log format | |
| ``` | |
| --- | |
| ### Phase 4: Cleanup (ืืืคืฆืืื ืื) | |
| #### Step 4.1: Mark deprecated files | |
| ``` | |
| ๐ Add deprecation notices to: | |
| - generate_prompts_from_state.py | |
| - test_ai_live.py | |
| - play_with_prompts.py | |
| ``` | |
| #### Step 4.2: Update documentation | |
| ``` | |
| ๐ Update: | |
| - README | |
| - AI_ARCHITECTURE.md | |
| ``` | |
| --- | |
| ## โฑ๏ธ ืกืืืื ืืื ืื | |
| | Phase | Task | Time | | |
| |-------|------|------| | |
| | 1.1 | AgentState | 15 min | | |
| | 1.2 | AILogger | 45 min | | |
| | 1.3 | AIManager | 1.5 hours | | |
| | 1.4 | AIUser | 30 min | | |
| | 1.5 | __init__.py | 5 min | | |
| | 2.1 | play_with_ai.py | 45 min | | |
| | 3.x | Testing | 1 hour | | |
| | **Total** | | **~5 hours** | | |
| --- | |
| ## โ Checklist ืืคื ื ืืชืืื | |
| - [ ] ืืื ื ืืืจืืืืงืืืจื ืืจืืจ | |
| - [ ] ืืื ืช ืืจืืืช ืืขืืืื | |
| - [ ] ืืื ืช ืืืจืืืช ืื ืจืืื | |
| - [ ] ืืืื ืืืชืืื Phase 1 | |
| --- | |
| ## ๐ฎ ืชืืกืคืืช ืขืชืืืืืช (ืื ืืจืืคืงืืืจ ืื ืืืื) | |
| 1. **ืกืืืื ืฆ'ืื ืืืืืืื** - `_maybe_summarize_chat()` | |
| 2. **Web Viewer real-time** - WebSocket ื-AILogger | |
| 3. **Multi-LLM support** - OpenAI, Anthropic | |
| 4. **Agent personalities** - Different prompts per agent | |
| 5. **Replay system** - Play back from logs | |
| --- | |
| ## ๐ ืงืืฆืื ืงืฉืืจืื | |
| - [AI_ARCHITECTURE.md](.github/instructions/AI_ARCHITECTURE.md) - ืืจืืืืงืืืจื ืืืืืช | |
| - [AI_AGENT_PRINCIPLES.md](.github/instructions/AI_AGENT_PRINCIPLES.md) - ืขืงืจืื ืืช ืขืืฆืื | |
| - [WORK_PLAN.md](.github/instructions/WORK_PLAN.md) - ืชืืื ืืช ืขืืืื ืืืืืช | |
| --- | |
| **ืืืื ืืืชืืื?** ๐ | |